summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format13
-rw-r--r--.dockerignore13
-rw-r--r--.editorconfig7
-rw-r--r--.github/issue_template.md16
-rw-r--r--.gitignore5
-rw-r--r--.travis.yml60
-rwxr-xr-x.travis/build-and-test.sh2
-rwxr-xr-x.travis/setup.sh52
-rw-r--r--Brewfile1
-rw-r--r--CHANGELOG123
-rw-r--r--COPYING2
-rw-r--r--Dockerfile33
-rw-r--r--Makefile169
-rw-r--r--README.md117
-rw-r--r--backends/aiger/aiger.cc42
-rw-r--r--backends/blif/blif.cc32
-rw-r--r--backends/btor/btor.cc158
-rw-r--r--backends/edif/edif.cc63
-rw-r--r--backends/firrtl/firrtl.cc531
-rw-r--r--backends/ilang/ilang_backend.cc13
-rw-r--r--backends/intersynth/intersynth.cc2
-rw-r--r--backends/json/json.cc9
-rw-r--r--backends/protobuf/protobuf.cc7
-rw-r--r--backends/simplec/test00_uut.v6
-rw-r--r--backends/smt2/Makefile.inc18
-rw-r--r--backends/smt2/smt2.cc26
-rw-r--r--backends/smt2/smtbmc.py125
-rw-r--r--backends/smt2/smtio.py38
-rw-r--r--backends/smv/smv.cc85
-rw-r--r--backends/spice/spice.cc2
-rw-r--r--backends/table/table.cc2
-rw-r--r--backends/verilog/verilog_backend.cc341
-rw-r--r--debian/changelog30
-rw-r--r--debian/compat1
-rw-r--r--debian/control6
-rw-r--r--debian/copyright45
-rw-r--r--debian/patches/0007-Disable-pretty-build.patch4
-rw-r--r--debian/patches/0009-Some-spelling-errors-fixed.patch102
-rw-r--r--debian/patches/0010-Fix-adding-of-sys.path-in-yosys-smtbmc.patch6
-rw-r--r--debian/patches/0010-Fix-reproducibility-of-PDF-documents-in-yosys-doc.patch4
-rw-r--r--debian/patches/0011-Do-not-show-g-build-flags-in-Version-string.patch6
-rw-r--r--debian/patches/0012-Skip-non-deterministic-test-causing-random-FTBFS-on-.patch6
-rw-r--r--debian/patches/0013-Let-dpkg-buildpackage-handle-stripping-of-binaries.patch13
-rw-r--r--debian/patches/0014-Set-path-to-berkeley-abc-instead-of-relative-path-to.patch35
-rw-r--r--debian/patches/01_gitrevision.patch8
-rw-r--r--debian/patches/02_removeabc.patch4
-rw-r--r--debian/patches/05_abc_executable.patch4
-rw-r--r--debian/patches/kfreebsd-support.patch28
-rw-r--r--debian/patches/series1
-rwxr-xr-xdebian/rules3
-rw-r--r--debian/yosys.install13
-rw-r--r--examples/anlogic/.gitignore7
-rw-r--r--examples/anlogic/README12
-rwxr-xr-xexamples/anlogic/build.sh4
-rw-r--r--examples/anlogic/build.tcl11
-rw-r--r--examples/anlogic/demo.adc2
-rw-r--r--examples/anlogic/demo.v18
-rw-r--r--examples/anlogic/demo.ys3
-rw-r--r--examples/igloo2/.gitignore4
-rw-r--r--examples/igloo2/example.pdc20
-rw-r--r--examples/igloo2/example.sdc2
-rw-r--r--examples/igloo2/example.v64
-rw-r--r--examples/igloo2/libero.tcl57
-rw-r--r--examples/igloo2/runme.sh6
-rw-r--r--examples/python-api/.gitignore1
-rwxr-xr-xexamples/python-api/pass.py32
-rwxr-xr-xexamples/python-api/script.py22
-rw-r--r--frontends/aiger/Makefile.inc3
-rw-r--r--frontends/aiger/aigerparse.cc451
-rw-r--r--frontends/aiger/aigerparse.h52
-rw-r--r--frontends/ast/ast.cc449
-rw-r--r--frontends/ast/ast.h31
-rw-r--r--frontends/ast/genrtlil.cc294
-rw-r--r--frontends/ast/simplify.cc336
-rw-r--r--frontends/blif/blifparse.cc2
-rw-r--r--frontends/ilang/ilang_frontend.cc38
-rw-r--r--frontends/ilang/ilang_frontend.h3
-rw-r--r--frontends/ilang/ilang_lexer.l1
-rw-r--r--frontends/ilang/ilang_parser.y77
-rw-r--r--frontends/json/jsonparse.cc24
-rw-r--r--frontends/liberty/liberty.cc13
-rw-r--r--frontends/verific/README31
-rw-r--r--frontends/verific/verific.cc636
-rw-r--r--frontends/verific/verific.h3
-rw-r--r--frontends/verific/verificsva.cc23
-rw-r--r--frontends/verilog/Makefile.inc2
-rw-r--r--frontends/verilog/const2ast.cc28
-rw-r--r--frontends/verilog/verilog_frontend.cc93
-rw-r--r--frontends/verilog/verilog_frontend.h12
-rw-r--r--frontends/verilog/verilog_lexer.l53
-rw-r--r--frontends/verilog/verilog_parser.y907
-rw-r--r--kernel/cellaigs.cc2
-rw-r--r--kernel/celltypes.h73
-rw-r--r--kernel/consteval.h9
-rw-r--r--kernel/cost.h4
-rw-r--r--kernel/driver.cc36
-rw-r--r--kernel/hashlib.h6
-rw-r--r--kernel/log.cc33
-rw-r--r--kernel/log.h50
-rw-r--r--kernel/register.cc4
-rw-r--r--kernel/rtlil.cc277
-rw-r--r--kernel/rtlil.h180
-rw-r--r--kernel/yosys.cc113
-rw-r--r--kernel/yosys.h20
-rw-r--r--libs/ezsat/ezminisat.h2
-rw-r--r--libs/subcircuit/README6
-rw-r--r--libs/subcircuit/subcircuit.cc10
-rw-r--r--manual/CHAPTER_CellLib.tex71
-rw-r--r--manual/CHAPTER_Overview.tex21
-rw-r--r--misc/__init__.py5
-rw-r--r--misc/launcher.c359
-rw-r--r--misc/py_wrap_generator.py2097
-rw-r--r--misc/yosys.proto12
-rw-r--r--passes/cmds/Makefile.inc2
-rw-r--r--passes/cmds/add.cc2
-rw-r--r--passes/cmds/blackbox.cc2
-rw-r--r--passes/cmds/bugpoint.cc371
-rw-r--r--passes/cmds/chformal.cc4
-rw-r--r--passes/cmds/connect.cc6
-rw-r--r--passes/cmds/cover.cc10
-rw-r--r--passes/cmds/plugin.cc50
-rw-r--r--passes/cmds/qwp.cc2
-rw-r--r--passes/cmds/rename.cc148
-rw-r--r--passes/cmds/select.cc60
-rw-r--r--passes/cmds/setattr.cc39
-rw-r--r--passes/cmds/setundef.cc140
-rw-r--r--passes/cmds/show.cc27
-rw-r--r--passes/cmds/stat.cc76
-rw-r--r--passes/cmds/tee.cc9
-rw-r--r--passes/cmds/trace.cc34
-rw-r--r--passes/cmds/write_file.cc2
-rw-r--r--passes/equiv/Makefile.inc2
-rw-r--r--passes/equiv/equiv_make.cc86
-rw-r--r--passes/equiv/equiv_opt.cc170
-rw-r--r--passes/fsm/fsm_detect.cc8
-rw-r--r--passes/fsm/fsm_extract.cc4
-rw-r--r--passes/fsm/fsm_opt.cc3
-rw-r--r--passes/hierarchy/hierarchy.cc590
-rw-r--r--passes/hierarchy/uniquify.cc4
-rw-r--r--passes/memory/memory_bram.cc49
-rw-r--r--passes/memory/memory_collect.cc3
-rw-r--r--passes/memory/memory_dff.cc22
-rw-r--r--passes/opt/Makefile.inc3
-rw-r--r--passes/opt/muxpack.cc368
-rw-r--r--passes/opt/opt_clean.cc212
-rw-r--r--passes/opt/opt_expr.cc363
-rw-r--r--passes/opt/opt_lut.cc607
-rw-r--r--passes/opt/opt_merge.cc8
-rw-r--r--passes/opt/opt_muxtree.cc32
-rw-r--r--passes/opt/opt_rmdff.cc85
-rw-r--r--passes/opt/pmux2shiftx.cc860
-rw-r--r--passes/opt/rmports.cc2
-rw-r--r--passes/opt/share.cc8
-rw-r--r--passes/opt/wreduce.cc175
-rw-r--r--passes/pmgen/.gitignore2
-rw-r--r--passes/pmgen/Makefile.inc23
-rw-r--r--passes/pmgen/README.md236
-rw-r--r--passes/pmgen/ice40_dsp.cc240
-rw-r--r--passes/pmgen/ice40_dsp.pmg162
-rw-r--r--passes/pmgen/peepopt.cc68
-rw-r--r--passes/pmgen/peepopt_muldiv.pmg36
-rw-r--r--passes/pmgen/peepopt_shiftmul.pmg94
-rw-r--r--passes/pmgen/pmgen.py575
-rw-r--r--passes/proc/proc_clean.cc44
-rw-r--r--passes/proc/proc_mux.cc76
-rw-r--r--passes/proc/proc_rmdead.cc18
-rw-r--r--passes/sat/Makefile.inc4
-rw-r--r--passes/sat/assertpmux.cc6
-rw-r--r--passes/sat/async2sync.cc53
-rw-r--r--passes/sat/cutpoint.cc168
-rw-r--r--passes/sat/expose.cc2
-rw-r--r--passes/sat/fmcombine.cc376
-rw-r--r--passes/sat/miter.cc8
-rw-r--r--passes/sat/mutate.cc988
-rw-r--r--passes/sat/sat.cc5
-rw-r--r--passes/sat/sim.cc5
-rw-r--r--passes/sat/supercover.cc92
-rw-r--r--passes/techmap/Makefile.inc1
-rw-r--r--passes/techmap/abc.cc139
-rw-r--r--passes/techmap/attrmap.cc4
-rw-r--r--passes/techmap/deminout.cc7
-rw-r--r--passes/techmap/dff2dffe.cc35
-rw-r--r--passes/techmap/dffinit.cc36
-rw-r--r--passes/techmap/dfflibmap.cc18
-rw-r--r--passes/techmap/flowmap.cc1613
-rw-r--r--passes/techmap/libparse.cc178
-rw-r--r--passes/techmap/libparse.h10
-rw-r--r--passes/techmap/lut2mux.cc2
-rw-r--r--passes/techmap/muxcover.cc227
-rw-r--r--passes/techmap/pmuxtree.cc4
-rw-r--r--passes/techmap/shregmap.cc197
-rw-r--r--passes/techmap/simplemap.cc2
-rw-r--r--passes/techmap/techmap.cc72
-rw-r--r--passes/techmap/zinit.cc2
-rw-r--r--passes/tests/flowmap/flow.v22
-rw-r--r--passes/tests/flowmap/flowp.v16
-rw-r--r--passes/tests/flowmap/pack1.v11
-rw-r--r--passes/tests/flowmap/pack1p.v11
-rw-r--r--passes/tests/flowmap/pack2.v15
-rw-r--r--passes/tests/flowmap/pack2p.v15
-rw-r--r--passes/tests/flowmap/pack3.v15
-rw-r--r--passes/tests/flowmap/pack3p.v15
-rwxr-xr-xtechlibs/achronix/speedster22i/cells_map.v16
-rwxr-xr-xtechlibs/achronix/speedster22i/cells_sim.v8
-rwxr-xr-xtechlibs/achronix/synth_achronix.cc6
-rw-r--r--techlibs/anlogic/Makefile.inc12
-rw-r--r--techlibs/anlogic/anlogic_determine_init.cc72
-rw-r--r--techlibs/anlogic/anlogic_eqn.cc113
-rw-r--r--techlibs/anlogic/arith_map.v84
-rw-r--r--techlibs/anlogic/cells_map.v61
-rw-r--r--techlibs/anlogic/cells_sim.v103
-rw-r--r--techlibs/anlogic/dram_init_16x4.vh16
-rw-r--r--techlibs/anlogic/drams.txt16
-rw-r--r--techlibs/anlogic/drams_map.v22
-rw-r--r--techlibs/anlogic/eagle_bb.v1028
-rw-r--r--techlibs/anlogic/synth_anlogic.cc213
-rw-r--r--techlibs/common/Makefile.inc3
-rw-r--r--techlibs/common/cmp2lut.v105
-rw-r--r--techlibs/common/gate2lut.v87
-rw-r--r--techlibs/common/prep.cc8
-rw-r--r--techlibs/common/simcells.v4
-rw-r--r--techlibs/common/simlib.v176
-rw-r--r--techlibs/common/synth.cc50
-rw-r--r--techlibs/coolrunner2/synth_coolrunner2.cc4
-rw-r--r--techlibs/easic/synth_easic.cc2
-rw-r--r--techlibs/ecp5/.gitignore9
-rw-r--r--techlibs/ecp5/Makefile.inc38
-rw-r--r--techlibs/ecp5/arith_map.v11
-rw-r--r--techlibs/ecp5/bram.txt29
-rwxr-xr-xtechlibs/ecp5/brams_connect.py46
-rwxr-xr-xtechlibs/ecp5/brams_init.py22
-rw-r--r--techlibs/ecp5/brams_map.v115
-rw-r--r--techlibs/ecp5/cells_bb.v666
-rw-r--r--techlibs/ecp5/cells_map.v86
-rw-r--r--techlibs/ecp5/cells_sim.v216
-rw-r--r--techlibs/ecp5/dram.txt1
-rw-r--r--techlibs/ecp5/ecp5_ffinit.cc203
-rw-r--r--techlibs/ecp5/latches_map.v11
-rw-r--r--techlibs/ecp5/synth_ecp5.cc33
-rw-r--r--techlibs/gowin/Makefile.inc11
-rw-r--r--techlibs/gowin/arith_map.v59
-rw-r--r--techlibs/gowin/bram.txt29
-rw-r--r--techlibs/gowin/brams_init3.vh12
-rw-r--r--techlibs/gowin/brams_map.v103
-rw-r--r--techlibs/gowin/cells_map.v6
-rw-r--r--techlibs/gowin/cells_sim.v140
-rw-r--r--techlibs/gowin/determine_init.cc72
-rw-r--r--techlibs/gowin/dram.txt17
-rw-r--r--techlibs/gowin/drams_map.v31
-rw-r--r--techlibs/gowin/synth_gowin.cc75
-rw-r--r--techlibs/greenpak4/cells_map.v44
-rw-r--r--techlibs/greenpak4/synth_greenpak4.cc2
-rw-r--r--techlibs/ice40/Makefile.inc2
-rw-r--r--techlibs/ice40/brams_map.v4
-rw-r--r--techlibs/ice40/cells_sim.v343
-rw-r--r--techlibs/ice40/ice40_braminit.cc159
-rw-r--r--techlibs/ice40/ice40_ffssr.cc3
-rw-r--r--techlibs/ice40/ice40_opt.cc15
-rw-r--r--techlibs/ice40/ice40_unlut.cc106
-rw-r--r--techlibs/ice40/synth_ice40.cc93
-rw-r--r--techlibs/ice40/tests/.gitignore13
-rw-r--r--techlibs/ice40/tests/test_dsp_map.sh107
-rw-r--r--techlibs/ice40/tests/test_dsp_model.sh11
-rw-r--r--techlibs/ice40/tests/test_dsp_model.v342
-rw-r--r--techlibs/intel/common/brams_map.v16
-rw-r--r--techlibs/intel/cycloneive/arith_map.v10
-rw-r--r--techlibs/intel/cyclonev/cells_map.v4
-rw-r--r--techlibs/intel/cyclonev/cells_sim.v14
-rw-r--r--techlibs/intel/synth_intel.cc433
-rw-r--r--techlibs/sf2/Makefile.inc8
-rw-r--r--techlibs/sf2/arith_map.v21
-rw-r--r--techlibs/sf2/cells_map.v82
-rw-r--r--techlibs/sf2/cells_sim.v327
-rw-r--r--techlibs/sf2/sf2_iobs.cc197
-rw-r--r--techlibs/sf2/synth_sf2.cc246
-rw-r--r--techlibs/xilinx/Makefile.inc3
-rw-r--r--techlibs/xilinx/arith_map.v282
-rw-r--r--techlibs/xilinx/cells_map.v208
-rw-r--r--techlibs/xilinx/cells_sim.v178
-rw-r--r--techlibs/xilinx/cells_xtra.sh32
-rw-r--r--techlibs/xilinx/cells_xtra.v710
-rw-r--r--techlibs/xilinx/drams.txt24
-rw-r--r--techlibs/xilinx/drams_map.v34
-rw-r--r--techlibs/xilinx/ff_map.v42
-rw-r--r--techlibs/xilinx/lut2lut.v65
-rw-r--r--techlibs/xilinx/lut_map.v94
-rw-r--r--techlibs/xilinx/synth_xilinx.cc294
-rw-r--r--tests/aiger/.gitignore1
-rw-r--r--tests/aiger/and_.aag8
-rw-r--r--tests/aiger/and_.aig5
-rw-r--r--tests/aiger/buffer.aag5
-rw-r--r--tests/aiger/buffer.aig4
-rw-r--r--tests/aiger/cnt1.aag4
-rw-r--r--tests/aiger/cnt1.aig4
-rw-r--r--tests/aiger/cnt1e.aag9
-rw-r--r--tests/aiger/cnt1e.aig5
-rw-r--r--tests/aiger/empty.aag1
-rw-r--r--tests/aiger/empty.aig1
-rw-r--r--tests/aiger/false.aag3
-rw-r--r--tests/aiger/false.aig3
-rw-r--r--tests/aiger/halfadder.aag14
-rw-r--r--tests/aiger/halfadder.aig9
-rw-r--r--tests/aiger/inverter.aag5
-rw-r--r--tests/aiger/inverter.aig4
-rw-r--r--tests/aiger/notcnt1.aag4
-rw-r--r--tests/aiger/notcnt1.aig4
-rw-r--r--tests/aiger/notcnt1e.aag9
-rw-r--r--tests/aiger/notcnt1e.aig5
-rw-r--r--tests/aiger/or_.aag8
-rw-r--r--tests/aiger/or_.aig5
-rwxr-xr-xtests/aiger/run-test.sh54
-rw-r--r--tests/aiger/toggle-re.aag14
-rw-r--r--tests/aiger/toggle-re.aig8
-rw-r--r--tests/aiger/toggle.aag6
-rw-r--r--tests/aiger/toggle.aig6
-rw-r--r--tests/aiger/true.aag3
-rw-r--r--tests/aiger/true.aig3
-rwxr-xr-xtests/arch/run-test.sh18
-rw-r--r--tests/asicworld/code_hdl_models_misc1.v22
-rw-r--r--tests/asicworld/code_hdl_models_mux21_switch.v22
-rw-r--r--tests/asicworld/code_hdl_models_nand_switch.v14
-rw-r--r--tests/asicworld/code_hdl_models_t_gate_switch.v11
-rwxr-xr-xtests/asicworld/run-test.sh2
-rw-r--r--tests/asicworld/xfirrtl23
-rw-r--r--tests/errors/syntax_err01.v4
-rw-r--r--tests/errors/syntax_err02.v7
-rw-r--r--tests/errors/syntax_err03.v7
-rw-r--r--tests/errors/syntax_err04.v4
-rw-r--r--tests/errors/syntax_err05.v4
-rw-r--r--tests/errors/syntax_err06.v6
-rw-r--r--tests/errors/syntax_err07.v6
-rw-r--r--tests/errors/syntax_err08.v6
-rw-r--r--tests/errors/syntax_err09.v3
-rw-r--r--tests/errors/syntax_err10.v3
-rw-r--r--tests/errors/syntax_err11.v3
-rw-r--r--tests/errors/syntax_err12.v7
-rw-r--r--tests/errors/syntax_err13.v4
-rw-r--r--tests/liberty/.gitignore2
-rw-r--r--tests/liberty/busdef.lib81
-rw-r--r--tests/liberty/normal.lib359
-rw-r--r--tests/liberty/processdefs.lib48
-rwxr-xr-xtests/liberty/run-test.sh10
-rw-r--r--tests/liberty/semicolextra.lib48
-rw-r--r--tests/liberty/semicolmissing.lib72
-rw-r--r--tests/liberty/small.v16
-rw-r--r--tests/lut/.gitignore1
-rw-r--r--tests/lut/check_map.ys6
-rw-r--r--tests/lut/map_and.v5
-rw-r--r--tests/lut/map_cmp.v29
-rw-r--r--tests/lut/map_mux.v5
-rw-r--r--tests/lut/map_not.v5
-rw-r--r--tests/lut/map_or.v5
-rw-r--r--tests/lut/map_xor.v5
-rwxr-xr-xtests/lut/run-test.sh6
-rw-r--r--tests/memories/firrtl_938.v22
-rw-r--r--tests/memories/issue00335.v28
-rw-r--r--tests/memories/issue00710.v17
-rw-r--r--tests/memories/read_two_mux.v16
-rwxr-xr-xtests/memories/run-test.sh16
-rw-r--r--tests/opt/.gitignore1
-rw-r--r--tests/opt/opt_expr_cmp.v40
-rw-r--r--tests/opt/opt_expr_cmp.ys4
-rw-r--r--tests/opt/opt_ff.v21
-rw-r--r--tests/opt/opt_ff.ys3
-rw-r--r--tests/opt/opt_lut.v18
-rw-r--r--tests/opt/opt_lut.ys4
-rw-r--r--tests/opt/opt_lut_elim.il19
-rw-r--r--tests/opt/opt_lut_elim.ys3
-rw-r--r--tests/opt/opt_lut_port.il18
-rw-r--r--tests/opt/opt_lut_port.ys3
-rwxr-xr-xtests/opt/run-test.sh6
-rw-r--r--tests/sat/counters-repeat.v38
-rw-r--r--tests/sat/counters-repeat.ys10
-rw-r--r--tests/simple/arrays02.sv16
-rw-r--r--tests/simple/attrib01_module.v21
-rw-r--r--tests/simple/attrib02_port_decl.v25
-rw-r--r--tests/simple/attrib03_parameter.v28
-rw-r--r--tests/simple/attrib04_net_var.v32
-rw-r--r--tests/simple/attrib05_port_conn.v.DISABLED21
-rw-r--r--tests/simple/attrib06_operator_suffix.v23
-rw-r--r--tests/simple/attrib07_func_call.v.DISABLED21
-rw-r--r--tests/simple/attrib08_mod_inst.v22
-rw-r--r--tests/simple/attrib09_case.v26
-rw-r--r--tests/simple/defvalue.sv22
-rw-r--r--tests/simple/dff_init.v54
-rw-r--r--tests/simple/forloops.v25
-rw-r--r--tests/simple/generate.v67
-rw-r--r--tests/simple/hierdefparam.v2
-rw-r--r--tests/simple/implicit_ports.v16
-rw-r--r--tests/simple/localparam_attr.v11
-rw-r--r--tests/simple/mem2reg.v22
-rw-r--r--tests/simple/param_attr.v11
-rw-r--r--tests/simple/peepopt.v13
-rw-r--r--tests/simple/retime.v6
-rwxr-xr-xtests/simple/run-test.sh3
-rw-r--r--tests/simple/task_func.v19
-rw-r--r--tests/simple/wandwor.v36
-rw-r--r--tests/simple/xfirrtl27
-rw-r--r--tests/sva/basic01.sv2
-rw-r--r--tests/sva/extnets.sv22
-rw-r--r--tests/svinterfaces/.gitignore8
-rwxr-xr-xtests/svinterfaces/run-test.sh6
-rwxr-xr-xtests/svinterfaces/runone.sh44
-rw-r--r--tests/svinterfaces/svinterface1.sv117
-rw-r--r--tests/svinterfaces/svinterface1_ref.v107
-rw-r--r--tests/svinterfaces/svinterface1_tb.v57
-rw-r--r--tests/svinterfaces/svinterface_at_top.sv125
-rw-r--r--tests/svinterfaces/svinterface_at_top_ref.v120
-rw-r--r--tests/svinterfaces/svinterface_at_top_tb.v68
-rw-r--r--tests/svinterfaces/svinterface_at_top_tb_wrapper.v68
-rw-r--r--tests/svinterfaces/svinterface_at_top_wrapper.v33
-rw-r--r--tests/tools/autotest.mk6
-rwxr-xr-xtests/tools/autotest.sh98
-rw-r--r--tests/various/.gitignore3
-rw-r--r--tests/various/attrib05_port_conn.v21
-rw-r--r--tests/various/attrib05_port_conn.ys2
-rw-r--r--tests/various/attrib07_func_call.v21
-rw-r--r--tests/various/attrib07_func_call.ys2
-rw-r--r--tests/various/chparam.sh52
-rw-r--r--tests/various/elab_sys_tasks.sv30
-rw-r--r--tests/various/elab_sys_tasks.ys1
-rw-r--r--tests/various/hierarchy.sh60
-rw-r--r--tests/various/muxcover.ys461
-rw-r--r--tests/various/muxpack.v259
-rw-r--r--tests/various/muxpack.ys268
-rw-r--r--tests/various/opt_rmdff.v50
-rw-r--r--tests/various/opt_rmdff.ys26
-rw-r--r--tests/various/pmux2shiftx.v44
-rw-r--r--tests/various/pmux2shiftx.ys39
-rwxr-xr-xtests/various/run-test.sh10
-rw-r--r--tests/various/shregmap.v48
-rw-r--r--tests/various/shregmap.ys66
-rw-r--r--tests/various/signext.ys33
-rw-r--r--tests/various/specify.v39
-rw-r--r--tests/various/specify.ys58
435 files changed, 30565 insertions, 2921 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 00000000..28d13da2
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+# Default Linux style
+BasedOnStyle: LLVM
+IndentWidth: 8
+UseTab: Always
+BreakBeforeBraces: Linux
+AllowShortIfStatementsOnASingleLine: false
+IndentCaseLabels: false
+
+# From CodingReadme
+TabWidth: 8
+ContinuationIndentWidth: 2
+ColumnLimit: 150
+# BreakBeforeBraces: Linux
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..9910e995
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,13 @@
+.editorconfig
+.gitignore
+.gitmodules
+.github
+.git
+Dockerfile
+README.md
+manual
+CodingReadme
+CodeOfConduct
+.travis
+.travis.yml
+
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..4d6f5ef7
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,7 @@
+root = true
+
+[*]
+indent_style = tab
+indent_size = tab
+trim_trailing_whitespace = true
+insert_final_newline = true
diff --git a/.github/issue_template.md b/.github/issue_template.md
index 24e91a4e..5a0723c3 100644
--- a/.github/issue_template.md
+++ b/.github/issue_template.md
@@ -1,9 +1,20 @@
## Steps to reproduce the issue
*Provide instructions for reproducing the issue. Make sure to include
-all neccessary source files. (You can simply drag&drop a .zip file into
+all necessary source files. (You can simply drag&drop a .zip file into
the issue editor.)*
+Also, make sure that the issue is actually reproducable in current git
+master of Yosys.
+
+See https://stackoverflow.com/help/mcve for some information on how to
+create a Minimal, Complete, and Verifiable example (MCVE).
+
+Please do not waste our time with issues that lack sufficient information
+to reproduce the issue easily. We will simply close those issues.
+
+Contact https://www.symbioticeda.com/ if you need commercial support for Yosys.
+
## Expected behavior
*Please describe the behavior you would have expected from the tool.*
@@ -11,6 +22,3 @@ the issue editor.)*
## Actual behavior
*Please describe how the behavior you see differs from the expected behavior.*
-
-**Important Note:** Nobody will be able to help you and/or fix the issue if you
-do not provide sufficient information for reproducing the problem.
diff --git a/.gitignore b/.gitignore
index 48ce458c..76f53cd0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
*.gch
*.gcda
*.gcno
+__pycache__
/.cproject
/.project
/.settings
@@ -24,8 +25,12 @@
/yosys-abc.exe
/yosys-config
/yosys-smtbmc
+/yosys-smtbmc.exe
+/yosys-smtbmc-script.py
/yosys-filterlib
/yosys-filterlib.exe
+/kernel/*.pyh
+/kernel/python_wrappers.cc
/kernel/version_*.cc
/share
/yosys-win32-mxebin-*
diff --git a/.travis.yml b/.travis.yml
index 321c3325..c253b2ff 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,33 +32,13 @@ matrix:
- xdot
- pkg-config
- python
+ - python3
+ - libboost-system-dev
+ - libboost-python-dev
+ - libboost-filesystem-dev
env:
- MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8"
- # Latest gcc-6 on Travis Linux
- - os: linux
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - g++-6
- - gperf
- - build-essential
- - bison
- - flex
- - libreadline-dev
- - gawk
- - tcl-dev
- - libffi-dev
- - git
- - graphviz
- - xdot
- - pkg-config
- - python
- env:
- - MATRIX_EVAL="CONFIG=gcc && CC=gcc-6 && CXX=g++-6"
-
# Latest gcc supported on Travis Linux
- os: linux
addons:
@@ -66,7 +46,7 @@ matrix:
sources:
- ubuntu-toolchain-r-test
packages:
- - g++-7
+ - g++-9
- gperf
- build-essential
- bison
@@ -80,8 +60,12 @@ matrix:
- xdot
- pkg-config
- python
+ - python3
+ - libboost-system-dev
+ - libboost-python-dev
+ - libboost-filesystem-dev
env:
- - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7"
+ - MATRIX_EVAL="CONFIG=gcc && CC=gcc-9 && CXX=g++-9"
# Clang which ships on Trusty Linux
- os: linux
@@ -105,6 +89,10 @@ matrix:
- xdot
- pkg-config
- python
+ - python3
+ - libboost-system-dev
+ - libboost-python-dev
+ - libboost-filesystem-dev
env:
- MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8"
@@ -113,9 +101,9 @@ matrix:
addons:
apt:
sources:
- - llvm-toolchain-trusty-5.0
+ - llvm-toolchain-xenial-8
packages:
- - clang-5.0
+ - clang-8
- gperf
- build-essential
- bison
@@ -129,14 +117,18 @@ matrix:
- xdot
- pkg-config
- python
+ - python3
+ - libboost-system-dev
+ - libboost-python-dev
+ - libboost-filesystem-dev
env:
- - MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0"
+ - MATRIX_EVAL="CONFIG=clang && CC=clang-8 && CXX=clang++-8"
- # Latest clang on Mac OS X
- - os: osx
- osx_image: xcode8
- env:
- - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7"
+# # Latest clang on Mac OS X
+# - os: osx
+# osx_image: xcode9.4
+# env:
+# - MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++"
before_install:
- ./.travis/setup.sh
diff --git a/.travis/build-and-test.sh b/.travis/build-and-test.sh
index 096dde64..b8c35041 100755
--- a/.travis/build-and-test.sh
+++ b/.travis/build-and-test.sh
@@ -36,6 +36,8 @@ echo
##########################################################################
+./yosys tests/simple/fiedler-cooley.v
+
echo
echo 'Testing...' && echo -en 'travis_fold:start:script.test\\r'
echo
diff --git a/.travis/setup.sh b/.travis/setup.sh
index 06851578..02879b97 100755
--- a/.travis/setup.sh
+++ b/.travis/setup.sh
@@ -6,48 +6,15 @@ source .travis/common.sh
##########################################################################
-# Fixing Travis's git clone
-echo
-echo 'Fixing git setup...' && echo -en 'travis_fold:start:before_install.git\\r'
-echo
-git fetch --unshallow && git fetch --tags
-
-# For pull requests, we get more info about the git source.
-if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then
- echo "- Fetching from pull request source"
- git remote add source https://github.com/$TRAVIS_PULL_REQUEST_SLUG.git
- git fetch source && git fetch --tags
-
- echo "- Fetching the actual pull request"
- git fetch origin pull/$TRAVIS_PULL_REQUEST/head:pull-$TRAVIS_PULL_REQUEST-head
- git fetch origin pull/$TRAVIS_PULL_REQUEST/merge:pull-$TRAVIS_PULL_REQUEST-merge
-
- git log -n 5 --graph pull-$TRAVIS_PULL_REQUEST-merge
-fi
-
-# For building branches we need to fix the "detached head" state.
-if [ z"$TRAVIS_BRANCH" != z ]; then
- TRAVIS_COMMIT_ACTUAL=$(git log --pretty=format:'%H' -n 1)
- echo "- Fixing detached head (current $TRAVIS_COMMIT_ACTUAL -> $TRAVIS_COMMIT)"
- git remote -v
- git branch -v
- if [ x"$(git show-ref -s HEAD)" = x"$TRAVIS_COMMIT" ]; then
- echo "Checked out at $TRAVIS_COMMIT"
- else
- if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then
- git fetch source $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from source"
- fi
- git fetch origin $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from origin"
- fi
- git branch -D $TRAVIS_BRANCH || true
- git checkout $TRAVIS_COMMIT -b $TRAVIS_BRANCH
- git branch -v
-fi
-
# Output status information.
-git status
-git describe --tags
-git log -n 5 --graph
+(
+ set +e
+ set -x
+ git status
+ git branch -v
+ git log -n 5 --graph
+ git log --format=oneline -n 20 --graph
+)
echo
echo -en 'travis_fold:end:before_install.git\\r'
echo
@@ -64,7 +31,6 @@ if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew tap Homebrew/bundle
brew bundle
brew install ccache
- brew install gcc@7
echo
echo -en 'travis_fold:end:before_install.brew\\r'
echo
@@ -85,7 +51,7 @@ fi
git clone git://github.com/steveicarus/iverilog.git
cd iverilog
autoconf
- ./configure --prefix=$HOME/.local-bin
+ CC=gcc CXX=g++ ./configure --prefix=$HOME/.local-bin
make
make install
echo
diff --git a/Brewfile b/Brewfile
index 0c58ce16..4ffe50e8 100644
--- a/Brewfile
+++ b/Brewfile
@@ -6,3 +6,4 @@ brew "git"
brew "graphviz"
brew "pkg-config"
brew "python3"
+brew "tcl-tk"
diff --git a/CHANGELOG b/CHANGELOG
index 5499c309..afbcffa2 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,125 @@ List of major changes and improvements between releases
=======================================================
+Yosys 0.8 .. Yosys 0.9
+--------------------------
+
+ * Various
+ - Many bugfixes and small improvements
+ - Added support for SystemVerilog interfaces and modports
+ - Added "write_edif -attrprop"
+ - Added "opt_lut" pass
+ - Added "gate2lut.v" techmap rule
+ - Added "rename -src"
+ - Added "equiv_opt" pass
+ - Added "flowmap" LUT mapping pass
+ - Added "rename -wire" to rename cells based on the wires they drive
+ - Added "bugpoint" for creating minimised testcases
+ - Added "write_edif -gndvccy"
+ - "write_verilog" to escape Verilog keywords
+ - Fixed sign handling of real constants
+ - "write_verilog" to write initial statement for initial flop state
+ - Added pmgen pattern matcher generator
+ - Fixed opt_rmdff handling of $_DFFSR_???_ and $_DLATCHSR_???_
+ - Added "setundef -params" to replace undefined cell parameters
+ - Renamed "yosys -D" to "yosys -U", added "yosys -D" to set Verilog defines
+ - Fixed handling of defparam when default_nettype is none
+ - Fixed "wreduce" flipflop handling
+ - Fixed FIRRTL to Verilog process instance subfield assignment
+ - Added "write_verilog -siminit"
+ - Several fixes and improvements for mem2reg memories
+ - Fixed handling of task output ports in clocked always blocks
+ - Improved handling of and-with-1 and or-with-0 in "opt_expr"
+ - Added "read_aiger" frontend
+ - Added "mutate" pass
+ - Added "hdlname" attribute
+ - Added "rename -output"
+ - Added "read_ilang -lib"
+ - Improved "proc" full_case detection and handling
+ - Added "whitebox" and "lib_whitebox" attributes
+ - Added "read_verilog -nowb", "flatten -wb" and "wbflip"
+ - Added Python bindings and support for Python plug-ins
+ - Added "pmux2shiftx"
+ - Added log_debug framework for reduced default verbosity
+ - Improved "opt_expr" and "opt_clean" handling of (partially) undriven and/or unused wires
+ - Added "peepopt" peephole optimisation pass using pmgen
+ - Added approximate support for SystemVerilog "var" keyword
+ - Added parsing of "specify" blocks into $specrule and $specify[23]
+ - Added support for attributes on parameters and localparams
+ - Added support for parsing attributes on port connections
+ - Added "wreduce -keepdc"
+ - Added support for optimising $dffe and $_DFFE_* cells in "opt_rmdff"
+ - Added Verilog wand/wor wire type support
+ - Added support for elaboration system tasks
+ - Added "muxcover -mux{4,8,16}=<cost>"
+ - Added "muxcover -dmux=<cost>"
+ - Added "muxcover -nopartial"
+ - Added "muxpack" pass
+ - Added "pmux2shiftx -norange"
+ - Added support for "~" in filename parsing
+ - Added "read_verilog -pwires" feature to turn parameters into wires
+ - Fixed sign extension of unsized constants with 'bx and 'bz MSB
+ - Fixed genvar to be a signed type
+ - Added support for attributes on case rules
+ - Added "upto" and "offset" to JSON frontend and backend
+ - Several liberty file parser improvements
+ - Fixed handling of more complex BRAM patterns
+ - Add "write_aiger -I -O -B"
+
+ * Formal Verification
+ - Added $changed support to read_verilog
+ - Added "read_verilog -noassert -noassume -assert-assumes"
+ - Added btor ops for $mul, $div, $mod and $concat
+ - Added yosys-smtbmc support for btor witnesses
+ - Added "supercover" pass
+ - Fixed $global_clock handling vs autowire
+ - Added $dffsr support to "async2sync"
+ - Added "fmcombine" pass
+ - Added memory init support in "write_btor"
+ - Added "cutpoint" pass
+ - Changed "ne" to "neq" in btor2 output
+ - Added support for SVA "final" keyword
+ - Added "fmcombine -initeq -anyeq"
+ - Added timescale and generated-by header to yosys-smtbmc vcd output
+ - Improved BTOR2 handling of undriven wires
+
+ * Verific support
+ - Enabled Verific flags vhdl_support_variable_slice and veri_elaborate_top_level_modules_having_interface_ports
+ - Improved support for asymmetric memories
+ - Added "verific -chparam"
+ - Fixed "verific -extnets" for more complex situations
+ - Added "read -verific" and "read -noverific"
+ - Added "hierarchy -chparam"
+
+ * New back-ends
+ - Added initial Anlogic support
+ - Added initial SmartFusion2 and IGLOO2 support
+
+ * ECP5 support
+ - Added "synth_ecp5 -nowidelut"
+ - Added BRAM inference support to "synth_ecp5"
+ - Added support for transforming Diamond IO and flipflop primitives
+
+ * iCE40 support
+ - Added "ice40_unlut" pass
+ - Added "synth_ice40 -relut"
+ - Added "synth_ice40 -noabc"
+ - Added "synth_ice40 -dffe_min_ce_use"
+ - Added DSP inference support using pmgen
+ - Added support for initialising BRAM primitives from a file
+ - Added iCE40 Ultra RGB LED driver cells
+
+ * Xilinx support
+ - Use "write_edif -pvector bra" for Xilinx EDIF files
+ - Fixes for VPR place and route support with "synth_xilinx"
+ - Added more cell simulation models
+ - Added "synth_xilinx -family"
+ - Added "stat -tech xilinx" to estimate logic cell usage
+ - Added "synth_xilinx -nocarry"
+ - Added "synth_xilinx -nowidelut"
+ - "synth_xilinx" to now infer hard shift registers (-nosrl to disable)
+ - Added support for mapping RAM32X1D
+
Yosys 0.7 .. Yosys 0.8
----------------------
@@ -14,7 +133,7 @@ Yosys 0.7 .. Yosys 0.8
- Added "write_verilog -decimal"
- Added "scc -set_attr"
- Added "verilog_defines" command
- - Remeber defines from one read_verilog to next
+ - Remember defines from one read_verilog to next
- Added support for hierarchical defparam
- Added FIRRTL back-end
- Improved ABC default scripts
@@ -23,7 +142,7 @@ Yosys 0.7 .. Yosys 0.8
- Added Verilog $rtoi and $itor support
- Added "check -initdrv"
- Added "read_blif -wideports"
- - Added support for systemVerilog "++" and "--" operators
+ - Added support for SystemVerilog "++" and "--" operators
- Added support for SystemVerilog unique, unique0, and priority case
- Added "write_edif" options for edif "flavors"
- Added support for resetall compiler directive
diff --git a/COPYING b/COPYING
index a01b7b69..0839088c 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright (C) 2012 - 2017 Clifford Wolf <clifford@clifford.at>
+Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..3c7188d8
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,33 @@
+FROM ubuntu:18.04 as builder
+LABEL author="Abdelrahman Hosny <abdelrahman.hosny@hotmail.com>"
+ENV DEBIAN_FRONTEND=noninteractive
+RUN apt-get update && apt-get install -y build-essential \
+ clang \
+ bison \
+ flex \
+ libreadline-dev \
+ gawk \
+ tcl-dev \
+ libffi-dev \
+ git \
+ pkg-config \
+ python3 && \
+ rm -rf /var/lib/apt/lists
+COPY . /
+RUN make && \
+ make install
+
+FROM ubuntu:18.04
+ENV DEBIAN_FRONTEND=noninteractive
+RUN apt-get update && apt-get install -y libreadline-dev tcl-dev
+
+COPY --from=builder /yosys /build/yosys
+COPY --from=builder /yosys-abc /build/yosys-abc
+COPY --from=builder /yosys-config /build/yosys-config
+COPY --from=builder /yosys-filterlib /build/yosys-filterlib
+COPY --from=builder /yosys-smtbmc /build/yosys-smtbmc
+
+ENV PATH /build:$PATH
+RUN useradd -m yosys
+USER yosys
+ENTRYPOINT ["yosys"]
diff --git a/Makefile b/Makefile
index 961e2cee..0a75c58f 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,7 @@
CONFIG := clang
# CONFIG := gcc
# CONFIG := gcc-4.8
+# CONFIG := afl-gcc
# CONFIG := emcc
# CONFIG := mxe
# CONFIG := msys2
@@ -10,6 +11,7 @@ CONFIG := clang
# features (the more the better)
ENABLE_TCL := 1
ENABLE_ABC := 1
+ENABLE_GLOB := 1
ENABLE_PLUGINS := 1
ENABLE_READLINE := 1
ENABLE_EDITLINE := 0
@@ -18,6 +20,9 @@ ENABLE_COVER := 1
ENABLE_LIBYOSYS := 0
ENABLE_PROTOBUF := 0
+# python wrappers
+ENABLE_PYOSYS := 0
+
# other configuration flags
ENABLE_GCOV := 0
ENABLE_GPROF := 0
@@ -41,6 +46,10 @@ OS := $(shell uname -s)
PREFIX ?= /usr/local
INSTALL_SUDO :=
+ifneq ($(wildcard Makefile.conf),)
+include Makefile.conf
+endif
+
BINDIR := $(PREFIX)/bin
LIBDIR := $(PREFIX)/lib
DATDIR := $(PREFIX)/share/yosys
@@ -72,6 +81,7 @@ PKG_CONFIG ?= pkg-config
SED ?= sed
BISON ?= bison
STRIP ?= strip
+AWK ?= awk
ifeq ($(OS), Darwin)
PLUGIN_LDFLAGS += -undefined dynamic_lookup
@@ -79,6 +89,11 @@ PLUGIN_LDFLAGS += -undefined dynamic_lookup
# homebrew search paths
ifneq ($(shell which brew),)
BREW_PREFIX := $(shell brew --prefix)/opt
+$(info $$BREW_PREFIX is [${BREW_PREFIX}])
+ifeq ($(ENABLE_PYOSYS),1)
+CXXFLAGS += -I$(BREW_PREFIX)/boost/include/boost
+LDFLAGS += -L$(BREW_PREFIX)/boost/lib
+endif
CXXFLAGS += -I$(BREW_PREFIX)/readline/include
LDFLAGS += -L$(BREW_PREFIX)/readline/lib
PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)
@@ -99,8 +114,8 @@ LDFLAGS += -rdynamic
LDLIBS += -lrt
endif
-YOSYS_VER := 0.8
-GIT_REV := 5706e90
+YOSYS_VER := 0.9
+GIT_REV := 1979e0b
OBJS = kernel/version_$(GIT_REV).o
# set 'ABCREV = default' to use abc/ as it is
@@ -109,7 +124,7 @@ OBJS = kernel/version_$(GIT_REV).o
# is just a symlink to your actual ABC working directory, as 'make mrproper'
# will remove the 'abc' directory and you do not want to accidentally
# delete your work on ABC..
-ABCREV = ae6716b
+ABCREV = 3709744
ABCPULL = 1
ABCURL ?= https://github.com/berkeley-abc/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
@@ -128,6 +143,21 @@ $(info $(subst $$--$$,$(newline),$(shell sed 's,^,[Makefile.conf] ,; s,$$,$$--$$
include Makefile.conf
endif
+ifeq ($(ENABLE_PYOSYS),1)
+PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)"
+PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi)
+PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
+PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.)
+PYTHON_PREFIX := $(shell $(PYTHON_EXECUTABLE)-config --prefix)
+PYTHON_DESTDIR := $(PYTHON_PREFIX)/lib/python$(PYTHON_VERSION)/site-packages
+
+# Reload Makefile.conf to override python specific variables if defined
+ifneq ($(wildcard Makefile.conf),)
+include Makefile.conf
+endif
+
+endif
+
ifeq ($(CONFIG),clang)
CXX = clang
LD = clang++
@@ -160,7 +190,7 @@ ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
else ifeq ($(CONFIG),gcc-static)
LD = $(CXX)
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -static
-LDLIBS := $(filter-out -lrt,$(LDLIBS))
+LDLIBS := $(filter-out -lrt,$(LDLIBS))
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
CXXFLAGS += -std=c++11 -Os
ABCMKARGS = CC="$(CC)" CXX="$(CXX)" LD="$(LD)" ABC_USE_LIBSTDCXX=1 LIBS="-lm -lpthread -static" OPTFLAGS="-O" \
@@ -175,6 +205,12 @@ LD = gcc-4.8
CXXFLAGS += -std=c++11 -Os
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
+else ifeq ($(CONFIG),afl-gcc)
+CXX = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc
+LD = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc
+CXXFLAGS += -std=c++11 -Os
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
+
else ifeq ($(CONFIG),cygwin)
CXX = gcc
LD = gcc
@@ -226,7 +262,8 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
LDLIBS := $(filter-out -lrt,$(LDLIBS))
ABCMKARGS += ARCHFLAGS="-DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
-ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc"
+# TODO: Try to solve pthread linking issue in more appropriate way
+ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" LDFLAGS="-Wl,--allow-multiple-definition" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc"
EXE = .exe
else ifeq ($(CONFIG),msys2)
@@ -259,6 +296,55 @@ ifeq ($(ENABLE_LIBYOSYS),1)
TARGETS += libyosys.so
endif
+ifeq ($(ENABLE_PYOSYS),1)
+
+#Detect name of boost_python library. Some distros usbe boost_python-py<version>, other boost_python<version>, some only use the major version number, some a concatenation of major and minor version numbers
+ifeq ($(OS), Darwin)
+BOOST_PYTHON_LIB ?= $(shell \
+ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \
+ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
+ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \
+ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
+ echo ""; fi; fi; fi; fi;)
+else
+BOOST_PYTHON_LIB ?= $(shell \
+ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \
+ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
+ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \
+ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
+ echo ""; fi; fi; fi; fi;)
+endif
+
+ifeq ($(BOOST_PYTHON_LIB),)
+$(error BOOST_PYTHON_LIB could not be detected. Please define manualy)
+endif
+
+ifeq ($(OS), Darwin)
+ifeq ($(PYTHON_MAJOR_VERSION),3)
+LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
+CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
+else
+LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
+CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
+endif
+else
+ifeq ($(PYTHON_MAJOR_VERSION),3)
+LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
+CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
+else
+LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
+CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
+endif
+endif
+
+ifeq ($(ENABLE_PYOSYS),1)
+PY_WRAPPER_FILE = kernel/python_wrappers
+OBJS += $(PY_WRAPPER_FILE).o
+PY_GEN_SCRIPT= py_wrap_generator
+PY_WRAP_INCLUDES := $(shell python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()")
+endif
+endif
+
ifeq ($(ENABLE_READLINE),1)
CXXFLAGS += -DYOSYS_ENABLE_READLINE
ifeq ($(OS), FreeBSD)
@@ -297,6 +383,10 @@ LDLIBS += -ldl
endif
endif
+ifeq ($(ENABLE_GLOB),1)
+CXXFLAGS += -DYOSYS_ENABLE_GLOB
+endif
+
ifeq ($(ENABLE_TCL),1)
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
ifeq ($(OS), FreeBSD)
@@ -307,7 +397,7 @@ endif
ifeq ($(CONFIG),mxe)
CXXFLAGS += -DYOSYS_ENABLE_TCL
-LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz
+LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz -luserenv
else
CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL
ifeq ($(OS), FreeBSD)
@@ -356,11 +446,15 @@ endif
endif
ifeq ($(ENABLE_VERIFIC),1)
-VERIFIC_DIR ?= /usr/local/src/verific_lib_eval
-VERIFIC_COMPONENTS ?= verilog vhdl database util containers sdf hier_tree
+VERIFIC_DIR ?= /usr/local/src/verific_lib
+VERIFIC_COMPONENTS ?= verilog vhdl database util containers hier_tree
CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC
+ifeq ($(OS), Darwin)
+LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-mac.a,$(VERIFIC_COMPONENTS)) -lz
+else
LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS)) -lz
endif
+endif
ifeq ($(ENABLE_PROTOBUF),1)
LDLIBS += $(shell pkg-config --cflags --libs protobuf)
@@ -391,8 +485,8 @@ endef
ifeq ($(PRETTY), 1)
P_STATUS = 0
P_OFFSET = 0
-P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys$(EXE) | gawk 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
-P_SHOW = [$(shell gawk "BEGIN { N=$(words $(OBJS) yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
+P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys$(EXE) | $(AWK) 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
+P_SHOW = [$(shell $(AWK) "BEGIN { N=$(words $(OBJS) yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
P = @echo "$(if $(findstring $@,$(TARGETS) $(EXTRA_TARGETS)),$(eval P_OFFSET = 10))$(call P_UPDATE)$(call P_SHOW) Building $@";
Q = @
S = -s
@@ -494,12 +588,26 @@ yosys$(EXE): $(OBJS)
$(P) $(LD) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS)
libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
+ifeq ($(OS), Darwin)
+ $(P) $(LD) -o libyosys.so -shared -Wl,-install_name,libyosys.so $(LDFLAGS) $^ $(LDLIBS)
+else
$(P) $(LD) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LDFLAGS) $^ $(LDLIBS)
+endif
%.o: %.cc
$(Q) mkdir -p $(dir $@)
$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $<
+%.pyh: %.h
+ $(Q) mkdir -p $(dir $@)
+ $(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(LD) -x c++ -o $@ -E -P -
+
+ifeq ($(ENABLE_PYOSYS),1)
+$(PY_WRAPPER_FILE).cc: misc/$(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES)
+ $(Q) mkdir -p $(dir $@)
+ $(P) python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")"
+endif
+
%.o: %.cpp
$(Q) mkdir -p $(dir $@)
$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $<
@@ -562,6 +670,12 @@ else
SEEDOPT=""
endif
+ifneq ($(ABCEXTERNAL),)
+ABCOPT="-A $(ABCEXTERNAL)"
+else
+ABCOPT=""
+endif
+
test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/simple && bash run-test.sh $(SEEDOPT)
+cd tests/hana && bash run-test.sh $(SEEDOPT)
@@ -570,10 +684,14 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/share && bash run-test.sh $(SEEDOPT)
+cd tests/fsm && bash run-test.sh $(SEEDOPT)
+cd tests/techmap && bash run-test.sh
- +cd tests/memories && bash run-test.sh $(SEEDOPT)
+ +cd tests/memories && bash run-test.sh $(ABCOPT) $(SEEDOPT)
+cd tests/bram && bash run-test.sh $(SEEDOPT)
+cd tests/various && bash run-test.sh
+cd tests/sat && bash run-test.sh
+ +cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
+ +cd tests/opt && bash run-test.sh
+ +cd tests/aiger && bash run-test.sh $(ABCOPT)
+ +cd tests/arch && bash run-test.sh
@echo ""
@echo " Passed \"make test\"."
@echo ""
@@ -594,8 +712,8 @@ vloghtb: $(TARGETS) $(EXTRA_TARGETS)
ystests: $(TARGETS) $(EXTRA_TARGETS)
rm -rf tests/ystests
- git clone https://github.com/YosysHQ/yosys-tests.git tests/ystests
- +PATH="$$PWD:$$PATH" cd tests/ystests && $(MAKE)
+ git clone -b yosys-0.9-rc https://github.com/YosysHQ/yosys-tests.git tests/ystests
+ +$(MAKE) PATH="$$PWD:$$PATH" -C tests/ystests
@echo ""
@echo " Finished \"make ystests\"."
@echo ""
@@ -620,8 +738,13 @@ 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) ldconfig
+ $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR)
+ $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
+ifeq ($(ENABLE_PYOSYS),1)
+ $(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys
+ $(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys/
+ $(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys/
+endif
endif
uninstall:
@@ -629,6 +752,11 @@ uninstall:
$(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR)
ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so
+ifeq ($(ENABLE_PYOSYS),1)
+ $(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/pyosys/libyosys.so
+ $(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/pyosys/__init__.py
+ $(INSTALL_SUDO) rmdir $(PYTHON_DESTDIR)/pyosys
+endif
endif
update-manual: $(TARGETS) $(EXTRA_TARGETS)
@@ -641,8 +769,9 @@ manual: $(TARGETS) $(EXTRA_TARGETS)
clean:
rm -rf share
+ rm -rf kernel/*.pyh
if test -d manual; then cd manual && sh clean.sh; fi
- rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS)
+ rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) $(PY_WRAP_INCLUDES) $(PY_WRAPPER_FILE).cc
rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a
rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d
rm -rf tests/asicworld/*.out tests/asicworld/*.log
@@ -652,6 +781,7 @@ clean:
rm -rf tests/sat/*.log tests/techmap/*.log tests/various/*.log
rm -rf tests/bram/temp tests/fsm/temp tests/realmath/temp tests/share/temp tests/smv/temp
rm -rf vloghtb/Makefile vloghtb/refdat vloghtb/rtl vloghtb/scripts vloghtb/spec vloghtb/check_yosys vloghtb/vloghammer_tb.tar.bz2 vloghtb/temp vloghtb/log_test_*
+ rm -f tests/svinterfaces/*.log_stdout tests/svinterfaces/*.log_stderr tests/svinterfaces/dut_result.txt tests/svinterfaces/reference_result.txt tests/svinterfaces/a.out tests/svinterfaces/*_syn.v tests/svinterfaces/*.diff
rm -f tests/tools/cmp_tbdata
clean-abc:
@@ -715,6 +845,9 @@ config-gcc-static: clean
config-gcc-4.8: clean
echo 'CONFIG := gcc-4.8' > Makefile.conf
+config-afl-gcc: clean
+ echo 'CONFIG := afl-gcc' > Makefile.conf
+
config-emcc: clean
echo 'CONFIG := emcc' > Makefile.conf
echo 'ENABLE_TCL := 0' >> Makefile.conf
@@ -728,9 +861,11 @@ config-mxe: clean
config-msys2: clean
echo 'CONFIG := msys2' > Makefile.conf
+ echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
config-msys2-64: clean
echo 'CONFIG := msys2-64' > Makefile.conf
+ echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
config-cygwin: clean
echo 'CONFIG := cygwin' > Makefile.conf
@@ -761,5 +896,5 @@ echo-git-rev:
-include techlibs/*/*.d
.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
+.PHONY: config-clean config-clang config-gcc config-gcc-static config-gcc-4.8 config-afl-gcc config-gprof config-sudo
diff --git a/README.md b/README.md
index 41ae4ac1..5132332a 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
```
yosys -- Yosys Open SYnthesis Suite
-Copyright (C) 2012 - 2017 Clifford Wolf <clifford@clifford.at>
+Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -34,11 +34,24 @@ compatible license that is similar in terms to the MIT license
or the 2-clause BSD license).
-Web Site
-========
+Web Site and Other Resources
+============================
More information and documentation can be found on the Yosys web site:
-http://www.clifford.at/yosys/
+- http://www.clifford.at/yosys/
+
+The "Documentation" page on the web site contains links to more resources,
+including a manual that even describes some of the Yosys internals:
+- http://www.clifford.at/yosys/documentation.html
+
+The file `CodingReadme` in this directory contains additional information
+for people interested in using the Yosys C++ APIs.
+
+Users interested in formal verification might want to use the formal verification
+front-end for Yosys, SymbiYosys:
+- https://symbiyosys.readthedocs.io/en/latest/
+- https://github.com/YosysHQ/SymbiYosys
+
Setup
======
@@ -53,25 +66,29 @@ prerequisites for building yosys:
$ sudo apt-get install build-essential clang bison flex \
libreadline-dev gawk tcl-dev libffi-dev git \
- graphviz xdot pkg-config python3
+ graphviz xdot pkg-config python3 libboost-system-dev \
+ libboost-python-dev libboost-filesystem-dev
-Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies:
+Similarily, on Mac OS X Homebrew can be used to install dependencies:
$ brew tap Homebrew/bundle && brew bundle
+
+or MacPorts:
+
$ sudo port install bison flex readline gawk libffi \
- git graphviz pkgconfig python36
+ git graphviz pkgconfig python36 boost tcl
On FreeBSD use the following command to install all prerequisites:
# pkg install bison flex readline gawk libffi\
- git graphviz pkgconfig python3 python36 tcl-wrapper
+ git graphviz pkgconfig python3 python36 tcl-wrapper boost-libs
On FreeBSD system use gmake instead of make. To run tests use:
% MAKE=gmake CC=cc gmake test
For Cygwin use the following command to install all prerequisites, or select these additional packages:
- setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel
+ setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build
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
@@ -92,12 +109,15 @@ Makefile.
To build Yosys simply type 'make' in this directory.
$ make
- $ make test
$ sudo make install
Note that this also downloads, builds and installs ABC (using yosys-abc
as executable name).
+Tests are located in the tests subdirectory and can be executed using the test target. Note that you need gawk as well as a recent version of iverilog (i.e. build from git). Then, execute tests via:
+
+ $ make test
+
Getting Started
===============
@@ -117,7 +137,7 @@ reading the design using the Verilog frontend:
yosys> read_verilog tests/simple/fiedler-cooley.v
-writing the design to the console in yosys's internal format:
+writing the design to the console in Yosys's internal format:
yosys> write_ilang
@@ -234,19 +254,15 @@ Unsupported Verilog-2005 Features
=================================
The following Verilog-2005 features are not supported by
-yosys and there are currently no plans to add support
+Yosys and there are currently no plans to add support
for them:
- Non-synthesizable language features as defined in
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
-- The ``tri``, ``triand``, ``trior``, ``wand`` and ``wor`` net types
-
-- The ``config`` keyword and library map files
+- The ``tri``, ``triand`` and ``trior`` net types
-- The ``disable``, ``primitive`` and ``specify`` statements
-
-- Latched logic (is synthesized as logic with feedback loops)
+- The ``config`` and ``disable`` keywords and library map files
Verilog Attributes and non-standard features
@@ -285,16 +301,34 @@ Verilog Attributes and non-standard features
storage element. The register itself will always have all bits set
to 'x' (undefined). The variable may only be used as blocking assigned
temporary variable within an always block. This is mostly used internally
- by yosys to synthesize Verilog functions and access arrays.
+ by Yosys to synthesize Verilog functions and access arrays.
-- The ``onehot`` attribute on wires mark them as onehot state register. This
+- The ``onehot`` attribute on wires mark them as one-hot state register. This
is used for example for memory port sharing and set by the fsm_map pass.
- The ``blackbox`` attribute on modules is used to mark empty stub modules
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.
+ also does not output blackbox modules on default. ``read_verilog``, unless
+ called with ``-noblackbox`` will automatically set the blackbox attribute
+ on any empty module it reads.
+
+- The ``noblackbox`` attribute set on an empty module prevents ``read_verilog``
+ from automatically setting the blackbox attribute on the module.
+
+- The ``whitebox`` attribute on modules triggers the same behavior as
+ ``blackbox``, but is for whitebox modules, i.e. library modules that
+ contain a behavioral model of the cell type.
+
+- The ``lib_whitebox`` attribute overwrites ``whitebox`` when ``read_verilog``
+ is run in `-lib` mode. Otherwise it's automatically removed.
+
+- The ``dynports`` attribute is used by the Verilog front-end to mark modules
+ that have ports with a width that depends on a parameter.
+
+- The ``hdlname`` attribute is used by some passes to document the original
+ (HDL) name of a module when renaming a module.
- The ``keep`` attribute on cells and wires is used to mark objects that should
never be removed by the optimizer. This is used for example for cells that
@@ -319,13 +353,21 @@ Verilog Attributes and non-standard features
through the synthesis. When entities are combined, a new |-separated
string is created that contains all the string from the original entities.
-- In addition to the ``(* ... *)`` attribute syntax, yosys supports
+- The ``defaultvalue`` attribute is used to store default values for
+ module inputs. The attribute is attached to the input wire by the HDL
+ front-end when the input is declared with a default value.
+
+- The ``parameter`` and ``localparam`` attributes are used to mark wires
+ that represent module parameters or localparams (when the HDL front-end
+ is run in -pwires mode).
+
+- In addition to the ``(* ... *)`` attribute syntax, Yosys supports
the non-standard ``{* ... *}`` attribute syntax to set default attributes
for everything that comes after the ``{* ... *}`` statement. (Reset
by adding an empty ``{* *}`` statement.)
- In module parameter and port declarations, and cell port and parameter
- lists, a trailing comma is ignored. This simplifies writing verilog code
+ lists, a trailing comma is ignored. This simplifies writing Verilog code
generators a bit in some cases.
- Modules can be declared with ``module mod_name(...);`` (with three dots
@@ -335,7 +377,7 @@ Verilog Attributes and non-standard features
- When defining a macro with `define, all text between triple double quotes
is interpreted as macro body, even if it contains unescaped newlines. The
- tipple double quotes are removed from the macro body. For example:
+ triple double quotes are removed from the macro body. For example:
`define MY_MACRO(a, b) """
assign a = 23;
@@ -382,12 +424,18 @@ 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
- expressions as <size>. If the expression is not a simple identifier, it
+ expressions as ``<size>``. If the expression is not a simple identifier, it
must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010``
-- 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.
+- The system tasks ``$finish``, ``$stop`` and ``$display`` are supported in
+ initial blocks in an unconditional context (only if/case statements on
+ expressions over parameters and constant values are allowed). The intended
+ use for this is synthesis-time DRC.
+
+- There is limited support for converting specify .. endspecify statements to
+ special ``$specify2``, ``$specify3``, and ``$specrule`` cells, for use in
+ blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this
+ functionality. (By default specify .. endspecify blocks are ignored.)
Non-standard or SystemVerilog features for formal verification
@@ -410,11 +458,11 @@ Non-standard or SystemVerilog features for formal verification
- The system functions ``$allconst`` and ``$allseq`` can be used to construct
formal exist-forall problems. Assumptions only hold if the trace satisfies
- the assumtion for all ``$allconst/$allseq`` values. For assertions and cover
+ the assumption for all ``$allconst/$allseq`` values. For assertions and cover
statements it is sufficient if just one ``$allconst/$allseq`` value triggers
the property (similar to ``$anyconst/$anyseq``).
-- Wires/registers decalred using the ``anyconst/anyseq/allconst/allseq`` attribute
+- Wires/registers declared using the ``anyconst/anyseq/allconst/allseq`` attribute
(for example ``(* anyconst *) reg [7:0] foobar;``) will behave as if driven
by a ``$anyconst/$anyseq/$allconst/$allseq`` function.
@@ -422,7 +470,7 @@ Non-standard or SystemVerilog features for formal verification
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
+ 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.
@@ -435,7 +483,7 @@ 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.
+ always block: ``assert(<expression>);``. It is transformed to an ``$assert`` cell.
- The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are
also supported. The same limitations as with the ``assert`` statement apply.
@@ -452,6 +500,9 @@ from SystemVerilog:
into a design with ``read_verilog``, all its packages are available to
SystemVerilog files being read into the same design afterwards.
+- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether
+ ports are inputs or outputs are supported.
+
Building the documentation
==========================
@@ -482,6 +533,6 @@ Then execute, from the root of the repository:
Notes:
-- To run `make manual` you need to have installed yosys with `make install`,
+- To run `make manual` you need to have installed Yosys with `make install`,
otherwise it will fail on finding `kernel/yosys.h` while building
`PRESENTATION_Prog`.
diff --git a/backends/aiger/aiger.cc b/backends/aiger/aiger.cc
index c323691a..6863b40f 100644
--- a/backends/aiger/aiger.cc
+++ b/backends/aiger/aiger.cc
@@ -89,7 +89,8 @@ struct AigerWriter
aig_map[bit] = mkgate(a0, a1);
} else
if (alias_map.count(bit)) {
- aig_map[bit] = bit2aig(alias_map.at(bit));
+ int a = bit2aig(alias_map.at(bit));
+ aig_map[bit] = a;
}
if (bit == State::Sx || bit == State::Sz)
@@ -100,7 +101,7 @@ struct AigerWriter
return aig_map.at(bit);
}
- AigerWriter(Module *module, bool zinit_mode) : module(module), zinit_mode(zinit_mode), sigmap(module)
+ AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode) : module(module), zinit_mode(zinit_mode), sigmap(module)
{
pool<SigBit> undriven_bits;
pool<SigBit> unused_bits;
@@ -293,6 +294,10 @@ struct AigerWriter
aig_map[bit] = 2*aig_m;
}
+ if (imode && input_bits.empty()) {
+ aig_m++, aig_i++;
+ }
+
if (zinit_mode)
{
for (auto it : ff_map) {
@@ -371,6 +376,11 @@ struct AigerWriter
aig_outputs.push_back(bit2aig(bit));
}
+ if (omode && output_bits.empty()) {
+ aig_o++;
+ aig_outputs.push_back(0);
+ }
+
for (auto it : asserts) {
aig_b++;
int bit_a = bit2aig(it.first);
@@ -378,6 +388,11 @@ struct AigerWriter
aig_outputs.push_back(mkgate(bit_a^1, bit_en));
}
+ if (bmode && asserts.empty()) {
+ aig_b++;
+ aig_outputs.push_back(0);
+ }
+
for (auto it : assumes) {
aig_c++;
int bit_a = bit2aig(it.first);
@@ -689,6 +704,11 @@ struct AigerBackend : public Backend {
log(" -vmap <filename>\n");
log(" like -map, but more verbose\n");
log("\n");
+ log(" -I, -O, -B\n");
+ log(" If the design contains no input/output/assert then create one\n");
+ log(" dummy input/output/bad_state pin to make the tools reading the\n");
+ log(" AIGER file happy.\n");
+ log("\n");
}
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
@@ -697,6 +717,9 @@ struct AigerBackend : public Backend {
bool miter_mode = false;
bool symbols_mode = false;
bool verbose_map = false;
+ bool imode = false;
+ bool omode = false;
+ bool bmode = false;
std::string map_filename;
log_header(design, "Executing AIGER backend.\n");
@@ -729,6 +752,18 @@ struct AigerBackend : public Backend {
verbose_map = true;
continue;
}
+ if (args[argidx] == "-I") {
+ imode = true;
+ continue;
+ }
+ if (args[argidx] == "-O") {
+ omode = true;
+ continue;
+ }
+ if (args[argidx] == "-B") {
+ bmode = true;
+ continue;
+ }
break;
}
extra_args(f, filename, args, argidx);
@@ -738,10 +773,11 @@ struct AigerBackend : public Backend {
if (top_module == nullptr)
log_error("Can't find top module in current design!\n");
- AigerWriter writer(top_module, zinit_mode);
+ AigerWriter writer(top_module, zinit_mode, imode, omode, bmode);
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
if (!map_filename.empty()) {
+ rewrite_filename(filename);
std::ofstream mapf;
mapf.open(map_filename.c_str(), std::ofstream::trunc);
if (mapf.fail())
diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc
index 0db5ff27..a1761b66 100644
--- a/backends/blif/blif.cc
+++ b/backends/blif/blif.cc
@@ -140,7 +140,7 @@ struct BlifDumper
return "subckt";
if (!design->modules_.count(RTLIL::escape_id(cell_type)))
return "gate";
- if (design->modules_.at(RTLIL::escape_id(cell_type))->get_bool_attribute("\\blackbox"))
+ if (design->modules_.at(RTLIL::escape_id(cell_type))->get_blackbox_attribute())
return "gate";
return "subckt";
}
@@ -196,7 +196,7 @@ struct BlifDumper
}
f << stringf("\n");
- if (module->get_bool_attribute("\\blackbox")) {
+ if (module->get_blackbox_attribute()) {
f << stringf(".blackbox\n");
f << stringf(".end\n");
return;
@@ -409,12 +409,26 @@ struct BlifDumper
f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type));
for (auto &conn : cell->connections())
- for (int i = 0; i < conn.second.size(); i++) {
- if (conn.second.size() == 1)
- f << stringf(" %s", cstr(conn.first));
- else
- f << stringf(" %s[%d]", cstr(conn.first), i);
- f << stringf("=%s", cstr(conn.second.extract(i, 1)));
+ {
+ if (conn.second.size() == 1) {
+ f << stringf(" %s=%s", cstr(conn.first), cstr(conn.second[0]));
+ continue;
+ }
+
+ Module *m = design->module(cell->type);
+ Wire *w = m ? m->wire(conn.first) : nullptr;
+
+ if (w == nullptr) {
+ for (int i = 0; i < GetSize(conn.second); i++)
+ f << stringf(" %s[%d]=%s", cstr(conn.first), i, cstr(conn.second[i]));
+ } else {
+ for (int i = 0; i < std::min(GetSize(conn.second), GetSize(w)); i++) {
+ SigBit sig(w, i);
+ f << stringf(" %s[%d]=%s", cstr(conn.first), sig.wire->upto ?
+ sig.wire->start_offset+sig.wire->width-sig.offset-1 :
+ sig.wire->start_offset+sig.offset, cstr(conn.second[i]));
+ }
+ }
}
f << stringf("\n");
@@ -640,7 +654,7 @@ struct BlifBackend : public Backend {
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
- if (module->get_bool_attribute("\\blackbox") && !config.blackbox_mode)
+ if (module->get_blackbox_attribute() && !config.blackbox_mode)
continue;
if (module->processes.size() != 0)
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index 58d2a862..a507b120 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -17,6 +17,11 @@
*
*/
+// [[CITE]] Btor2 , BtorMC and Boolector 3.0
+// Aina Niemetz, Mathias Preiner, Clifford Wolf, Armin Biere
+// Computer Aided Verification - 30th International Conference, CAV 2018
+// https://cs.stanford.edu/people/niemetz/publication/2018/niemetzpreinerwolfbiere-cav18/
+
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
@@ -129,16 +134,23 @@ struct BtorWorker
void export_cell(Cell *cell)
{
- log_assert(cell_recursion_guard.count(cell) == 0);
+ if (cell_recursion_guard.count(cell)) {
+ string cell_list;
+ for (auto c : cell_recursion_guard)
+ cell_list += stringf("\n %s", log_id(c));
+ log_error("Found topological loop while processing cell %s. Active cells:%s\n", log_id(cell), cell_list.c_str());
+ }
+
cell_recursion_guard.insert(cell);
btorf_push(log_id(cell));
- if (cell->type.in("$add", "$sub", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx",
- "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
+ if (cell->type.in("$add", "$sub", "$mul", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx",
+ "$concat", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
{
string btor_op;
if (cell->type == "$add") btor_op = "add";
if (cell->type == "$sub") btor_op = "sub";
+ if (cell->type == "$mul") btor_op = "mul";
if (cell->type.in("$shl", "$sshl")) btor_op = "sll";
if (cell->type == "$shr") btor_op = "srl";
if (cell->type == "$sshr") btor_op = "sra";
@@ -146,6 +158,7 @@ struct BtorWorker
if (cell->type.in("$and", "$_AND_")) btor_op = "and";
if (cell->type.in("$or", "$_OR_")) btor_op = "or";
if (cell->type.in("$xor", "$_XOR_")) btor_op = "xor";
+ if (cell->type == "$concat") btor_op = "concat";
if (cell->type == "$_NAND_") btor_op = "nand";
if (cell->type == "$_NOR_") btor_op = "nor";
if (cell->type.in("$xnor", "$_XNOR_")) btor_op = "xnor";
@@ -214,6 +227,40 @@ struct BtorWorker
goto okay;
}
+ if (cell->type.in("$div", "$mod"))
+ {
+ string btor_op;
+ if (cell->type == "$div") btor_op = "div";
+ if (cell->type == "$mod") btor_op = "rem";
+ log_assert(!btor_op.empty());
+
+ int width = GetSize(cell->getPort("\\Y"));
+ width = std::max(width, GetSize(cell->getPort("\\A")));
+ width = std::max(width, GetSize(cell->getPort("\\B")));
+
+ bool a_signed = cell->hasParam("\\A_SIGNED") ? cell->getParam("\\A_SIGNED").as_bool() : false;
+ bool b_signed = cell->hasParam("\\B_SIGNED") ? cell->getParam("\\B_SIGNED").as_bool() : false;
+
+ int nid_a = get_sig_nid(cell->getPort("\\A"), width, a_signed);
+ int nid_b = get_sig_nid(cell->getPort("\\B"), width, b_signed);
+
+ int sid = get_bv_sid(width);
+ int nid = next_nid++;
+ btorf("%d %c%s %d %d %d\n", nid, a_signed || b_signed ? 's' : 'u', btor_op.c_str(), sid, nid_a, nid_b);
+
+ SigSpec sig = sigmap(cell->getPort("\\Y"));
+
+ if (GetSize(sig) < width) {
+ int sid = get_bv_sid(GetSize(sig));
+ int nid2 = next_nid++;
+ btorf("%d slice %d %d %d 0\n", nid2, sid, nid, GetSize(sig)-1);
+ nid = nid2;
+ }
+
+ add_nid_sig(nid, sig);
+ goto okay;
+ }
+
if (cell->type.in("$_ANDNOT_", "$_ORNOT_"))
{
int sid = get_bv_sid(1);
@@ -304,7 +351,7 @@ struct BtorWorker
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.in("$ne", "$nex")) btor_op = "neq";
if (cell->type == "$ge") btor_op = "gte";
if (cell->type == "$gt") btor_op = "gt";
log_assert(!btor_op.empty());
@@ -506,6 +553,18 @@ struct BtorWorker
}
}
+ Const initval;
+ for (int i = 0; i < GetSize(sig_q); i++)
+ if (initbits.count(sig_q[i]))
+ initval.bits.push_back(initbits.at(sig_q[i]) ? State::S1 : State::S0);
+ else
+ initval.bits.push_back(State::Sx);
+
+ int nid_init_val = -1;
+
+ if (!initval.is_fully_undef())
+ nid_init_val = get_sig_nid(initval);
+
int sid = get_bv_sid(GetSize(sig_q));
int nid = next_nid++;
@@ -514,15 +573,7 @@ struct BtorWorker
else
btorf("%d state %d %s\n", nid, sid, log_id(symbol));
- Const initval;
- for (int i = 0; i < GetSize(sig_q); i++)
- if (initbits.count(sig_q[i]))
- initval.bits.push_back(initbits.at(sig_q[i]) ? State::S1 : State::S0);
- else
- initval.bits.push_back(State::Sx);
-
- if (!initval.is_fully_undef()) {
- int nid_init_val = get_sig_nid(initval);
+ if (nid_init_val >= 0) {
int nid_init = next_nid++;
if (verbose)
btorf("; initval = %s\n", log_signal(initval));
@@ -575,6 +626,7 @@ struct BtorWorker
{
int abits = cell->getParam("\\ABITS").as_int();
int width = cell->getParam("\\WIDTH").as_int();
+ int nwords = cell->getParam("\\SIZE").as_int();
int rdports = cell->getParam("\\RD_PORTS").as_int();
int wrports = cell->getParam("\\WR_PORTS").as_int();
@@ -601,6 +653,52 @@ struct BtorWorker
int data_sid = get_bv_sid(width);
int bool_sid = get_bv_sid(1);
int sid = get_mem_sid(abits, width);
+
+ Const initdata = cell->getParam("\\INIT");
+ initdata.exts(nwords*width);
+ int nid_init_val = -1;
+
+ if (!initdata.is_fully_undef())
+ {
+ bool constword = true;
+ Const firstword = initdata.extract(0, width);
+
+ for (int i = 1; i < nwords; i++) {
+ Const thisword = initdata.extract(i*width, width);
+ if (thisword != firstword) {
+ constword = false;
+ break;
+ }
+ }
+
+ if (constword)
+ {
+ if (verbose)
+ btorf("; initval = %s\n", log_signal(firstword));
+ nid_init_val = get_sig_nid(firstword);
+ }
+ else
+ {
+ int nid_init_val = next_nid++;
+ btorf("%d state %d\n", nid_init_val, sid);
+
+ for (int i = 0; i < nwords; i++) {
+ Const thisword = initdata.extract(i*width, width);
+ if (thisword.is_fully_undef())
+ continue;
+ Const thisaddr(i, abits);
+ int nid_thisword = get_sig_nid(thisword);
+ int nid_thisaddr = get_sig_nid(thisaddr);
+ int last_nid_init_val = nid_init_val;
+ nid_init_val = next_nid++;
+ if (verbose)
+ btorf("; initval[%d] = %s\n", i, log_signal(thisword));
+ btorf("%d write %d %d %d %d\n", nid_init_val, sid, last_nid_init_val, nid_thisaddr, nid_thisword);
+ }
+ }
+ }
+
+
int nid = next_nid++;
int nid_head = nid;
@@ -609,6 +707,12 @@ struct BtorWorker
else
btorf("%d state %d %s\n", nid, sid, log_id(cell));
+ if (nid_init_val >= 0)
+ {
+ int nid_init = next_nid++;
+ btorf("%d init %d %d %d\n", nid_init, sid, nid, nid_init_val);
+ }
+
if (asyncwr)
{
for (int port = 0; port < wrports; port++)
@@ -776,9 +880,28 @@ struct BtorWorker
else
{
if (bit_cell.count(bit) == 0)
- log_error("No driver for signal bit %s.\n", log_signal(bit));
- export_cell(bit_cell.at(bit));
- log_assert(bit_nid.count(bit));
+ {
+ SigSpec s = bit;
+
+ while (i+GetSize(s) < GetSize(sig) && sig[i+GetSize(s)].wire != nullptr &&
+ bit_cell.count(sig[i+GetSize(s)]) == 0)
+ s.append(sig[i+GetSize(s)]);
+
+ log_warning("No driver for signal %s.\n", log_signal(s));
+
+ int sid = get_bv_sid(GetSize(s));
+ int nid = next_nid++;
+ btorf("%d input %d %s\n", nid, sid);
+ nid_width[nid] = GetSize(s);
+
+ i += GetSize(s)-1;
+ continue;
+ }
+ else
+ {
+ export_cell(bit_cell.at(bit));
+ log_assert(bit_nid.count(bit));
+ }
}
}
@@ -892,9 +1015,8 @@ struct BtorWorker
btorf_push(stringf("output %s", log_id(wire)));
- int sid = get_bv_sid(GetSize(wire));
int nid = get_sig_nid(wire);
- btorf("%d output %d %d %s\n", next_nid++, sid, nid, log_id(wire));
+ btorf("%d output %d %s\n", next_nid++, nid, log_id(wire));
btorf_pop(stringf("output %s", log_id(wire)));
}
diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc
index 5f9ec54f..6d946953 100644
--- a/backends/edif/edif.cc
+++ b/backends/edif/edif.cc
@@ -106,6 +106,13 @@ struct EdifBackend : public Backend {
log(" if the design contains constant nets. use \"hilomap\" to map to custom\n");
log(" constant drivers first)\n");
log("\n");
+ log(" -gndvccy\n");
+ log(" create \"GND\" and \"VCC\" cells with \"Y\" outputs. (the default is \"G\"\n");
+ log(" for \"GND\" and \"P\" for \"VCC\".)\n");
+ log("\n");
+ log(" -attrprop\n");
+ log(" create EDIF properties for cell attributes\n");
+ log("\n");
log(" -pvector {par|bra|ang}\n");
log(" sets the delimiting character for module port rename clauses to\n");
log(" parentheses, square brackets, or angle brackets.\n");
@@ -121,8 +128,9 @@ struct EdifBackend : public Backend {
log_header(design, "Executing EDIF backend.\n");
std::string top_module_name;
bool port_rename = false;
+ bool attr_properties = false;
std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
- bool nogndvcc = false;
+ bool nogndvcc = false, gndvccy = false;
CellTypes ct(design);
EdifNames edif_names;
@@ -137,6 +145,14 @@ struct EdifBackend : public Backend {
nogndvcc = true;
continue;
}
+ if (args[argidx] == "-gndvccy") {
+ gndvccy = true;
+ continue;
+ }
+ if (args[argidx] == "-attrprop") {
+ attr_properties = true;
+ continue;
+ }
if (args[argidx] == "-pvector" && argidx+1 < args.size()) {
std::string parray;
port_rename = true;
@@ -162,7 +178,7 @@ struct EdifBackend : public Backend {
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
- if (module->get_bool_attribute("\\blackbox"))
+ if (module->get_blackbox_attribute())
continue;
if (top_module_name.empty())
@@ -176,7 +192,7 @@ struct EdifBackend : public Backend {
for (auto cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
- if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
+ if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_blackbox_attribute()) {
lib_cell_ports[cell->type];
for (auto p : cell->connections())
lib_cell_ports[cell->type][p.first] = GetSize(p.second);
@@ -203,7 +219,7 @@ struct EdifBackend : public Backend {
*f << stringf(" (cellType GENERIC)\n");
*f << stringf(" (view VIEW_NETLIST\n");
*f << stringf(" (viewType NETLIST)\n");
- *f << stringf(" (interface (port G (direction OUTPUT)))\n");
+ *f << stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy ? 'Y' : 'G');
*f << stringf(" )\n");
*f << stringf(" )\n");
@@ -211,7 +227,7 @@ struct EdifBackend : public Backend {
*f << stringf(" (cellType GENERIC)\n");
*f << stringf(" (view VIEW_NETLIST\n");
*f << stringf(" (viewType NETLIST)\n");
- *f << stringf(" (interface (port P (direction OUTPUT)))\n");
+ *f << stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy ? 'Y' : 'P');
*f << stringf(" )\n");
*f << stringf(" )\n");
}
@@ -286,7 +302,7 @@ struct EdifBackend : public Backend {
*f << stringf(" (technology (numberDefinition))\n");
for (auto module : sorted_modules)
{
- if (module->get_bool_attribute("\\blackbox"))
+ if (module->get_blackbox_attribute())
continue;
SigMap sigmap(module);
@@ -332,24 +348,33 @@ struct EdifBackend : public Backend {
*f << stringf(" (instance %s\n", EDIF_DEF(cell->name));
*f << stringf(" (viewRef VIEW_NETLIST (cellRef %s%s))", EDIF_REF(cell->type),
lib_cell_ports.count(cell->type) > 0 ? " (libraryRef LIB)" : "");
- for (auto &p : cell->parameters)
- if ((p.second.flags & RTLIL::CONST_FLAG_STRING) != 0)
- *f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(p.first), p.second.decode_string().c_str());
- else if (p.second.bits.size() <= 32 && RTLIL::SigSpec(p.second).is_fully_def())
- *f << stringf("\n (property %s (integer %u))", EDIF_DEF(p.first), p.second.as_int());
+
+ auto add_prop = [&](IdString name, Const val) {
+ if ((val.flags & RTLIL::CONST_FLAG_STRING) != 0)
+ *f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(name), val.decode_string().c_str());
+ else if (val.bits.size() <= 32 && RTLIL::SigSpec(val).is_fully_def())
+ *f << stringf("\n (property %s (integer %u))", EDIF_DEF(name), val.as_int());
else {
std::string hex_string = "";
- for (size_t i = 0; i < p.second.bits.size(); i += 4) {
+ for (size_t i = 0; i < val.bits.size(); i += 4) {
int digit_value = 0;
- if (i+0 < p.second.bits.size() && p.second.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1;
- if (i+1 < p.second.bits.size() && p.second.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2;
- if (i+2 < p.second.bits.size() && p.second.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4;
- if (i+3 < p.second.bits.size() && p.second.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8;
+ if (i+0 < val.bits.size() && val.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1;
+ if (i+1 < val.bits.size() && val.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2;
+ if (i+2 < val.bits.size() && val.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4;
+ if (i+3 < val.bits.size() && val.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8;
char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
hex_string = std::string(digit_str) + hex_string;
}
- *f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(p.first), GetSize(p.second.bits), hex_string.c_str());
+ *f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(name), GetSize(val.bits), hex_string.c_str());
}
+ };
+
+ for (auto &p : cell->parameters)
+ add_prop(p.first, p.second);
+ if (attr_properties)
+ for (auto &p : cell->attributes)
+ add_prop(p.first, p.second);
+
*f << stringf(")\n");
for (auto &p : cell->connections()) {
RTLIL::SigSpec sig = sigmap(p.second);
@@ -403,9 +428,9 @@ struct EdifBackend : public Backend {
if (nogndvcc)
log_error("Design contains constant nodes (map with \"hilomap\" first).\n");
if (sig == RTLIL::State::S0)
- *f << stringf(" (portRef G (instanceRef GND))\n");
+ *f << stringf(" (portRef %c (instanceRef GND))\n", gndvccy ? 'Y' : 'G');
if (sig == RTLIL::State::S1)
- *f << stringf(" (portRef P (instanceRef VCC))\n");
+ *f << stringf(" (portRef %c (instanceRef VCC))\n", gndvccy ? 'Y' : 'P');
}
*f << stringf(" ))\n");
}
diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc
index 32410a65..1c7a7351 100644
--- a/backends/firrtl/firrtl.cc
+++ b/backends/firrtl/firrtl.cc
@@ -23,7 +23,11 @@
#include "kernel/celltypes.h"
#include "kernel/cellaigs.h"
#include "kernel/log.h"
+#include <algorithm>
#include <string>
+#include <regex>
+#include <vector>
+#include <cmath>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -37,6 +41,7 @@ static const FDirection FD_NODIRECTION = 0x0;
static const FDirection FD_IN = 0x1;
static const FDirection FD_OUT = 0x2;
static const FDirection FD_INOUT = 0x3;
+static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width
// Get a port direction with respect to a specific module.
FDirection getPortFDirection(IdString id, Module *module)
@@ -101,6 +106,125 @@ struct FirrtlWorker
RTLIL::Design *design;
std::string indent;
+ // Define read/write ports and memories.
+ // We'll collect their definitions and emit the corresponding FIRRTL definitions at the appropriate point in module construction.
+ // For the moment, we don't handle $readmemh or $readmemb.
+ // These will be part of a subsequent PR.
+ struct read_port {
+ string name;
+ bool clk_enable;
+ bool clk_parity;
+ bool transparent;
+ RTLIL::SigSpec clk;
+ RTLIL::SigSpec ena;
+ RTLIL::SigSpec addr;
+ read_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr) : name(name), clk_enable(clk_enable), clk_parity(clk_parity), transparent(transparent), clk(clk), ena(ena), addr(addr) {
+ // Current (3/13/2019) conventions:
+ // generate a constant 0 for clock and a constant 1 for enable if they are undefined.
+ if (!clk.is_fully_def())
+ this->clk = SigSpec(RTLIL::Const(0, 1));
+ if (!ena.is_fully_def())
+ this->ena = SigSpec(RTLIL::Const(1, 1));
+ }
+ string gen_read(const char * indent) {
+ string addr_expr = make_expr(addr);
+ string ena_expr = make_expr(ena);
+ string clk_expr = make_expr(clk);
+ string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str());
+ string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str());
+ string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str());
+ return addr_str + ena_str + clk_str;
+ }
+ };
+ struct write_port : read_port {
+ RTLIL::SigSpec mask;
+ write_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr, RTLIL::SigSpec mask) : read_port(name, clk_enable, clk_parity, transparent, clk, ena, addr), mask(mask) {
+ if (!clk.is_fully_def())
+ this->clk = SigSpec(RTLIL::Const(0));
+ if (!ena.is_fully_def())
+ this->ena = SigSpec(RTLIL::Const(0));
+ if (!mask.is_fully_def())
+ this->ena = SigSpec(RTLIL::Const(1));
+ }
+ string gen_read(const char * /* indent */) {
+ log_error("gen_read called on write_port: %s\n", name.c_str());
+ return stringf("gen_read called on write_port: %s\n", name.c_str());
+ }
+ string gen_write(const char * indent) {
+ string addr_expr = make_expr(addr);
+ string ena_expr = make_expr(ena);
+ string clk_expr = make_expr(clk);
+ string mask_expr = make_expr(mask);
+ string mask_str = stringf("%s%s.mask <= %s\n", indent, name.c_str(), mask_expr.c_str());
+ string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str());
+ string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str());
+ string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str());
+ return addr_str + ena_str + clk_str + mask_str;
+ }
+ };
+ /* Memories defined within this module. */
+ struct memory {
+ Cell *pCell; // for error reporting
+ string name; // memory name
+ int abits; // number of address bits
+ int size; // size (in units) of the memory
+ int width; // size (in bits) of each element
+ int read_latency;
+ int write_latency;
+ vector<read_port> read_ports;
+ vector<write_port> write_ports;
+ std::string init_file;
+ std::string init_file_srcFileSpec;
+ string srcLine;
+ memory(Cell *pCell, string name, int abits, int size, int width) : pCell(pCell), name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {
+ // Provide defaults for abits or size if one (but not the other) is specified.
+ if (this->abits == 0 && this->size != 0) {
+ this->abits = ceil_log2(this->size);
+ } else if (this->abits != 0 && this->size == 0) {
+ this->size = 1 << this->abits;
+ }
+ // Sanity-check this construction.
+ if (this->name == "") {
+ log_error("Nameless memory%s\n", this->atLine());
+ }
+ if (this->abits == 0 && this->size == 0) {
+ log_error("Memory %s has zero address bits and size%s\n", this->name.c_str(), this->atLine());
+ }
+ if (this->width == 0) {
+ log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine());
+ }
+ }
+ // We need a default constructor for the dict insert.
+ memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
+
+ const char *atLine() {
+ if (srcLine == "") {
+ if (pCell) {
+ auto p = pCell->attributes.find("\\src");
+ srcLine = " at " + p->second.decode_string();
+ }
+ }
+ return srcLine.c_str();
+ }
+ void add_memory_read_port(read_port &rp) {
+ read_ports.push_back(rp);
+ }
+ void add_memory_write_port(write_port &wp) {
+ write_ports.push_back(wp);
+ }
+ void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) {
+ this->init_file = init_file;
+ this->init_file_srcFileSpec = init_file_srcFileSpec;
+ }
+
+ };
+ dict<string, memory> memories;
+
+ void register_memory(memory &m)
+ {
+ memories[m.name] = m;
+ }
+
void register_reverse_wire_map(string id, SigSpec sig)
{
for (int i = 0; i < GetSize(sig); i++)
@@ -111,7 +235,7 @@ struct FirrtlWorker
{
}
- string make_expr(const SigSpec &sig)
+ static string make_expr(const SigSpec &sig)
{
string expr;
@@ -160,11 +284,9 @@ struct FirrtlWorker
std::string fid(RTLIL::IdString internal_id)
{
- const char *str = internal_id.c_str();
- return *str == '\\' ? str + 1 : str;
+ return make_id(internal_id);
}
-
std::string cellname(RTLIL::Cell *cell)
{
return fid(cell->name).c_str();
@@ -173,6 +295,26 @@ struct FirrtlWorker
void process_instance(RTLIL::Cell *cell, vector<string> &wire_exprs)
{
std::string cell_type = fid(cell->type);
+ std::string instanceOf;
+ // If this is a parameterized module, its parent module is encoded in the cell type
+ if (cell->type.substr(0, 8) == "$paramod")
+ {
+ std::string::iterator it;
+ for (it = cell_type.begin(); it < cell_type.end(); it++)
+ {
+ switch (*it) {
+ case '\\': /* FALL_THROUGH */
+ case '=': /* FALL_THROUGH */
+ case '\'': /* FALL_THROUGH */
+ case '$': instanceOf.append("_"); break;
+ default: instanceOf.append(1, *it); break;
+ }
+ }
+ }
+ else
+ {
+ instanceOf = cell_type;
+ }
std::string cell_name = cellname(cell);
std::string cell_name_comment;
@@ -182,41 +324,75 @@ struct FirrtlWorker
cell_name_comment = "";
// Find the module corresponding to this instance.
auto instModule = design->module(cell->type);
- wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), cell_type.c_str()));
+ // If there is no instance for this, just return.
+ if (instModule == NULL)
+ {
+ log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str());
+ return;
+ }
+ wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str()));
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
if (it->second.size() > 0) {
const SigSpec &secondSig = it->second;
const std::string firstName = cell_name + "." + make_id(it->first);
- const std::string secondName = make_expr(secondSig);
+ const std::string secondExpr = make_expr(secondSig);
// Find the direction for this port.
FDirection dir = getPortFDirection(it->first, instModule);
- std::string source, sink;
+ std::string sourceExpr, sinkExpr;
+ const SigSpec *sinkSig = nullptr;
switch (dir) {
case FD_INOUT:
- log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", log_id(cell_type), log_signal(it->second));
+ log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
+ /* FALLTHRU */
case FD_OUT:
- source = firstName;
- sink = secondName;
+ sourceExpr = firstName;
+ sinkExpr = secondExpr;
+ sinkSig = &secondSig;
break;
case FD_NODIRECTION:
- log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", log_id(cell_type), log_signal(it->second));
- /* FALL_THROUGH */
+ log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
+ /* FALLTHRU */
case FD_IN:
- source = secondName;
- sink = firstName;
+ sourceExpr = secondExpr;
+ sinkExpr = firstName;
break;
default:
- log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", log_id(cell_type), log_signal(it->second), dir);
+ log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir);
break;
}
- wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sink.c_str(), source.c_str()));
+ // Check for subfield assignment.
+ std::string bitsString = "bits(";
+ if (sinkExpr.substr(0, bitsString.length()) == bitsString ) {
+ if (sinkSig == nullptr)
+ log_error("Unknown subfield %s.%s\n", cell_type.c_str(), sinkExpr.c_str());
+ // Don't generate the assignment here.
+ // Add the source and sink to the "reverse_wire_map" and we'll output the assignment
+ // as part of the coalesced subfield assignments for this wire.
+ register_reverse_wire_map(sourceExpr, *sinkSig);
+ } else {
+ wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str()));
+ }
}
}
wire_exprs.push_back(stringf("\n"));
}
+ // Given an expression for a shift amount, and a maximum width,
+ // generate the FIRRTL expression for equivalent dynamic shift taking into account FIRRTL shift semantics.
+ std::string gen_dshl(const string b_expr, const int b_padded_width)
+ {
+ string result = b_expr;
+ if (b_padded_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) {
+ int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1;
+ string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1);
+ // Deal with the difference in semantics between FIRRTL and verilog
+ result = stringf("mux(gt(%s, %s), %s, bits(%s, %d, 0))", b_expr.c_str(), max_shift_string.c_str(), max_shift_string.c_str(), b_expr.c_str(), max_shift_width_bits - 1);
+ }
+ return result;
+ }
+
void run()
{
f << stringf(" module %s:\n", make_id(module->name));
@@ -225,6 +401,12 @@ struct FirrtlWorker
for (auto wire : module->wires())
{
const auto wireName = make_id(wire->name);
+ // If a wire has initial data, issue a warning since FIRRTL doesn't currently support it.
+ if (wire->attributes.count("\\init")) {
+ log_warning("Initial value (%s) for (%s.%s) not supported\n",
+ wire->attributes.at("\\init").as_string().c_str(),
+ log_id(module), log_id(wire));
+ }
if (wire->port_id)
{
if (wire->port_input && wire->port_output)
@@ -240,7 +422,8 @@ struct FirrtlWorker
for (auto cell : module->cells())
{
- // Is this cell is a module instance?
+ bool extract_y_bits = false; // Assume no extraction of final bits will be required.
+ // Is this cell is a module instance?
if (cell->type[0] != '$')
{
process_instance(cell, wire_exprs);
@@ -264,21 +447,23 @@ struct FirrtlWorker
}
string primop;
- bool always_uint = false;
+ bool always_uint = false;
if (cell->type == "$not") primop = "not";
- if (cell->type == "$neg") primop = "neg";
- if (cell->type == "$logic_not") {
+ else if (cell->type == "$neg") {
+ primop = "neg";
+ is_signed = true; // Result of "neg" is signed (an SInt).
+ } else if (cell->type == "$logic_not") {
primop = "eq";
a_expr = stringf("%s, UInt(0)", a_expr.c_str());
}
- if (cell->type == "$reduce_and") primop = "andr";
- if (cell->type == "$reduce_or") primop = "orr";
- if (cell->type == "$reduce_xor") primop = "xorr";
- if (cell->type == "$reduce_xnor") {
+ else if (cell->type == "$reduce_and") primop = "andr";
+ else if (cell->type == "$reduce_or") primop = "orr";
+ else if (cell->type == "$reduce_xor") primop = "xorr";
+ else if (cell->type == "$reduce_xnor") {
primop = "not";
a_expr = stringf("xorr(%s)", a_expr.c_str());
}
- if (cell->type == "$reduce_bool") {
+ else if (cell->type == "$reduce_bool") {
primop = "neq";
// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool();
@@ -297,14 +482,15 @@ struct FirrtlWorker
continue;
}
if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx",
- "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
- "$logic_and", "$logic_or"))
+ "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
+ "$logic_and", "$logic_or"))
{
string y_id = make_id(cell->name);
bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
string a_expr = make_expr(cell->getPort("\\A"));
string b_expr = make_expr(cell->getPort("\\B"));
+ int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int();
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
if (cell->parameters.at("\\A_SIGNED").as_bool()) {
@@ -315,67 +501,95 @@ struct FirrtlWorker
if (cell->parameters.at("\\B_SIGNED").as_bool()) {
b_expr = "asSInt(" + b_expr + ")";
}
- b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
+ if (b_padded_width < y_width) {
+ auto b_sig = cell->getPort("\\B");
+ b_padded_width = y_width;
+ }
}
- a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
+ auto a_sig = cell->getPort("\\A");
if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type == "$shr")) {
a_expr = "asUInt(" + a_expr + ")";
}
string primop;
- bool always_uint = false;
+ bool always_uint = false;
if (cell->type == "$add") primop = "add";
- if (cell->type == "$sub") primop = "sub";
- if (cell->type == "$mul") primop = "mul";
- if (cell->type == "$div") primop = "div";
- if (cell->type == "$mod") primop = "rem";
- if (cell->type == "$and") {
+ else if (cell->type == "$sub") primop = "sub";
+ else if (cell->type == "$mul") primop = "mul";
+ else if (cell->type == "$div") primop = "div";
+ else if (cell->type == "$mod") primop = "rem";
+ else if (cell->type == "$and") {
primop = "and";
always_uint = true;
}
- if (cell->type == "$or" ) {
+ else if (cell->type == "$or" ) {
primop = "or";
always_uint = true;
}
- if (cell->type == "$xor") {
+ else if (cell->type == "$xor") {
primop = "xor";
always_uint = true;
}
- if ((cell->type == "$eq") | (cell->type == "$eqx")) {
+ else if ((cell->type == "$eq") | (cell->type == "$eqx")) {
primop = "eq";
always_uint = true;
}
- if ((cell->type == "$ne") | (cell->type == "$nex")) {
+ else if ((cell->type == "$ne") | (cell->type == "$nex")) {
primop = "neq";
always_uint = true;
}
- if (cell->type == "$gt") {
+ else if (cell->type == "$gt") {
primop = "gt";
always_uint = true;
}
- if (cell->type == "$ge") {
+ else if (cell->type == "$ge") {
primop = "geq";
always_uint = true;
}
- if (cell->type == "$lt") {
+ else if (cell->type == "$lt") {
primop = "lt";
always_uint = true;
}
- if (cell->type == "$le") {
+ else if (cell->type == "$le") {
primop = "leq";
always_uint = true;
}
- if ((cell->type == "$shl") | (cell->type == "$sshl")) primop = "dshl";
- if ((cell->type == "$shr") | (cell->type == "$sshr")) primop = "dshr";
- if ((cell->type == "$logic_and")) {
+ else if ((cell->type == "$shl") | (cell->type == "$sshl")) {
+ // FIRRTL will widen the result (y) by the amount of the shift.
+ // We'll need to offset this by extracting the un-widened portion as Verilog would do.
+ extract_y_bits = true;
+ // Is the shift amount constant?
+ auto b_sig = cell->getPort("\\B");
+ if (b_sig.is_fully_const()) {
+ primop = "shl";
+ b_expr = std::to_string(b_sig.as_int());
+ } else {
+ primop = "dshl";
+ // Convert from FIRRTL left shift semantics.
+ b_expr = gen_dshl(b_expr, b_padded_width);
+ }
+ }
+ else if ((cell->type == "$shr") | (cell->type == "$sshr")) {
+ // We don't need to extract a specific range of bits.
+ extract_y_bits = false;
+ // Is the shift amount constant?
+ auto b_sig = cell->getPort("\\B");
+ if (b_sig.is_fully_const()) {
+ primop = "shr";
+ b_expr = std::to_string(b_sig.as_int());
+ } else {
+ primop = "dshr";
+ }
+ }
+ else if ((cell->type == "$logic_and")) {
primop = "and";
a_expr = "neq(" + a_expr + ", UInt(0))";
b_expr = "neq(" + b_expr + ", UInt(0))";
always_uint = true;
}
- if ((cell->type == "$logic_or")) {
+ else if ((cell->type == "$logic_or")) {
primop = "or";
a_expr = "neq(" + a_expr + ", UInt(0))";
b_expr = "neq(" + b_expr + ", UInt(0))";
@@ -388,6 +602,11 @@ struct FirrtlWorker
string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
+ // Deal with FIRRTL's "shift widens" semantics
+ if (extract_y_bits) {
+ expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1);
+ }
+
if ((is_signed && !always_uint) || cell->type.in("$sub"))
expr = stringf("asUInt(%s)", expr.c_str());
@@ -420,6 +639,7 @@ struct FirrtlWorker
int abits = cell->parameters.at("\\ABITS").as_int();
int width = cell->parameters.at("\\WIDTH").as_int();
int size = cell->parameters.at("\\SIZE").as_int();
+ memory m(cell, mem_id, abits, size, width);
int rd_ports = cell->parameters.at("\\RD_PORTS").as_int();
int wr_ports = cell->parameters.at("\\WR_PORTS").as_int();
@@ -436,33 +656,24 @@ struct FirrtlWorker
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 addr_sig = cell->getPort("\\RD_ADDR").extract(i*abits, abits);
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);
+ string addr_expr = make_expr(addr_sig);
+ string name(stringf("%s.r%d", m.name.c_str(), i));
+ bool clk_enable = false;
+ bool clk_parity = true;
+ bool transparency = false;
+ SigSpec ena_sig = RTLIL::SigSpec(RTLIL::State::S1, 1);
+ SigSpec clk_sig = RTLIL::SigSpec(RTLIL::State::S0, 1);
+ read_port rp(name, clk_enable, clk_parity, transparency, clk_sig, ena_sig, addr_sig);
+ m.add_memory_read_port(rp);
+ cell_exprs.push_back(rp.gen_read(indent.c_str()));
+ register_reverse_wire_map(stringf("%s.data", name.c_str()), data_sig);
}
for (int i = 0; i < wr_ports; i++)
@@ -473,9 +684,16 @@ struct FirrtlWorker
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));
+ string name(stringf("%s.w%d", m.name.c_str(), i));
+ bool clk_enable = true;
+ bool clk_parity = true;
+ bool transparency = false;
+ SigSpec addr_sig =cell->getPort("\\WR_ADDR").extract(i*abits, abits);
+ string addr_expr = make_expr(addr_sig);
+ SigSpec data_sig =cell->getPort("\\WR_DATA").extract(i*width, width);
+ string data_expr = make_expr(data_sig);
+ SigSpec clk_sig = cell->getPort("\\WR_CLK").extract(i);
+ string clk_expr = make_expr(clk_sig);
SigSpec wen_sig = cell->getPort("\\WR_EN").extract(i*width, width);
string wen_expr = make_expr(wen_sig[0]);
@@ -484,13 +702,57 @@ struct FirrtlWorker
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()));
+ SigSpec mask_sig = RTLIL::SigSpec(RTLIL::State::S1, 1);
+ write_port wp(name, clk_enable, clk_parity, transparency, clk_sig, wen_sig[0], addr_sig, mask_sig);
+ m.add_memory_write_port(wp);
+ cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), name.c_str(), data_expr.c_str()));
+ cell_exprs.push_back(wp.gen_write(indent.c_str()));
}
+ register_memory(m);
+ continue;
+ }
+ if (cell->type.in("$memwr", "$memrd", "$meminit"))
+ {
+ std::string cell_type = fid(cell->type);
+ std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string());
+ int abits = cell->parameters.at("\\ABITS").as_int();
+ int width = cell->parameters.at("\\WIDTH").as_int();
+ memory *mp = nullptr;
+ if (cell->type == "$meminit" ) {
+ log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str());
+ } else {
+ // It's a $memwr or $memrd. Remember the read/write port parameters for the eventual FIRRTL memory definition.
+ auto addrSig = cell->getPort("\\ADDR");
+ auto dataSig = cell->getPort("\\DATA");
+ auto enableSig = cell->getPort("\\EN");
+ auto clockSig = cell->getPort("\\CLK");
+ Const clk_enable = cell->parameters.at("\\CLK_ENABLE");
+ Const clk_polarity = cell->parameters.at("\\CLK_POLARITY");
+
+ // Do we already have an entry for this memory?
+ if (memories.count(mem_id) == 0) {
+ memory m(cell, mem_id, abits, 0, width);
+ register_memory(m);
+ }
+ mp = &memories.at(mem_id);
+ int portNum = 0;
+ bool transparency = false;
+ string data_expr = make_expr(dataSig);
+ if (cell->type.in("$memwr")) {
+ portNum = (int) mp->write_ports.size();
+ write_port wp(stringf("%s.w%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig, dataSig);
+ mp->add_memory_write_port(wp);
+ cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), wp.name.c_str(), data_expr.c_str()));
+ cell_exprs.push_back(wp.gen_write(indent.c_str()));
+ } else if (cell->type.in("$memrd")) {
+ portNum = (int) mp->read_ports.size();
+ read_port rp(stringf("%s.r%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig);
+ mp->add_memory_read_port(rp);
+ cell_exprs.push_back(rp.gen_read(indent.c_str()));
+ register_reverse_wire_map(stringf("%s.data", rp.name.c_str()), dataSig);
+ }
+ }
continue;
}
@@ -513,7 +775,65 @@ struct FirrtlWorker
continue;
}
- log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
+ // This may be a parameterized module - paramod.
+ if (cell->type.substr(0, 8) == "$paramod")
+ {
+ process_instance(cell, wire_exprs);
+ continue;
+ }
+ if (cell->type == "$shiftx") {
+ // assign y = a[b +: y_width];
+ // We'll extract the correct bits as part of the primop.
+
+ string y_id = make_id(cell->name);
+ int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
+ string a_expr = make_expr(cell->getPort("\\A"));
+ // Get the initial bit selector
+ string b_expr = make_expr(cell->getPort("\\B"));
+ wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+
+ if (cell->getParam("\\B_SIGNED").as_bool()) {
+ // Use validif to constrain the selection (test the sign bit)
+ auto b_string = b_expr.c_str();
+ int b_sign = cell->parameters.at("\\B_WIDTH").as_int() - 1;
+ b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string);
+ }
+ string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str());
+
+ cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ register_reverse_wire_map(y_id, cell->getPort("\\Y"));
+ continue;
+ }
+ if (cell->type == "$shift") {
+ // assign y = a >> b;
+ // where b may be negative
+
+ string y_id = make_id(cell->name);
+ int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
+ string a_expr = make_expr(cell->getPort("\\A"));
+ string b_expr = make_expr(cell->getPort("\\B"));
+ auto b_string = b_expr.c_str();
+ int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int();
+ string expr;
+ wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+
+ if (cell->getParam("\\B_SIGNED").as_bool()) {
+ // We generate a left or right shift based on the sign of b.
+ std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_padded_width).c_str(), y_width);
+ std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
+ expr = stringf("mux(%s < 0, %s, %s)",
+ b_string,
+ dshl.c_str(),
+ dshr.c_str()
+ );
+ } else {
+ expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
+ }
+ cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ register_reverse_wire_map(y_id, cell->getPort("\\Y"));
+ continue;
+ }
+ log_warning("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
}
for (auto conn : module->connections())
@@ -610,6 +930,24 @@ struct FirrtlWorker
f << stringf("\n");
+ // If we have any memory definitions, output them.
+ for (auto kv : memories) {
+ memory &m = kv.second;
+ f << stringf(" mem %s:\n", m.name.c_str());
+ f << stringf(" data-type => UInt<%d>\n", m.width);
+ f << stringf(" depth => %d\n", m.size);
+ for (int i = 0; i < (int) m.read_ports.size(); i += 1) {
+ f << stringf(" reader => r%d\n", i);
+ }
+ for (int i = 0; i < (int) m.write_ports.size(); i += 1) {
+ f << stringf(" writer => w%d\n", i);
+ }
+ f << stringf(" read-latency => %d\n", m.read_latency);
+ f << stringf(" write-latency => %d\n", m.write_latency);
+ f << stringf(" read-under-write => undefined\n");
+ }
+ f << stringf("\n");
+
for (auto str : cell_exprs)
f << str;
@@ -629,38 +967,53 @@ struct FirrtlBackend : public Backend {
log(" write_firrtl [options] [filename]\n");
log("\n");
log("Write a FIRRTL netlist of the current design.\n");
+ log("The following commands are executed by this command:\n");
+ log(" pmuxtree\n");
log("\n");
}
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- size_t argidx;
- for (argidx = 1; argidx < args.size(); argidx++)
- {
- // if (args[argidx] == "-aig") {
- // aig_mode = true;
- // continue;
- // }
- break;
+ size_t argidx = args.size(); // We aren't expecting any arguments.
+
+ // If we weren't explicitly passed a filename, use the last argument (if it isn't a flag).
+ if (filename == "") {
+ if (argidx > 0 && args[argidx - 1][0] != '-') {
+ // extra_args and friends need to see this argument.
+ argidx -= 1;
+ filename = args[argidx];
+ }
}
extra_args(f, filename, args, argidx);
- log_header(design, "Executing FIRRTL backend.\n");
+ if (!design->full_selection())
+ log_cmd_error("This command only operates on fully selected designs!\n");
- Module *top = design->top_module();
+ log_header(design, "Executing FIRRTL backend.\n");
+ log_push();
- if (top == nullptr)
- log_error("No top module found!\n");
+ Pass::call(design, stringf("pmuxtree"));
namecache.clear();
autoid_counter = 0;
+ // Get the top module, or a reasonable facsimile - we need something for the circuit name.
+ Module *top = design->top_module();
+ Module *last = nullptr;
+ // Generate module and wire names.
for (auto module : design->modules()) {
make_id(module->name);
+ last = module;
+ if (top == nullptr && module->get_bool_attribute("\\top")) {
+ top = module;
+ }
for (auto wire : module->wires())
if (wire->port_id)
make_id(wire->name);
}
+ if (top == nullptr)
+ top = last;
+
*f << stringf("circuit %s:\n", make_id(top->name));
for (auto module : design->modules())
diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc
index 4c58ea08..313af7d5 100644
--- a/backends/ilang/ilang_backend.cc
+++ b/backends/ilang/ilang_backend.cc
@@ -160,7 +160,10 @@ void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::
}
f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
for (auto &it : cell->parameters) {
- f << stringf("%s parameter%s %s ", indent.c_str(), (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it.first.c_str());
+ f << stringf("%s parameter%s%s %s ", indent.c_str(),
+ (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "",
+ (it.second.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "",
+ it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
@@ -201,10 +204,15 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it)
{
+ for (auto ait = (*it)->attributes.begin(); ait != (*it)->attributes.end(); ++ait) {
+ f << stringf("%s attribute %s ", indent.c_str(), ait->first.c_str());
+ dump_const(f, ait->second);
+ f << stringf("\n");
+ }
f << stringf("%s case ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) {
if (i > 0)
- f << stringf(", ");
+ f << stringf(" , ");
dump_sigspec(f, (*it)->compare[i]);
}
f << stringf("\n");
@@ -480,6 +488,7 @@ struct DumpPass : public Pass {
std::stringstream buf;
if (!filename.empty()) {
+ rewrite_filename(filename);
std::ofstream *ff = new std::ofstream;
ff->open(filename.c_str(), append ? std::ofstream::app : std::ofstream::trunc);
if (ff->fail()) {
diff --git a/backends/intersynth/intersynth.cc b/backends/intersynth/intersynth.cc
index 2eb08dbe..b0e3cd25 100644
--- a/backends/intersynth/intersynth.cc
+++ b/backends/intersynth/intersynth.cc
@@ -127,7 +127,7 @@ struct IntersynthBackend : public Backend {
RTLIL::Module *module = module_it.second;
SigMap sigmap(module);
- if (module->get_bool_attribute("\\blackbox"))
+ if (module->get_blackbox_attribute())
continue;
if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells_.size() == 0)
continue;
diff --git a/backends/json/json.cc b/backends/json/json.cc
index f5c68798..dda4dfed 100644
--- a/backends/json/json.cc
+++ b/backends/json/json.cc
@@ -126,6 +126,10 @@ struct JsonWriter
f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: {\n", get_name(n).c_str());
f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output");
+ if (w->start_offset)
+ f << stringf(" \"offset\": %d,\n", w->start_offset);
+ if (w->upto)
+ f << stringf(" \"upto\": 1,\n");
f << stringf(" \"bits\": %s\n", get_bits(w).c_str());
f << stringf(" }");
first = false;
@@ -189,6 +193,10 @@ struct JsonWriter
f << stringf(" %s: {\n", get_name(w->name).c_str());
f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
f << stringf(" \"bits\": %s,\n", get_bits(w).c_str());
+ if (w->start_offset)
+ f << stringf(" \"offset\": %d,\n", w->start_offset);
+ if (w->upto)
+ f << stringf(" \"upto\": 1,\n");
f << stringf(" \"attributes\": {");
write_parameters(w->attributes);
f << stringf("\n }\n");
@@ -525,6 +533,7 @@ struct JsonPass : public Pass {
std::stringstream buf;
if (!filename.empty()) {
+ rewrite_filename(filename);
std::ofstream *ff = new std::ofstream;
ff->open(filename.c_str(), std::ofstream::trunc);
if (ff->fail()) {
diff --git a/backends/protobuf/protobuf.cc b/backends/protobuf/protobuf.cc
index f56147ce..fff110bb 100644
--- a/backends/protobuf/protobuf.cc
+++ b/backends/protobuf/protobuf.cc
@@ -48,7 +48,7 @@ struct ProtobufDesignSerializer
ProtobufDesignSerializer(bool use_selection, bool aig_mode) :
aig_mode_(aig_mode), use_selection_(use_selection) { }
-
+
string get_name(IdString name)
{
return RTLIL::unescape_id(name);
@@ -60,7 +60,7 @@ struct ProtobufDesignSerializer
{
for (auto &param : parameters) {
std::string key = get_name(param.first);
-
+
yosys::pb::Parameter pb_param;
@@ -207,7 +207,7 @@ struct ProtobufDesignSerializer
(*models)[aig.name] = pb_model;
}
}
-
+
void serialize_design(yosys::pb::Design *pb, Design *design)
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
@@ -336,6 +336,7 @@ struct ProtobufPass : public Pass {
std::stringstream buf;
if (!filename.empty()) {
+ rewrite_filename(filename);
std::ofstream *ff = new std::ofstream;
ff->open(filename.c_str(), std::ofstream::trunc);
if (ff->fail()) {
diff --git a/backends/simplec/test00_uut.v b/backends/simplec/test00_uut.v
index 744dbe9e..92329a6f 100644
--- a/backends/simplec/test00_uut.v
+++ b/backends/simplec/test00_uut.v
@@ -3,12 +3,12 @@ module test(input [31:0] a, b, c, output [31:0] x, y, z, w);
unit_y unit_y_inst (.a(a), .b(b), .c(c), .y(y));
assign z = a ^ b ^ c, w = z;
endmodule
-
+
module unit_x(input [31:0] a, b, c, output [31:0] x);
assign x = (a & b) | c;
endmodule
-
+
module unit_y(input [31:0] a, b, c, output [31:0] y);
assign y = a & (b | c);
endmodule
-
+
diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc
index f98e6104..2c0b7c69 100644
--- a/backends/smt2/Makefile.inc
+++ b/backends/smt2/Makefile.inc
@@ -3,14 +3,30 @@ OBJS += backends/smt2/smt2.o
ifneq ($(CONFIG),mxe)
ifneq ($(CONFIG),emcc)
+
+# MSYS targets support yosys-smtbmc, but require a launcher script
+ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64))
+TARGETS += yosys-smtbmc.exe yosys-smtbmc-script.py
+# Needed to find the Python interpreter for yosys-smtbmc scripts.
+# Override if necessary, it is only used for msys2 targets.
+PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3)
+
+yosys-smtbmc-script.py: backends/smt2/smtbmc.py
+ $(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' \
+ -e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@
+
+yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py
+ $(P) gcc -DGUI=0 -O -s -o $@ $<
+# Other targets
+else
TARGETS += yosys-smtbmc
yosys-smtbmc: backends/smt2/smtbmc.py
$(P) sed 's|##yosys-sys-path##|sys.path += ["/usr/share/yosys"]|;' < $< > $@.new
$(Q) chmod +x $@.new
$(Q) mv $@.new $@
+endif
$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py))
endif
endif
-
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
index e2777ae0..e318a405 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -416,6 +416,7 @@ struct Smt2Worker
for (char ch : expr) {
if (ch == 'A') processed_expr += get_bv(sig_a);
else if (ch == 'B') processed_expr += get_bv(sig_b);
+ else if (ch == 'P') processed_expr += get_bv(cell->getPort("\\B"));
else if (ch == 'L') processed_expr += is_signed ? "a" : "l";
else if (ch == 'U') processed_expr += is_signed ? "s" : "u";
else processed_expr += ch;
@@ -554,7 +555,9 @@ struct Smt2Worker
if (cell->type.in("$shift", "$shiftx")) {
if (cell->getParam("\\B_SIGNED").as_bool()) {
- /* FIXME */
+ return export_bvop(cell, stringf("(ite (bvsge P #b%0*d) "
+ "(bvlshr A B) (bvlshr A (bvneg B)))",
+ GetSize(cell->getPort("\\B")), 0), 's');
} else {
return export_bvop(cell, "(bvlshr A B)", 's');
}
@@ -885,8 +888,8 @@ struct Smt2Worker
string name_a = get_bool(cell->getPort("\\A"));
string name_en = get_bool(cell->getPort("\\EN"));
- decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id,
- cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell)));
+ string infostr = (cell->name[0] == '$' && cell->attributes.count("\\src")) ? cell->attributes.at("\\src").decode_string() : get_id(cell);
+ decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, infostr.c_str()));
if (cell->type == "$cover")
decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n",
@@ -1101,20 +1104,27 @@ struct Smt2Worker
break;
Const initword = init_data.extract(i*width, width, State::Sx);
+ Const initmask = initword;
bool gen_init_constr = false;
- for (auto bit : initword.bits)
- if (bit == State::S0 || bit == State::S1)
+ for (int k = 0; k < GetSize(initword); k++) {
+ if (initword[k] == State::S0 || initword[k] == State::S1) {
gen_init_constr = true;
+ initmask[k] = State::S1;
+ } else {
+ initmask[k] = State::S0;
+ initword[k] = State::S0;
+ }
+ }
if (gen_init_constr)
{
if (statebv)
/* FIXME */;
else
- init_list.push_back(stringf("(= (select (|%s#%d#0| state) #b%s) #b%s) ; %s[%d]",
+ init_list.push_back(stringf("(= (bvand (select (|%s#%d#0| state) #b%s) #b%s) #b%s) ; %s[%d]",
get_id(module), arrayid, Const(i, abits).as_string().c_str(),
- initword.as_string().c_str(), get_id(cell), i));
+ initmask.as_string().c_str(), initword.as_string().c_str(), get_id(cell), i));
}
}
}
@@ -1533,7 +1543,7 @@ struct Smt2Backend : public Backend {
for (auto module : sorted_modules)
{
- if (module->get_bool_attribute("\\blackbox") || module->has_memories_warn() || module->has_processes_warn())
+ if (module->get_blackbox_attribute() || module->has_memories_warn() || module->has_processes_warn())
continue;
log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module));
diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py
index 6af2a5ac..445a42e0 100644
--- a/backends/smt2/smtbmc.py
+++ b/backends/smt2/smtbmc.py
@@ -32,6 +32,7 @@ cexfile = None
aimfile = None
aiwfile = None
aigheader = True
+btorwitfile = None
vlogtbfile = None
vlogtbtop = None
inconstr = list()
@@ -86,12 +87,15 @@ yosys-smtbmc [options] <yosys_smt2_output>
--aig <aim_filename>:<aiw_filename>
like above, but for map files and witness files that do not
- share a filename prefix (or use differen file extensions).
+ share a filename prefix (or use different file extensions).
--aig-noheader
the AIGER witness file does not include the status and
properties lines.
+ --btorwit <btor_witness_filename>
+ read a BTOR witness.
+
--noinfo
only run the core proof, do not collect and print any
additional information (e.g. which assert failed)
@@ -99,8 +103,8 @@ yosys-smtbmc [options] <yosys_smt2_output>
--presat
check if the design with assumptions but without assertions
is SAT before checking if assertions are UNSAT. This will
- detect if there are contradicting assumtions. In some cases
- this will also help to "warmup" the solver, potentially
+ detect if there are contradicting assumptions. In some cases
+ this will also help to "warm up" the solver, potentially
yielding a speedup.
--final-only
@@ -145,14 +149,14 @@ yosys-smtbmc [options] <yosys_smt2_output>
--append <num_steps>
add <num_steps> time steps at the end of the trace
when creating a counter example (this additional time
- steps will still be constrained by assumtions)
+ steps will still be constrained by assumptions)
""" + so.helpmsg())
sys.exit(1)
try:
opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts +
- ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "presat",
+ ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "btorwit=", "presat",
"dump-vcd=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=",
"smtc-init", "smtc-top=", "noinit"])
except:
@@ -189,6 +193,8 @@ for o, a in opts:
aiwfile = a + ".aiw"
elif o == "--aig-noheader":
aigheader = False
+ elif o == "--btorwit":
+ btorwitfile = a
elif o == "--dump-vcd":
vcdfile = a
elif o == "--dump-vlogtb":
@@ -575,6 +581,103 @@ if aimfile is not None:
num_steps = max(num_steps, step+1)
step += 1
+if btorwitfile is not None:
+ with open(btorwitfile, "r") as f:
+ step = None
+ suffix = None
+ altsuffix = None
+ header_okay = False
+
+ for line in f:
+ line = line.strip()
+
+ if line == "sat":
+ header_okay = True
+ continue
+
+ if not header_okay:
+ continue
+
+ if line == "" or line[0] == "b" or line[0] == "j":
+ continue
+
+ if line == ".":
+ break
+
+ if line[0] == '#' or line[0] == '@':
+ step = int(line[1:])
+ suffix = line
+ altsuffix = suffix
+ if suffix[0] == "@":
+ altsuffix = "#" + suffix[1:]
+ else:
+ altsuffix = "@" + suffix[1:]
+ continue
+
+ line = line.split()
+
+ if len(line) == 0:
+ continue
+
+ if line[-1].endswith(suffix):
+ line[-1] = line[-1][0:len(line[-1]) - len(suffix)]
+
+ if line[-1].endswith(altsuffix):
+ line[-1] = line[-1][0:len(line[-1]) - len(altsuffix)]
+
+ if line[-1][0] == "$":
+ continue
+
+ # BV assignments
+ if len(line) == 3 and line[1][0] != "[":
+ value = line[1]
+ name = line[2]
+
+ path = smt.get_path(topmod, name)
+
+ if not smt.net_exists(topmod, path):
+ continue
+
+ width = smt.net_width(topmod, path)
+
+ if width == 1:
+ assert value in ["0", "1"]
+ value = "true" if value == "1" else "false"
+ else:
+ value = "#b" + value
+
+ smtexpr = "(= [%s] %s)" % (name, value)
+ constr_assumes[step].append((btorwitfile, smtexpr))
+
+ # Array assignments
+ if len(line) == 4 and line[1][0] == "[":
+ index = line[1]
+ value = line[2]
+ name = line[3]
+
+ path = smt.get_path(topmod, name)
+
+ if not smt.mem_exists(topmod, path):
+ continue
+
+ meminfo = smt.mem_info(topmod, path)
+
+ if meminfo[1] == 1:
+ assert value in ["0", "1"]
+ value = "true" if value == "1" else "false"
+ else:
+ value = "#b" + value
+
+ assert index[0] == "["
+ assert index[-1] == "]"
+ index = "#b" + index[1:-1]
+
+ smtexpr = "(= (select [%s] %s) %s)" % (name, index, value)
+ constr_assumes[step].append((btorwitfile, smtexpr))
+
+ skip_steps = step
+ num_steps = step+1
+
def write_vcd_trace(steps_start, steps_stop, index):
filename = vcdfile.replace("%", index)
print_msg("Writing trace to VCD file: %s" % (filename))
@@ -1259,7 +1362,11 @@ elif covermode:
smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i))
smt_assert_consequent(get_constr_expr(constr_assumes, i))
print_msg("Re-solving with appended steps..")
- assert smt_check_sat() == "sat"
+ if smt_check_sat() == "unsat":
+ print("%s Cannot appended steps without violating assumptions!" % smt.timestamp())
+ found_failed_assert = True
+ retstatus = False
+ break
reached_covers = smt.bv2bin(smt.get("(covers_%d s%d)" % (coveridx, step)))
assert len(reached_covers) == len(cover_desc)
@@ -1377,7 +1484,11 @@ else: # not tempind, covermode
smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i))
smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i))
smt_assert_consequent(get_constr_expr(constr_assumes, i))
- assert smt_check_sat() == "sat"
+ print_msg("Re-solving with appended steps..")
+ if smt_check_sat() == "unsat":
+ print("%s Cannot appended steps without violating assumptions!" % smt.timestamp())
+ retstatus = False
+ break
print_anyconsts(step)
for i in range(step, last_check_step+1):
print_failed_asserts(i)
diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py
index 3fc823e3..ae7968a1 100644
--- a/backends/smt2/smtio.py
+++ b/backends/smt2/smtio.py
@@ -31,11 +31,19 @@ from threading import Thread
# does not run out of stack frames when parsing large expressions
if os.name == "posix":
smtio_reclimit = 64 * 1024
- smtio_stacksize = 128 * 1024 * 1024
if sys.getrecursionlimit() < smtio_reclimit:
sys.setrecursionlimit(smtio_reclimit)
- if resource.getrlimit(resource.RLIMIT_STACK)[0] < smtio_stacksize:
- resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, -1))
+
+ current_rlimit_stack = resource.getrlimit(resource.RLIMIT_STACK)
+ if current_rlimit_stack[0] != resource.RLIM_INFINITY:
+ smtio_stacksize = 128 * 1024 * 1024
+ if os.uname().sysname == "Darwin":
+ # MacOS has rather conservative stack limits
+ smtio_stacksize = 16 * 1024 * 1024
+ if current_rlimit_stack[1] != resource.RLIM_INFINITY:
+ smtio_stacksize = min(smtio_stacksize, current_rlimit_stack[1])
+ if current_rlimit_stack[0] < smtio_stacksize:
+ resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, current_rlimit_stack[1]))
# currently running solvers (so we can kill them)
@@ -158,19 +166,28 @@ class SmtIo:
self.unroll = False
if self.solver == "yices":
- self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts
+ if self.noincr:
+ self.popen_vargs = ['yices-smt2'] + self.solver_opts
+ else:
+ self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts
if self.solver == "z3":
self.popen_vargs = ['z3', '-smt2', '-in'] + self.solver_opts
if self.solver == "cvc4":
- self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts
+ if self.noincr:
+ self.popen_vargs = ['cvc4', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts
+ else:
+ self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts
if self.solver == "mathsat":
self.popen_vargs = ['mathsat'] + self.solver_opts
if self.solver == "boolector":
- self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts
+ if self.noincr:
+ self.popen_vargs = ['boolector', '--smt2'] + self.solver_opts
+ else:
+ self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts
self.unroll = True
if self.solver == "abc":
@@ -767,7 +784,7 @@ class SmtIo:
def get_path(self, mod, path):
assert mod in self.modinfo
- path = path.split(".")
+ path = path.replace("\\", "/").split(".")
for i in range(len(path)-1):
first = ".".join(path[0:i+1])
@@ -1006,6 +1023,8 @@ class MkVcd:
assert t >= self.t
if t != self.t:
if self.t == -1:
+ print("$version Generated by Yosys-SMTBMC $end", file=self.f)
+ print("$timescale 1ns $end", file=self.f)
print("$var integer 32 t smt_step $end", file=self.f)
print("$var event 1 ! smt_clock $end", file=self.f)
@@ -1024,7 +1043,10 @@ class MkVcd:
scope = scope[:-1]
while uipath[:-1] != scope:
- print("$scope module %s $end" % uipath[len(scope)], file=self.f)
+ scopename = uipath[len(scope)]
+ if scopename.startswith("$"):
+ scopename = "\\" + scopename
+ print("$scope module %s $end" % scopename, file=self.f)
scope.append(uipath[len(scope)])
if path in self.clocks and self.clocks[path][1] == "event":
diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc
index b8383412..d75456c1 100644
--- a/backends/smv/smv.cc
+++ b/backends/smv/smv.cc
@@ -42,7 +42,7 @@ struct SmvWorker
pool<Wire*> partial_assignment_wires;
dict<SigBit, std::pair<const char*, int>> partial_assignment_bits;
- vector<string> assignments, invarspecs;
+ vector<string> inputvars, vars, definitions, assignments, invarspecs;
const char *cid()
{
@@ -195,7 +195,7 @@ struct SmvWorker
return rvalue(sig);
const char *temp_id = cid();
- f << stringf(" %s : unsigned word[%d]; -- %s\n", temp_id, GetSize(sig), log_signal(sig));
+// f << stringf(" %s : unsigned word[%d]; -- %s\n", temp_id, GetSize(sig), log_signal(sig));
int offset = 0;
for (auto bit : sig) {
@@ -210,14 +210,14 @@ struct SmvWorker
void run()
{
f << stringf("MODULE %s\n", cid(module->name));
- f << stringf(" VAR\n");
for (auto wire : module->wires())
{
if (SigSpec(wire) != sigmap(wire))
partial_assignment_wires.insert(wire);
- f << stringf(" %s : unsigned word[%d]; -- %s\n", cid(wire->name), wire->width, log_id(wire));
+ if (wire->port_input)
+ inputvars.push_back(stringf("%s : unsigned word[%d]; -- %s", cid(wire->name), wire->width, log_id(wire)));
if (wire->attributes.count("\\init"))
assignments.push_back(stringf("init(%s) := %s;", lvalue(wire), rvalue(wire->attributes.at("\\init"))));
@@ -275,8 +275,8 @@ struct SmvWorker
const char *b_shr = rvalue_u(sig_b);
const char *b_shl = cid();
- f << stringf(" %s : unsigned word[%d]; -- neg(%s)\n", b_shl, GetSize(sig_b), log_signal(sig_b));
- assignments.push_back(stringf("%s := unsigned(-%s);", b_shl, rvalue_s(sig_b)));
+// f << stringf(" %s : unsigned word[%d]; -- neg(%s)\n", b_shl, GetSize(sig_b), log_signal(sig_b));
+ definitions.push_back(stringf("%s := unsigned(-%s);", b_shl, rvalue_s(sig_b)));
string expr_shl = stringf("resize(%s << %s[%d:0], %d)", expr_a.c_str(), b_shl, shift_b_width-1, width_y);
string expr_shr = stringf("resize(%s >> %s[%d:0], %d)", expr_a.c_str(), b_shr, shift_b_width-1, width_y);
@@ -303,7 +303,7 @@ struct SmvWorker
GetSize(sig_b)-shift_b_width, width_y, expr.c_str());
}
- assignments.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
+ definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
continue;
}
@@ -319,12 +319,12 @@ struct SmvWorker
if (cell->getParam("\\A_SIGNED").as_bool())
{
- assignments.push_back(stringf("%s := unsigned(%s%s);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := unsigned(%s%s);", lvalue(cell->getPort("\\Y")),
op.c_str(), rvalue_s(cell->getPort("\\A"), width)));
}
else
{
- assignments.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")),
op.c_str(), rvalue_u(cell->getPort("\\A"), width)));
}
@@ -346,12 +346,12 @@ struct SmvWorker
if (cell->getParam("\\A_SIGNED").as_bool())
{
- assignments.push_back(stringf("%s := unsigned(%s %s %s);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := unsigned(%s %s %s);", lvalue(cell->getPort("\\Y")),
rvalue_s(cell->getPort("\\A"), width), op.c_str(), rvalue_s(cell->getPort("\\B"), width)));
}
else
{
- assignments.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
rvalue_u(cell->getPort("\\A"), width), op.c_str(), rvalue_u(cell->getPort("\\B"), width)));
}
@@ -370,12 +370,12 @@ struct SmvWorker
if (cell->getParam("\\A_SIGNED").as_bool())
{
- assignments.push_back(stringf("%s := resize(unsigned(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := resize(unsigned(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
rvalue_s(cell->getPort("\\A"), width), op.c_str(), rvalue_s(cell->getPort("\\B"), width), width_y));
}
else
{
- assignments.push_back(stringf("%s := resize(%s %s %s, %d);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := resize(%s %s %s, %d);", lvalue(cell->getPort("\\Y")),
rvalue_u(cell->getPort("\\A"), width), op.c_str(), rvalue_u(cell->getPort("\\B"), width), width_y));
}
@@ -407,7 +407,7 @@ struct SmvWorker
expr_b = stringf("resize(%s, %d)", rvalue(cell->getPort("\\B")), width);
}
- assignments.push_back(stringf("%s := resize(word1(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := resize(word1(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
expr_a.c_str(), op.c_str(), expr_b.c_str(), GetSize(cell->getPort("\\Y"))));
continue;
@@ -425,7 +425,7 @@ struct SmvWorker
if (cell->type == "$reduce_or") expr = stringf("%s != 0ub%d_0", expr_a, width_a);
if (cell->type == "$reduce_bool") expr = stringf("%s != 0ub%d_0", expr_a, width_a);
- assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
+ definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
continue;
}
@@ -444,7 +444,7 @@ struct SmvWorker
if (cell->type == "$reduce_xnor")
expr = "!(" + expr + ")";
- assignments.push_back(stringf("%s := resize(%s, %d);", expr_y, expr.c_str(), width_y));
+ definitions.push_back(stringf("%s := resize(%s, %d);", expr_y, expr.c_str(), width_y));
continue;
}
@@ -462,7 +462,7 @@ struct SmvWorker
if (cell->type == "$logic_and") expr = expr_a + " & " + expr_b;
if (cell->type == "$logic_or") expr = expr_a + " | " + expr_b;
- assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
+ definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
continue;
}
@@ -474,7 +474,7 @@ struct SmvWorker
string expr_a = stringf("(%s = 0ub%d_0)", rvalue(cell->getPort("\\A")), width_a);
const char *expr_y = lvalue(cell->getPort("\\Y"));
- assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr_a.c_str(), width_y));
+ definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr_a.c_str(), width_y));
continue;
}
@@ -490,12 +490,13 @@ struct SmvWorker
expr += stringf("bool(%s) ? %s : ", rvalue(sig_s[i]), rvalue(sig_b.extract(i*width, width)));
expr += rvalue(sig_a);
- assignments.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
+ definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
continue;
}
if (cell->type == "$dff")
{
+ vars.push_back(stringf("%s : unsigned word[%d]; -- %s", lvalue(cell->getPort("\\Q")), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q"))));
assignments.push_back(stringf("next(%s) := %s;", lvalue(cell->getPort("\\Q")), rvalue(cell->getPort("\\D"))));
continue;
}
@@ -503,7 +504,7 @@ struct SmvWorker
if (cell->type.in("$_BUF_", "$_NOT_"))
{
string op = cell->type == "$_NOT_" ? "!" : "";
- assignments.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")), op.c_str(), rvalue(cell->getPort("\\A"))));
+ definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")), op.c_str(), rvalue(cell->getPort("\\A"))));
continue;
}
@@ -517,49 +518,49 @@ struct SmvWorker
if (cell->type.in("$_XNOR_")) op = "xnor";
if (cell->type.in("$_ANDNOT_", "$_ORNOT_"))
- assignments.push_back(stringf("%s := %s %s (!%s);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := %s %s (!%s);", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
else
if (cell->type.in("$_NAND_", "$_NOR_"))
- assignments.push_back(stringf("%s := !(%s %s %s);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := !(%s %s %s);", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
else
- assignments.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
continue;
}
if (cell->type == "$_MUX_")
{
- assignments.push_back(stringf("%s := bool(%s) ? %s : %s;", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := bool(%s) ? %s : %s;", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\S")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\A"))));
continue;
}
if (cell->type == "$_AOI3_")
{
- assignments.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C"))));
continue;
}
if (cell->type == "$_OAI3_")
{
- assignments.push_back(stringf("%s := !((%s | %s) & %s);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := !((%s | %s) & %s);", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C"))));
continue;
}
if (cell->type == "$_AOI4_")
{
- assignments.push_back(stringf("%s := !((%s & %s) | (%s & %s));", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := !((%s & %s) | (%s & %s));", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")), rvalue(cell->getPort("\\D"))));
continue;
}
if (cell->type == "$_OAI4_")
{
- assignments.push_back(stringf("%s := !((%s | %s) & (%s | %s));", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := !((%s | %s) & (%s | %s));", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")), rvalue(cell->getPort("\\D"))));
continue;
}
@@ -567,13 +568,13 @@ struct SmvWorker
if (cell->type[0] == '$')
log_error("Found currently unsupported cell type %s (%s.%s).\n", log_id(cell->type), log_id(module), log_id(cell));
- f << stringf(" %s : %s;\n", cid(cell->name), cid(cell->type));
+// f << stringf(" %s : %s;\n", cid(cell->name), cid(cell->type));
for (auto &conn : cell->connections())
if (cell->output(conn.first))
- assignments.push_back(stringf("%s := %s.%s;", lvalue(conn.second), cid(cell->name), cid(conn.first)));
+ definitions.push_back(stringf("%s := %s.%s;", lvalue(conn.second), cid(cell->name), cid(conn.first)));
else
- assignments.push_back(stringf("%s.%s := %s;", cid(cell->name), cid(conn.first), rvalue(conn.second)));
+ definitions.push_back(stringf("%s.%s := %s;", cid(cell->name), cid(conn.first), rvalue(conn.second)));
}
for (Wire *wire : partial_assignment_wires)
@@ -657,7 +658,25 @@ struct SmvWorker
}
}
- assignments.push_back(stringf("%s := %s;", cid(wire->name), expr.c_str()));
+ definitions.push_back(stringf("%s := %s;", cid(wire->name), expr.c_str()));
+ }
+
+ if (!inputvars.empty()) {
+ f << stringf(" IVAR\n");
+ for (const string &line : inputvars)
+ f << stringf(" %s\n", line.c_str());
+ }
+
+ if (!vars.empty()) {
+ f << stringf(" VAR\n");
+ for (const string &line : vars)
+ f << stringf(" %s\n", line.c_str());
+ }
+
+ if (!definitions.empty()) {
+ f << stringf(" DEFINE\n");
+ for (const string &line : definitions)
+ f << stringf(" %s\n", line.c_str());
}
if (!assignments.empty()) {
@@ -720,7 +739,7 @@ struct SmvBackend : public Backend {
pool<Module*> modules;
for (auto module : design->modules())
- if (!module->get_bool_attribute("\\blackbox") && !module->has_memories_warn() && !module->has_processes_warn())
+ if (!module->get_blackbox_attribute() && !module->has_memories_warn() && !module->has_processes_warn())
modules.insert(module);
if (template_f.is_open())
diff --git a/backends/spice/spice.cc b/backends/spice/spice.cc
index b6a3f1e7..6738a4bb 100644
--- a/backends/spice/spice.cc
+++ b/backends/spice/spice.cc
@@ -212,7 +212,7 @@ struct SpiceBackend : public Backend {
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
- if (module->get_bool_attribute("\\blackbox"))
+ if (module->get_blackbox_attribute())
continue;
if (module->processes.size() != 0)
diff --git a/backends/table/table.cc b/backends/table/table.cc
index b75169ea..796f1805 100644
--- a/backends/table/table.cc
+++ b/backends/table/table.cc
@@ -67,7 +67,7 @@ struct TableBackend : public Backend {
for (auto module : design->modules())
{
- if (module->get_bool_attribute("\\blackbox"))
+ if (module->get_blackbox_attribute())
continue;
SigMap sigmap(module);
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index d53df2e7..087c6fec 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -33,7 +33,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal;
+bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal, siminit;
int auto_name_counter, auto_name_offset, auto_name_digits;
std::map<RTLIL::IdString, int> auto_name_map;
std::set<RTLIL::IdString> reg_wires, reg_ct;
@@ -126,6 +126,33 @@ std::string id(RTLIL::IdString internal_id, bool may_rename = true)
break;
}
+ const pool<string> keywords = {
+ // IEEE 1800-2017 Annex B
+ "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before",
+ "begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle",
+ "checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint",
+ "cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker",
+ "endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage",
+ "endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually",
+ "expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function",
+ "generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies",
+ "import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface",
+ "intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint",
+ "macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor",
+ "noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive",
+ "priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent",
+ "pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat",
+ "restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until",
+ "s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify",
+ "specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on",
+ "sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1",
+ "tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with",
+ "untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while",
+ "wildcard", "wire", "with", "within", "wor", "xnor", "xor",
+ };
+ if (keywords.count(str))
+ do_escape = true;
+
if (do_escape)
return "\\" + std::string(str) + " ";
return std::string(str);
@@ -156,10 +183,15 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
return true;
}
-void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false)
+void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool escape_comment = false)
{
+ bool set_signed = (data.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
if (width < 0)
width = data.bits.size() - offset;
+ if (width == 0) {
+ f << "\"\"";
+ return;
+ }
if (nostr)
goto dump_hex;
if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
@@ -244,7 +276,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
}
}
} else {
- f << stringf("\"");
+ if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
+ f << stringf("\"");
std::string str = data.decode_string();
for (size_t i = 0; i < str.size(); i++) {
if (str[i] == '\n')
@@ -262,7 +295,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
else
f << str[i];
}
- f << stringf("\"");
+ if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
+ f << stringf("\"");
}
}
@@ -313,6 +347,10 @@ void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decima
void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
{
+ if (GetSize(sig) == 0) {
+ f << "\"\"";
+ return;
+ }
if (sig.is_chunk()) {
dump_sigchunk(f, sig.as_chunk());
} else {
@@ -326,20 +364,22 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
}
}
-void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n', bool modattr = false)
+void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n', bool modattr = false, bool as_comment = false)
{
if (noattr)
return;
+ if (attr2comment)
+ as_comment = true;
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
- f << stringf("%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
+ f << stringf("%s" "%s %s", indent.c_str(), as_comment ? "/*" : "(*", id(it->first).c_str());
f << stringf(" = ");
if (modattr && (it->second == Const(0, 1) || it->second == Const(0)))
f << stringf(" 0 ");
else if (modattr && (it->second == Const(1, 1) || it->second == Const(1)))
f << stringf(" 1 ");
else
- dump_const(f, it->second, -1, 0, false, false, attr2comment);
- f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
+ dump_const(f, it->second, -1, 0, false, as_comment);
+ f << stringf(" %s%c", as_comment ? "*/" : "*)", term);
}
}
@@ -388,7 +428,7 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
void dump_memory(std::ostream &f, std::string indent, RTLIL::Memory *memory)
{
dump_attributes(f, indent, memory->attributes);
- f << stringf("%s" "reg [%d:0] %s [%d:0];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size-1);
+ f << stringf("%s" "reg [%d:0] %s [%d:%d];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size+memory->start_offset-1, memory->start_offset);
}
void dump_cell_expr_port(std::ostream &f, RTLIL::Cell *cell, std::string port, bool gen_signed = true)
@@ -678,13 +718,45 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
#undef HANDLE_UNIOP
#undef HANDLE_BINOP
- if (cell->type == "$shiftx")
+ if (cell->type == "$shift")
{
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, cell->getPort("\\Y"));
f << stringf(" = ");
+ if (cell->getParam("\\B_SIGNED").as_bool())
+ {
+ f << stringf("$signed(");
+ dump_sigspec(f, cell->getPort("\\B"));
+ f << stringf(")");
+ f << stringf(" < 0 ? ");
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(" << - ");
+ dump_sigspec(f, cell->getPort("\\B"));
+ f << stringf(" : ");
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(" >> ");
+ dump_sigspec(f, cell->getPort("\\B"));
+ }
+ else
+ {
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(" >> ");
+ dump_sigspec(f, cell->getPort("\\B"));
+ }
+ f << stringf(";\n");
+ return true;
+ }
+
+ if (cell->type == "$shiftx")
+ {
+ std::string temp_id = next_auto_id();
+ f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort("\\A"))-1, temp_id.c_str());
dump_sigspec(f, cell->getPort("\\A"));
- f << stringf("[");
+ f << stringf(";\n");
+
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = %s[", temp_id.c_str());
if (cell->getParam("\\B_SIGNED").as_bool())
f << stringf("$signed(");
dump_sigspec(f, cell->getPort("\\B"));
@@ -757,6 +829,18 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
+ if (cell->type == "$tribuf")
+ {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = ");
+ dump_sigspec(f, cell->getPort("\\EN"));
+ f << stringf(" ? ");
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(" : %d'bz;\n", cell->parameters.at("\\WIDTH").as_int());
+ return true;
+ }
+
if (cell->type == "$slice")
{
f << stringf("%s" "assign ", indent.c_str());
@@ -952,6 +1036,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
std::string mem_id = id(cell->parameters["\\MEMID"].decode_string());
int abits = cell->parameters["\\ABITS"].as_int();
int size = cell->parameters["\\SIZE"].as_int();
+ int offset = cell->parameters["\\OFFSET"].as_int();
int width = cell->parameters["\\WIDTH"].as_int();
bool use_init = !(RTLIL::SigSpec(cell->parameters["\\INIT"]).is_fully_undef());
@@ -960,7 +1045,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
// initial begin
// memid[0] = ...
// end
- f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size-1, 0);
+ f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size+offset-1, offset);
if (use_init)
{
f << stringf("%s" "initial begin\n", indent.c_str());
@@ -993,43 +1078,46 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool();
rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool();
rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool();
+ if (use_rd_clk)
{
- std::ostringstream os;
- dump_sigspec(os, sig_rd_clk);
- clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
- if( clk_to_lof_body.count(clk_domain_str) == 0 )
- clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
- }
- if (use_rd_clk && !rd_transparent)
- {
- // for clocked read ports make something like:
- // reg [..] temp_id;
- // always @(posedge clk)
- // if (rd_en) temp_id <= array_reg[r_addr];
- // assign r_data = temp_id;
- std::string temp_id = next_auto_id();
- lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
{
std::ostringstream os;
- if (sig_rd_en != RTLIL::SigBit(true))
+ dump_sigspec(os, sig_rd_clk);
+ clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
+ if( clk_to_lof_body.count(clk_domain_str) == 0 )
+ clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
+ }
+ if (!rd_transparent)
+ {
+ // for clocked read ports make something like:
+ // reg [..] temp_id;
+ // always @(posedge clk)
+ // if (rd_en) temp_id <= array_reg[r_addr];
+ // assign r_data = temp_id;
+ std::string temp_id = next_auto_id();
+ lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
+ {
+ std::ostringstream os;
+ if (sig_rd_en != RTLIL::SigBit(true))
+ {
+ os << stringf("if (");
+ dump_sigspec(os, sig_rd_en);
+ os << stringf(") ");
+ }
+ os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
+ dump_sigspec(os, sig_rd_addr);
+ os << stringf("];\n");
+ clk_to_lof_body[clk_domain_str].push_back(os.str());
+ }
{
- os << stringf("if (");
- dump_sigspec(os, sig_rd_en);
- os << stringf(") ");
+ std::ostringstream os;
+ dump_sigspec(os, sig_rd_data);
+ std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
+ clk_to_lof_body[""].push_back(line);
}
- os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
- dump_sigspec(os, sig_rd_addr);
- os << stringf("];\n");
- clk_to_lof_body[clk_domain_str].push_back(os.str());
}
+ else
{
- std::ostringstream os;
- dump_sigspec(os, sig_rd_data);
- std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
- clk_to_lof_body[""].push_back(line);
- }
- } else {
- if (rd_transparent) {
// for rd-transparent read-ports make something like:
// reg [..] temp_id;
// always @(posedge clk)
@@ -1049,15 +1137,15 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), temp_id.c_str());
clk_to_lof_body[""].push_back(line);
}
- } else {
- // for non-clocked read-ports make something like:
- // assign r_data = array_reg[r_addr];
- std::ostringstream os, os2;
- dump_sigspec(os, sig_rd_data);
- dump_sigspec(os2, sig_rd_addr);
- std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
- clk_to_lof_body[""].push_back(line);
}
+ } else {
+ // for non-clocked read-ports make something like:
+ // assign r_data = array_reg[r_addr];
+ std::ostringstream os, os2;
+ dump_sigspec(os, sig_rd_data);
+ dump_sigspec(os2, sig_rd_addr);
+ std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
+ clk_to_lof_body[""].push_back(line);
}
}
@@ -1159,6 +1247,118 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
+ if (cell->type.in("$assert", "$assume", "$cover"))
+ {
+ f << stringf("%s" "always @* if (", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\EN"));
+ f << stringf(") %s(", cell->type.c_str()+1);
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(");\n");
+ return true;
+ }
+
+ if (cell->type.in("$specify2", "$specify3"))
+ {
+ f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
+
+ SigSpec en = cell->getPort("\\EN");
+ if (en != State::S1) {
+ f << stringf("if (");
+ dump_sigspec(f, cell->getPort("\\EN"));
+ f << stringf(") ");
+ }
+
+ f << "(";
+ if (cell->type == "$specify3" && cell->getParam("\\EDGE_EN").as_bool())
+ f << (cell->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
+
+ dump_sigspec(f, cell->getPort("\\SRC"));
+
+ f << " ";
+ if (cell->getParam("\\SRC_DST_PEN").as_bool())
+ f << (cell->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
+ f << (cell->getParam("\\FULL").as_bool() ? "*> ": "=> ");
+
+ if (cell->type == "$specify3") {
+ f << "(";
+ dump_sigspec(f, cell->getPort("\\DST"));
+ f << " ";
+ if (cell->getParam("\\DAT_DST_PEN").as_bool())
+ f << (cell->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
+ f << ": ";
+ dump_sigspec(f, cell->getPort("\\DAT"));
+ f << ")";
+ } else {
+ dump_sigspec(f, cell->getPort("\\DST"));
+ }
+
+ bool bak_decimal = decimal;
+ decimal = 1;
+
+ f << ") = (";
+ dump_const(f, cell->getParam("\\T_RISE_MIN"));
+ f << ":";
+ dump_const(f, cell->getParam("\\T_RISE_TYP"));
+ f << ":";
+ dump_const(f, cell->getParam("\\T_RISE_MAX"));
+ f << ", ";
+ dump_const(f, cell->getParam("\\T_FALL_MIN"));
+ f << ":";
+ dump_const(f, cell->getParam("\\T_FALL_TYP"));
+ f << ":";
+ dump_const(f, cell->getParam("\\T_FALL_MAX"));
+ f << ");\n";
+
+ decimal = bak_decimal;
+
+ f << stringf("%s" "endspecify\n", indent.c_str());
+ return true;
+ }
+
+ if (cell->type == "$specrule")
+ {
+ f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
+
+ string spec_type = cell->getParam("\\TYPE").decode_string();
+ f << stringf("%s(", spec_type.c_str());
+
+ if (cell->getParam("\\SRC_PEN").as_bool())
+ f << (cell->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
+ dump_sigspec(f, cell->getPort("\\SRC"));
+
+ if (cell->getPort("\\SRC_EN") != State::S1) {
+ f << " &&& ";
+ dump_sigspec(f, cell->getPort("\\SRC_EN"));
+ }
+
+ f << ", ";
+ if (cell->getParam("\\DST_PEN").as_bool())
+ f << (cell->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
+ dump_sigspec(f, cell->getPort("\\DST"));
+
+ if (cell->getPort("\\DST_EN") != State::S1) {
+ f << " &&& ";
+ dump_sigspec(f, cell->getPort("\\DST_EN"));
+ }
+
+ bool bak_decimal = decimal;
+ decimal = 1;
+
+ f << ", ";
+ dump_const(f, cell->getParam("\\T_LIMIT"));
+
+ if (spec_type == "$setuphold" || spec_type == "$recrem" || spec_type == "$fullskew") {
+ f << ", ";
+ dump_const(f, cell->getParam("\\T_LIMIT2"));
+ }
+
+ f << ");\n";
+ decimal = bak_decimal;
+
+ f << stringf("%s" "endspecify\n", indent.c_str());
+ return true;
+ }
+
// FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
// FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
@@ -1181,8 +1381,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (it != cell->parameters.begin())
f << stringf(",");
f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
- bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
- dump_const(f, it->second, -1, 0, false, is_signed);
+ dump_const(f, it->second);
f << stringf(")");
}
f << stringf("\n%s" ")", indent.c_str());
@@ -1229,12 +1428,20 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (defparam && cell->parameters.size() > 0) {
for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str());
- bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
- dump_const(f, it->second, -1, 0, false, is_signed);
+ dump_const(f, it->second);
f << stringf(";\n");
}
}
+ if (siminit && reg_ct.count(cell->type) && cell->hasPort("\\Q")) {
+ std::stringstream ss;
+ dump_reg_init(ss, cell->getPort("\\Q"));
+ if (!ss.str().empty()) {
+ f << stringf("%sinitial %s.Q", indent.c_str(), cell_name.c_str());
+ f << ss.str();
+ f << ";\n";
+ }
+ }
}
void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
@@ -1287,12 +1494,14 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
return;
}
+ dump_attributes(f, indent, sw->attributes);
f << stringf("%s" "casez (", indent.c_str());
dump_sigspec(f, sw->signal);
f << stringf(")\n");
bool got_default = false;
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
+ dump_attributes(f, indent + " ", (*it)->attributes, '\n', /*modattr=*/false, /*as_comment=*/true);
if ((*it)->compare.size() == 0) {
if (got_default)
continue;
@@ -1351,6 +1560,8 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
if (sync->type == RTLIL::STa) {
f << stringf("%s" "always @* begin\n", indent.c_str());
+ } else if (sync->type == RTLIL::STi) {
+ f << stringf("%s" "initial begin\n", indent.c_str());
} else {
f << stringf("%s" "always @(", indent.c_str());
if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
@@ -1411,14 +1622,15 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
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 (val[i] == State::S0 || val[i] == State::S1)
+ active_initdata[sig[i]] = val[i];
}
if (!module->processes.empty())
log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
"can't always be mapped directly to Verilog always blocks. Unintended\n"
"changes in simulation behavior are possible! Use \"proc\" to convert\n"
- "processes to logic networks and registers.", log_id(module));
+ "processes to logic networks and registers.\n", log_id(module));
f << stringf("\n");
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
@@ -1454,7 +1666,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
}
}
- dump_attributes(f, indent, module->attributes, '\n', true);
+ dump_attributes(f, indent, module->attributes, '\n', /*attr2comment=*/true);
f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
bool keep_running = true;
for (int port_id = 1; keep_running; port_id++) {
@@ -1521,6 +1733,10 @@ struct VerilogBackend : public Backend {
log(" without this option all internal cells are converted to Verilog\n");
log(" expressions.\n");
log("\n");
+ log(" -siminit\n");
+ log(" add initial statements with hierarchical refs to initialize FFs when\n");
+ log(" in -noexpr mode.\n");
+ log("\n");
log(" -nodec\n");
log(" 32-bit constant values are by default dumped as decimal numbers,\n");
log(" not bit pattern. This option deactivates this feature and instead\n");
@@ -1577,11 +1793,14 @@ struct VerilogBackend : public Backend {
nostr = false;
defparam = false;
decimal = false;
+ siminit = false;
auto_prefix = "";
bool blackboxes = false;
bool selected = false;
+ auto_name_map.clear();
+ reg_wires.clear();
reg_ct.clear();
reg_ct.insert("$dff");
@@ -1653,6 +1872,10 @@ struct VerilogBackend : public Backend {
decimal = true;
continue;
}
+ if (arg == "-siminit") {
+ siminit = true;
+ continue;
+ }
if (arg == "-blackboxes") {
blackboxes = true;
continue;
@@ -1673,7 +1896,7 @@ struct VerilogBackend : public Backend {
*f << stringf("/* Generated by %s */\n", yosys_version_str);
for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
- if (it->second->get_bool_attribute("\\blackbox") != blackboxes)
+ if (it->second->get_blackbox_attribute() != blackboxes)
continue;
if (selected && !design->selected_whole_module(it->first)) {
if (design->selected_module(it->first))
@@ -1684,6 +1907,8 @@ struct VerilogBackend : public Backend {
dump_module(*f, "", it->second);
}
+ auto_name_map.clear();
+ reg_wires.clear();
reg_ct.clear();
}
} VerilogBackend;
diff --git a/debian/changelog b/debian/changelog
index 3c7b1cd3..ce294daa 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,33 @@
+yosys (0.9-1) unstable; urgency=medium
+
+ * Upload to sid
+ * New upstream release
+ - Refreshed patches
+ * debian/copyright:
+ - Get copyright info up-to-date
+ * debian/control:
+ - New standards version 4.4.0 - no changes
+ - DH level 12
+ - Use debhelper-compat instead of debian/compat file
+ - Change build-dependency from texlive-generic-recommended to
+ texlive-plain-generic (Closes: #941555) (Thanks Steve Langasek)
+ * debian/rules:
+ - Don't override dh_install with --fail-missing anymore
+
+ -- Ruben Undheim <ruben.undheim@gmail.com> Fri, 18 Oct 2019 23:27:34 +0200
+
+yosys (0.8+20190328git32bd0f2-1~exp1) experimental; urgency=low
+
+ * New upstream GIT HEAD
+ * debian/control:
+ - New standards version 4.3.0 - no changes
+ * debian/copyright:
+ - Added new copyright holders
+ * debian/patches: Refreshed patches
+ * debian/yosys.install: Install more files
+
+ -- Ruben Undheim <ruben.undheim@gmail.com> Sun, 31 Mar 2019 00:01:48 +0100
+
yosys (0.8-1) unstable; urgency=medium
* New upstream release
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index b4de3947..00000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-11
diff --git a/debian/control b/debian/control
index 47afaa77..d3ea7737 100644
--- a/debian/control
+++ b/debian/control
@@ -4,7 +4,7 @@ Uploaders: Ruben Undheim <ruben.undheim@gmail.com>,
Sebastian Kuzminsky <seb@highlab.com>
Section: electronics
Priority: optional
-Build-Depends: debhelper (>= 11),
+Build-Depends: debhelper-compat (= 12),
dh-python,
tcl-dev,
libreadline-dev,
@@ -19,7 +19,7 @@ Build-Depends: debhelper (>= 11),
berkeley-abc (>= 1.01+20161002hgeb6eca6+dfsg)
Build-Depends-Indep:
texlive-base,
- texlive-generic-recommended,
+ texlive-plain-generic,
texlive-fonts-recommended,
texlive-fonts-extra,
texlive-latex-base,
@@ -30,7 +30,7 @@ Build-Depends-Indep:
texlive-bibtex-extra,
lmodern,
graphviz
-Standards-Version: 4.2.1
+Standards-Version: 4.4.0
Vcs-Browser: https://salsa.debian.org/science-team/yosys
Vcs-Git: https://salsa.debian.org/science-team/yosys.git
Homepage: http://www.clifford.at/yosys
diff --git a/debian/copyright b/debian/copyright
index 1e61f307..f1f2a135 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -3,7 +3,7 @@ Upstream-Name: yosys
Source: http://www.clifford.at/yosys/
Files: *
-Copyright: 2012-2018 Clifford Wolf <clifford@clifford.at>
+Copyright: 2012-2019 Clifford Wolf <clifford@clifford.at>
License: ISC
Files: backends/btor/btor.cc
@@ -26,8 +26,33 @@ License: ISC
Files: passes/techmap/dff2dffs.cc
techlibs/ecp5/arith_map.v
techlibs/ecp5/synth_ecp5.cc
+ techlibs/ecp5/ecp5_ffinit.cc
+ techlibs/gowin/arith_map.v
Copyright: 2012 Clifford Wolf <clifford@clifford.at>
- 2018 David Shah <dave@ds0.me>
+ 2018-2019 David Shah <dave@ds0.me>
+License: ISC
+
+Files: frontends/aiger/aigerparse.*
+Copyright: 2012 Clifford Wolf <clifford@clifford.at>
+ 2012 Eddie Hung <eddie@fpgeh.com>
+License: ISC
+
+Files: frontends/ast/ast.cc
+ passes/hierarchy/hierarchy.cc
+Copyright: 2012 Clifford Wolf <clifford@clifford.at>
+ 2018 Ruben Undheim <ruben.undheim@gmail.com>
+License: ISC
+
+Files: passes/opt/muxpack.cc
+Copyright: 2012 Clifford Wolf <clifford@clifford.at>
+ 2019 Eddie Hung <eddie@fpgeh.com>
+License: ISC
+
+Files: passes/cmds/bugpoint.cc
+ passes/equiv/equiv_opt.cc
+ passes/opt/opt_lut.cc
+ passes/techmap/flowmap.cc
+Copyright: 2018 whitequark <whitequark@whitequark.org>
License: ISC
Files: passes/techmap/extract_reduce.cc
@@ -35,6 +60,16 @@ Files: passes/techmap/extract_reduce.cc
Copyright: 2017 Robert Ou <rqou@robertou.com>
License: ISC
+Files: techlibs/anlogic/anlogic_determine_init.c
+ techlibs/anlogic/anlogic_eqn.cc
+ techlibs/anlogic/arith_map.v
+ techlibs/anlogic/synth_anlogic.cc
+ techlibs/gowin/determine_init.cc
+Copyright: 2012,2018 Clifford Wolf <clifford@clifford.at
+ 2018 Icenowy Zheng <icenowy@aosc.io>
+ 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+License: ISC
+
Files: misc/yosys.proto
Copyright: 2018 Serge Bazanski <q3k@symbioticeda.com>
License: ISC
@@ -51,6 +86,10 @@ Copyright: Steve Reid <steve@edmweb.com>
License: Public-Domain
These files are in the public domain.
+Files: misc/launcher.c
+Copyright: 2016 Jason R Coombs <jaraco@jaraco.com>
+License: MIT
+
Files: manual/CHAPTER_StateOfTheArt/simlib_hana.v
tests/hana/hana_vlib.v
Copyright: 2009-2010 Parvez Ahmad <parvez_ahmad@yahoo.co.uk>
@@ -67,7 +106,7 @@ Copyright: 2010 Conor Santifort <csantifort.amber@gmail.com>
License: LGPL-2.1+
Files: debian/*
-Copyright: 2014-2016,2018 Ruben Undheim <ruben.undheim@gmail.com>
+Copyright: 2014-2016,2018-2019 Ruben Undheim <ruben.undheim@gmail.com>
2016 Sebastian Kuzminsky <seb@highlab.com>
License: GPL-2+
diff --git a/debian/patches/0007-Disable-pretty-build.patch b/debian/patches/0007-Disable-pretty-build.patch
index c115f66b..03269c47 100644
--- a/debian/patches/0007-Disable-pretty-build.patch
+++ b/debian/patches/0007-Disable-pretty-build.patch
@@ -7,10 +7,10 @@ Subject: Disable pretty build
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
-index f357258..13b19ce 100644
+index da1b73f..065f4f2 100644
--- a/Makefile
+++ b/Makefile
-@@ -52,7 +52,7 @@ EXTRA_OBJS =
+@@ -61,7 +61,7 @@ EXTRA_OBJS =
EXTRA_TARGETS =
TARGETS = yosys$(EXE) yosys-config
diff --git a/debian/patches/0009-Some-spelling-errors-fixed.patch b/debian/patches/0009-Some-spelling-errors-fixed.patch
index 40cc827a..339c2da3 100644
--- a/debian/patches/0009-Some-spelling-errors-fixed.patch
+++ b/debian/patches/0009-Some-spelling-errors-fixed.patch
@@ -3,83 +3,26 @@ Date: Thu, 12 Jul 2018 13:41:39 +0200
Subject: Some spelling errors fixed
---
- backends/simplec/simplec.cc | 2 +-
- backends/table/table.cc | 2 +-
- backends/verilog/verilog_backend.cc | 2 +-
- frontends/blif/blifparse.cc | 2 +-
- frontends/liberty/liberty.cc | 2 +-
+ frontends/ast/genrtlil.cc | 2 +-
manual/CHAPTER_Overview.tex | 2 +-
manual/command-reference-manual.tex | 2 +-
- passes/cmds/show.cc | 2 +-
- 8 files changed, 8 insertions(+), 8 deletions(-)
+ 3 files changed, 3 insertions(+), 3 deletions(-)
-diff --git a/backends/simplec/simplec.cc b/backends/simplec/simplec.cc
-index 349bc5a..6f2ccbe 100644
---- a/backends/simplec/simplec.cc
-+++ b/backends/simplec/simplec.cc
-@@ -748,7 +748,7 @@ struct SimplecBackend : public Backend {
- log("\n");
- log(" write_simplec [options] [filename]\n");
- log("\n");
-- log("Write simple C code for simulating the design. The C code writen can be used to\n");
-+ log("Write simple C code for simulating the design. The C code written can be used to\n");
- log("simulate the design in a C environment, but the purpose of this command is to\n");
- log("generate code that works well with C-based formal verification.\n");
- log("\n");
-diff --git a/backends/table/table.cc b/backends/table/table.cc
-index 979273d..b75169e 100644
---- a/backends/table/table.cc
-+++ b/backends/table/table.cc
-@@ -109,7 +109,7 @@ struct TableBackend : public Backend {
- else if (cell->output(conn.first))
- *f << "out" << "\t";
- else
-- *f << "unkown" << "\t";
-+ *f << "unknown" << "\t";
-
- *f << log_signal(sigmap(conn.second)) << "\n";
- }
-diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
-index ae90315..d53df2e 100644
---- a/backends/verilog/verilog_backend.cc
-+++ b/backends/verilog/verilog_backend.cc
-@@ -1415,7 +1415,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
- }
-
- if (!module->processes.empty())
-- log_warning("Module %s contains unmapped RTLIL proccesses. RTLIL processes\n"
-+ log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
- "can't always be mapped directly to Verilog always blocks. Unintended\n"
- "changes in simulation behavior are possible! Use \"proc\" to convert\n"
- "processes to logic networks and registers.", log_id(module));
-diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc
-index 034b3e7..9116b25 100644
---- a/frontends/blif/blifparse.cc
-+++ b/frontends/blif/blifparse.cc
-@@ -276,7 +276,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
-
- if(lastcell == nullptr || module == nullptr)
- {
-- err_reason = stringf("No primative object to attach .cname %s.", p);
-+ err_reason = stringf("No primitive object to attach .cname %s.", p);
- goto error_with_reason;
- }
-
-diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc
-index 0a5bd84..e90c87a 100644
---- a/frontends/liberty/liberty.cc
-+++ b/frontends/liberty/liberty.cc
-@@ -615,7 +615,7 @@ struct LibertyFrontend : public Frontend {
- LibertyAst *bus_type_node = node->find("bus_type");
-
- if (!bus_type_node || !type_map.count(bus_type_node->value))
-- log_error("Unkown or unsupported type for bus interface %s on cell %s.\n",
-+ log_error("Unknown or unsupported type for bus interface %s on cell %s.\n",
- node->args.at(0).c_str(), log_id(cell_name));
-
- int bus_type_width = std::get<0>(type_map.at(bus_type_node->value));
+diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
+index 571ddd9..cee344a 100644
+--- a/frontends/ast/genrtlil.cc
++++ b/frontends/ast/genrtlil.cc
+@@ -558,7 +558,7 @@ struct AST_INTERNAL::ProcessGenerator
+ break;
+
+ case AST_ASSIGN:
+- log_file_error(ast->filename, ast->linenum, "Found continous assignment in always/initial block!\n");
++ log_file_error(ast->filename, ast->linenum, "Found continuous assignment in always/initial block!\n");
+ break;
+
+ case AST_PARAMETER:
diff --git a/manual/CHAPTER_Overview.tex b/manual/CHAPTER_Overview.tex
-index 964875d..ae5cf09 100644
+index 3009bf2..4136efe 100644
--- a/manual/CHAPTER_Overview.tex
+++ b/manual/CHAPTER_Overview.tex
@@ -240,7 +240,7 @@ An RTLIL::Wire object has the following properties:
@@ -104,16 +47,3 @@ index bed6326..eb43467 100644
-signed
mark ports (A, B) that are declared as signed (using the [AB]_SIGNED
-diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
-index a488732..58acd30 100644
---- a/passes/cmds/show.cc
-+++ b/passes/cmds/show.cc
-@@ -623,7 +623,7 @@ struct ShowPass : public Pass {
- log(" assigned to each unique value of this attribute.\n");
- log("\n");
- log(" -width\n");
-- log(" annotate busses with a label indicating the width of the bus.\n");
-+ log(" annotate buses with a label indicating the width of the bus.\n");
- log("\n");
- log(" -signed\n");
- log(" mark ports (A, B) that are declared as signed (using the [AB]_SIGNED\n");
diff --git a/debian/patches/0010-Fix-adding-of-sys.path-in-yosys-smtbmc.patch b/debian/patches/0010-Fix-adding-of-sys.path-in-yosys-smtbmc.patch
index 0b46c4a0..5d37598f 100644
--- a/debian/patches/0010-Fix-adding-of-sys.path-in-yosys-smtbmc.patch
+++ b/debian/patches/0010-Fix-adding-of-sys.path-in-yosys-smtbmc.patch
@@ -7,10 +7,10 @@ Subject: Fix adding of sys.path in yosys-smtbmc
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc
-index dce82f0..f98e610 100644
+index 92941d4..2c0b7c6 100644
--- a/backends/smt2/Makefile.inc
+++ b/backends/smt2/Makefile.inc
-@@ -6,7 +6,7 @@ ifneq ($(CONFIG),emcc)
+@@ -22,7 +22,7 @@ else
TARGETS += yosys-smtbmc
yosys-smtbmc: backends/smt2/smtbmc.py
@@ -18,4 +18,4 @@ index dce82f0..f98e610 100644
+ $(P) sed 's|##yosys-sys-path##|sys.path += ["/usr/share/yosys"]|;' < $< > $@.new
$(Q) chmod +x $@.new
$(Q) mv $@.new $@
-
+ endif
diff --git a/debian/patches/0010-Fix-reproducibility-of-PDF-documents-in-yosys-doc.patch b/debian/patches/0010-Fix-reproducibility-of-PDF-documents-in-yosys-doc.patch
index aa77fe92..2f16462a 100644
--- a/debian/patches/0010-Fix-reproducibility-of-PDF-documents-in-yosys-doc.patch
+++ b/debian/patches/0010-Fix-reproducibility-of-PDF-documents-in-yosys-doc.patch
@@ -11,10 +11,10 @@ Subject: Fix reproducibility of PDF documents in yosys-doc
5 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/Makefile b/Makefile
-index 13b19ce..e7a9de1 100644
+index 065f4f2..8608472 100644
--- a/Makefile
+++ b/Makefile
-@@ -638,9 +638,9 @@ update-manual: $(TARGETS) $(EXTRA_TARGETS)
+@@ -766,9 +766,9 @@ update-manual: $(TARGETS) $(EXTRA_TARGETS)
cd manual && ../yosys -p 'help -write-tex-command-reference-manual'
manual: $(TARGETS) $(EXTRA_TARGETS)
diff --git a/debian/patches/0011-Do-not-show-g-build-flags-in-Version-string.patch b/debian/patches/0011-Do-not-show-g-build-flags-in-Version-string.patch
index b72651db..00e41f64 100644
--- a/debian/patches/0011-Do-not-show-g-build-flags-in-Version-string.patch
+++ b/debian/patches/0011-Do-not-show-g-build-flags-in-Version-string.patch
@@ -7,10 +7,10 @@ Subject: Do not show g++ build flags in Version string
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
-index e7a9de1..5c381ff 100644
+index 8608472..1f8d5a2 100644
--- a/Makefile
+++ b/Makefile
-@@ -504,8 +504,7 @@ libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
+@@ -612,8 +612,7 @@ endif
$(Q) mkdir -p $(dir $@)
$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $<
@@ -20,7 +20,7 @@ index e7a9de1..5c381ff 100644
kernel/version_$(GIT_REV).cc: $(YOSYS_SRC)/Makefile
$(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc
-@@ -519,8 +518,10 @@ CXXFLAGS_NOVERIFIC = $(CXXFLAGS)
+@@ -627,8 +626,10 @@ CXXFLAGS_NOVERIFIC = $(CXXFLAGS)
LDLIBS_NOVERIFIC = $(LDLIBS)
endif
diff --git a/debian/patches/0012-Skip-non-deterministic-test-causing-random-FTBFS-on-.patch b/debian/patches/0012-Skip-non-deterministic-test-causing-random-FTBFS-on-.patch
index 18ba0e17..9d54763a 100644
--- a/debian/patches/0012-Skip-non-deterministic-test-causing-random-FTBFS-on-.patch
+++ b/debian/patches/0012-Skip-non-deterministic-test-causing-random-FTBFS-on-.patch
@@ -8,14 +8,14 @@ Subject: Skip non-deterministic test causing random FTBFS on some
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
-index 5c381ff..b169eb7 100644
+index 1f8d5a2..6801a59 100644
--- a/Makefile
+++ b/Makefile
-@@ -566,7 +566,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+@@ -680,7 +680,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/simple && bash run-test.sh $(SEEDOPT)
+cd tests/hana && bash run-test.sh $(SEEDOPT)
+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
-- +cd tests/realmath && bash run-test.sh $(SEEDOPT)
+- # +cd tests/realmath && bash run-test.sh $(SEEDOPT)
+ #+cd tests/realmath && bash run-test.sh $(SEEDOPT)
+cd tests/share && bash run-test.sh $(SEEDOPT)
+cd tests/fsm && bash run-test.sh $(SEEDOPT)
diff --git a/debian/patches/0013-Let-dpkg-buildpackage-handle-stripping-of-binaries.patch b/debian/patches/0013-Let-dpkg-buildpackage-handle-stripping-of-binaries.patch
index 2389eb85..a62c7d26 100644
--- a/debian/patches/0013-Let-dpkg-buildpackage-handle-stripping-of-binaries.patch
+++ b/debian/patches/0013-Let-dpkg-buildpackage-handle-stripping-of-binaries.patch
@@ -7,10 +7,10 @@ Subject: Let dpkg-buildpackage handle stripping of binaries
1 file changed, 4 deletions(-)
diff --git a/Makefile b/Makefile
-index b169eb7..961e2ce 100644
+index 6801a59..0a75c58 100644
--- a/Makefile
+++ b/Makefile
-@@ -612,19 +612,15 @@ install: $(TARGETS) $(EXTRA_TARGETS)
+@@ -730,20 +730,16 @@ install: $(TARGETS) $(EXTRA_TARGETS)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
$(INSTALL_SUDO) cp $(TARGETS) $(DESTDIR)$(BINDIR)
ifneq ($(filter yosys,$(TARGETS)),)
@@ -25,8 +25,9 @@ index b169eb7..961e2ce 100644
$(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) mkdir -p $(DESTDIR)$(LIBDIR)
+ $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
- $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so
- $(INSTALL_SUDO) ldconfig
- endif
-
+ ifeq ($(ENABLE_PYOSYS),1)
+ $(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys
+ $(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys/
diff --git a/debian/patches/0014-Set-path-to-berkeley-abc-instead-of-relative-path-to.patch b/debian/patches/0014-Set-path-to-berkeley-abc-instead-of-relative-path-to.patch
new file mode 100644
index 00000000..89a5f71b
--- /dev/null
+++ b/debian/patches/0014-Set-path-to-berkeley-abc-instead-of-relative-path-to.patch
@@ -0,0 +1,35 @@
+From: Ruben Undheim <ruben.undheim@gmail.com>
+Date: Fri, 18 Oct 2019 20:49:35 +0000
+Subject: Set path to berkeley-abc instead of relative path to yosys-abc
+
+---
+ tests/aiger/run-test.sh | 2 +-
+ tests/tools/autotest.sh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/tests/aiger/run-test.sh b/tests/aiger/run-test.sh
+index deaf48a..4fbffcd 100755
+--- a/tests/aiger/run-test.sh
++++ b/tests/aiger/run-test.sh
+@@ -3,7 +3,7 @@
+ set -e
+
+ OPTIND=1
+-abcprog="../../yosys-abc" # default to built-in version of abc
++abcprog="berkeley-abc" # default to built-in version of abc
+ while getopts "A:" opt
+ do
+ case "$opt" in
+diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh
+index 4d34786..6bece9b 100755
+--- a/tests/tools/autotest.sh
++++ b/tests/tools/autotest.sh
+@@ -23,7 +23,7 @@ warn_iverilog_git=false
+ # The tests are skipped if firrtl2verilog is the empty string (the default).
+ firrtl2verilog=""
+ xfirrtl="../xfirrtl"
+-abcprog="$toolsdir/../../yosys-abc"
++abcprog="berkeley-abc"
+
+ if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then
+ ( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1
diff --git a/debian/patches/01_gitrevision.patch b/debian/patches/01_gitrevision.patch
index 8e3b5352..222d1363 100644
--- a/debian/patches/01_gitrevision.patch
+++ b/debian/patches/01_gitrevision.patch
@@ -11,15 +11,15 @@ Forwarded: doesn't make sense upstream
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
-index d759b11..c92c808 100644
+index a673154..d779dc0 100644
--- a/Makefile
+++ b/Makefile
-@@ -100,7 +100,7 @@ LDLIBS += -lrt
+@@ -115,7 +115,7 @@ LDLIBS += -lrt
endif
- YOSYS_VER := 0.8
+ YOSYS_VER := 0.9
-GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
-+GIT_REV := 5706e90
++GIT_REV := 1979e0b
OBJS = kernel/version_$(GIT_REV).o
# set 'ABCREV = default' to use abc/ as it is
diff --git a/debian/patches/02_removeabc.patch b/debian/patches/02_removeabc.patch
index 4ef26c8c..e1cb8ca5 100644
--- a/debian/patches/02_removeabc.patch
+++ b/debian/patches/02_removeabc.patch
@@ -9,10 +9,10 @@ Forwarded: doesn't make sense upstream
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
-index c92c808..f357258 100644
+index d779dc0..da1b73f 100644
--- a/Makefile
+++ b/Makefile
-@@ -350,7 +350,7 @@ LDLIBS += -lpthread
+@@ -440,7 +440,7 @@ LDLIBS += -lpthread
endif
else
ifeq ($(ABCEXTERNAL),)
diff --git a/debian/patches/05_abc_executable.patch b/debian/patches/05_abc_executable.patch
index b4a97529..ef774d46 100644
--- a/debian/patches/05_abc_executable.patch
+++ b/debian/patches/05_abc_executable.patch
@@ -11,10 +11,10 @@ Forwarded: doesn't make sense upstream
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
-index d2d15a4..adc9614 100644
+index bf05c68..75daaa6 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
-@@ -1432,11 +1432,7 @@ struct AbcPass : public Pass {
+@@ -1472,11 +1472,7 @@ struct AbcPass : public Pass {
pi_map.clear();
po_map.clear();
diff --git a/debian/patches/kfreebsd-support.patch b/debian/patches/kfreebsd-support.patch
index d1ae9201..3f8938be 100644
--- a/debian/patches/kfreebsd-support.patch
+++ b/debian/patches/kfreebsd-support.patch
@@ -16,7 +16,7 @@ Subject: Change yosys to look for the #define constant "__unix__" instead of
6 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/kernel/driver.cc b/kernel/driver.cc
-index 1786411..8b328e5 100644
+index f273057..edec776 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -34,7 +34,7 @@
@@ -28,7 +28,7 @@ index 1786411..8b328e5 100644
# include <sys/resource.h>
# include <sys/types.h>
# include <unistd.h>
-@@ -449,7 +449,7 @@ int main(int argc, char **argv)
+@@ -466,7 +466,7 @@ int main(int argc, char **argv)
if (print_stats)
log_hasher = new SHA1;
@@ -37,7 +37,7 @@ index 1786411..8b328e5 100644
// set stack size to >= 128 MB
{
struct rlimit rl;
-@@ -532,7 +532,7 @@ int main(int argc, char **argv)
+@@ -560,7 +560,7 @@ int main(int argc, char **argv)
#else
std::string meminfo;
std::string stats_divider = ", ";
@@ -46,7 +46,7 @@ index 1786411..8b328e5 100644
std::ifstream statm;
statm.open(stringf("/proc/%lld/statm", (long long)getpid()));
if (statm.is_open()) {
-@@ -599,7 +599,7 @@ int main(int argc, char **argv)
+@@ -627,7 +627,7 @@ int main(int argc, char **argv)
}
}
@@ -56,7 +56,7 @@ index 1786411..8b328e5 100644
{
string filename;
diff --git a/kernel/log.cc b/kernel/log.cc
-index 0ee2170..1dfa89a 100644
+index a782095..311bc38 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -25,7 +25,7 @@
@@ -68,7 +68,7 @@ index 0ee2170..1dfa89a 100644
# include <dlfcn.h>
#endif
-@@ -389,7 +389,7 @@ void log_pop()
+@@ -420,7 +420,7 @@ void log_pop()
log_flush();
}
@@ -77,7 +77,7 @@ index 0ee2170..1dfa89a 100644
void log_backtrace(const char *prefix, int levels)
{
if (levels <= 0) return;
-@@ -584,7 +584,7 @@ void log_wire(RTLIL::Wire *wire, std::string indent)
+@@ -615,7 +615,7 @@ void log_wire(RTLIL::Wire *wire, std::string indent)
// ---------------------------------------------------
// This is the magic behind the code coverage counters
// ---------------------------------------------------
@@ -87,10 +87,10 @@ index 0ee2170..1dfa89a 100644
dict<std::string, std::pair<std::string, int>> extra_coverage_data;
diff --git a/kernel/log.h b/kernel/log.h
-index 0b4905c..0f068a1 100644
+index 3e1faca..82e27d0 100644
--- a/kernel/log.h
+++ b/kernel/log.h
-@@ -119,7 +119,7 @@ static inline void log_assert_worker(bool cond, const char *expr, const char *fi
+@@ -165,7 +165,7 @@ static inline void log_assert_worker(bool cond, const char *expr, const char *fi
// This is the magic behind the code coverage counters
// ---------------------------------------------------
@@ -100,10 +100,10 @@ index 0b4905c..0f068a1 100644
#define cover(_id) do { \
static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
-index ad03289..822cab9 100644
+index 69a1417..791d40e 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
-@@ -77,7 +77,7 @@ std::vector<void*> memhasher_store;
+@@ -89,7 +89,7 @@ std::vector<void*> memhasher_store;
void memhasher_on()
{
@@ -112,7 +112,7 @@ index ad03289..822cab9 100644
memhasher_rng += time(NULL) << 16 ^ getpid();
#endif
memhasher_store.resize(0x10000);
-@@ -660,7 +660,7 @@ struct TclPass : public Pass {
+@@ -737,7 +737,7 @@ struct TclPass : public Pass {
} TclPass;
#endif
@@ -135,10 +135,10 @@ index 1921a1d..efbfb08 100644
#include <stdlib.h>
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
-index 0ec7476..5f0042a 100644
+index 1128116..0d137ca 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
-@@ -128,7 +128,7 @@ struct CoverPass : public Pass {
+@@ -130,7 +130,7 @@ struct CoverPass : public Pass {
log("\n");
}
diff --git a/debian/patches/series b/debian/patches/series
index 643b1cf4..2175b25d 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -11,3 +11,4 @@ kfreebsd-support.patch
0011-Do-not-show-g-build-flags-in-Version-string.patch
0012-Skip-non-deterministic-test-causing-random-FTBFS-on-.patch
0013-Let-dpkg-buildpackage-handle-stripping-of-binaries.patch
+0014-Set-path-to-berkeley-abc-instead-of-relative-path-to.patch
diff --git a/debian/rules b/debian/rules
index a9af380a..1c6b5249 100755
--- a/debian/rules
+++ b/debian/rules
@@ -30,9 +30,6 @@ override_dh_auto_install:
dh_auto_install
chmod a-x debian/tmp/usr/share/yosys/achronix/speedster22i/cells*.v
-override_dh_install:
- dh_install --fail-missing
-
override_dh_installman:
cd debian/man ; CHANGELOG_DATE="$(CHANGELOG_DATE)" ./genmanpages.sh
dh_installman
diff --git a/debian/yosys.install b/debian/yosys.install
index d9cc4ec2..e3326453 100644
--- a/debian/yosys.install
+++ b/debian/yosys.install
@@ -19,3 +19,16 @@ usr/share/yosys/ecp5
usr/share/yosys/achronix
usr/share/yosys/intel
debian/tmp/usr/share/yosys/python3/smtio.py usr/share/yosys
+
+usr/share/yosys/gate2lut.v
+usr/share/yosys/cmp2lut.v
+usr/share/yosys/anlogic/arith_map.v
+usr/share/yosys/anlogic/cells_map.v
+usr/share/yosys/anlogic/dram_init_16x4.vh
+usr/share/yosys/anlogic/cells_sim.v
+usr/share/yosys/anlogic/drams_map.v
+usr/share/yosys/anlogic/eagle_bb.v
+usr/share/yosys/anlogic/drams.txt
+usr/share/yosys/sf2/arith_map.v
+usr/share/yosys/sf2/cells_map.v
+usr/share/yosys/sf2/cells_sim.v
diff --git a/examples/anlogic/.gitignore b/examples/anlogic/.gitignore
new file mode 100644
index 00000000..97c978a1
--- /dev/null
+++ b/examples/anlogic/.gitignore
@@ -0,0 +1,7 @@
+demo.bit
+demo_phy.area
+full.v
+*.log
+*.h
+*.tde
+*.svf
diff --git a/examples/anlogic/README b/examples/anlogic/README
new file mode 100644
index 00000000..35d8e9cb
--- /dev/null
+++ b/examples/anlogic/README
@@ -0,0 +1,12 @@
+LED Blink project for Anlogic Lichee Tang board.
+
+Follow the install instructions for the Tang Dynasty IDE from given link below.
+
+https://tang.sipeed.com/en/getting-started/installing-td-ide/linux/
+
+
+set TD_HOME env variable to the full path to the TD <TD Install Directory> as follow.
+
+export TD_HOME=<TD Install Directory>
+
+then run "bash build.sh" in this directory.
diff --git a/examples/anlogic/build.sh b/examples/anlogic/build.sh
new file mode 100755
index 00000000..e0f6b4cf
--- /dev/null
+++ b/examples/anlogic/build.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+set -ex
+yosys demo.ys
+$TD_HOME/bin/td build.tcl
diff --git a/examples/anlogic/build.tcl b/examples/anlogic/build.tcl
new file mode 100644
index 00000000..06db525c
--- /dev/null
+++ b/examples/anlogic/build.tcl
@@ -0,0 +1,11 @@
+import_device eagle_s20.db -package BG256
+read_verilog full.v -top demo
+read_adc demo.adc
+optimize_rtl
+map_macro
+map
+pack
+place
+route
+report_area -io_info -file demo_phy.area
+bitgen -bit demo.bit -version 0X0000 -svf demo.svf -svf_comment_on -g ucode:00000000000000000000000000000000
diff --git a/examples/anlogic/demo.adc b/examples/anlogic/demo.adc
new file mode 100644
index 00000000..ec802502
--- /dev/null
+++ b/examples/anlogic/demo.adc
@@ -0,0 +1,2 @@
+set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ
+set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED
diff --git a/examples/anlogic/demo.v b/examples/anlogic/demo.v
new file mode 100644
index 00000000..e17db771
--- /dev/null
+++ b/examples/anlogic/demo.v
@@ -0,0 +1,18 @@
+module demo (
+ input wire CLK_IN,
+ output wire R_LED
+);
+ parameter time1 = 30'd12_000_000;
+ reg led_state;
+ reg [29:0] count;
+
+ always @(posedge CLK_IN)begin
+ if(count == time1)begin
+ count<= 30'd0;
+ led_state <= ~led_state;
+ end
+ else
+ count <= count + 1'b1;
+ end
+ assign R_LED = led_state;
+endmodule
diff --git a/examples/anlogic/demo.ys b/examples/anlogic/demo.ys
new file mode 100644
index 00000000..cb396cc2
--- /dev/null
+++ b/examples/anlogic/demo.ys
@@ -0,0 +1,3 @@
+read_verilog demo.v
+synth_anlogic -top demo
+write_verilog full.v
diff --git a/examples/igloo2/.gitignore b/examples/igloo2/.gitignore
new file mode 100644
index 00000000..33b7182d
--- /dev/null
+++ b/examples/igloo2/.gitignore
@@ -0,0 +1,4 @@
+/netlist.edn
+/netlist.vm
+/example.stp
+/proj
diff --git a/examples/igloo2/example.pdc b/examples/igloo2/example.pdc
new file mode 100644
index 00000000..298d9e93
--- /dev/null
+++ b/examples/igloo2/example.pdc
@@ -0,0 +1,20 @@
+# Add placement constraints here
+
+set_io clk -pinname H16 -fixed yes -DIRECTION INPUT
+
+set_io SW1 -pinname H12 -fixed yes -DIRECTION INPUT
+set_io SW2 -pinname H13 -fixed yes -DIRECTION INPUT
+
+set_io LED1 -pinname J16 -fixed yes -DIRECTION OUTPUT
+set_io LED2 -pinname M16 -fixed yes -DIRECTION OUTPUT
+set_io LED3 -pinname K16 -fixed yes -DIRECTION OUTPUT
+set_io LED4 -pinname N16 -fixed yes -DIRECTION OUTPUT
+
+set_io AA -pinname L12 -fixed yes -DIRECTION OUTPUT
+set_io AB -pinname L13 -fixed yes -DIRECTION OUTPUT
+set_io AC -pinname M13 -fixed yes -DIRECTION OUTPUT
+set_io AD -pinname N15 -fixed yes -DIRECTION OUTPUT
+set_io AE -pinname L11 -fixed yes -DIRECTION OUTPUT
+set_io AF -pinname L14 -fixed yes -DIRECTION OUTPUT
+set_io AG -pinname N14 -fixed yes -DIRECTION OUTPUT
+set_io CA -pinname M15 -fixed yes -DIRECTION OUTPUT
diff --git a/examples/igloo2/example.sdc b/examples/igloo2/example.sdc
new file mode 100644
index 00000000..f8b48731
--- /dev/null
+++ b/examples/igloo2/example.sdc
@@ -0,0 +1,2 @@
+# Add timing constraints here
+create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}]
diff --git a/examples/igloo2/example.v b/examples/igloo2/example.v
new file mode 100644
index 00000000..4a9486e5
--- /dev/null
+++ b/examples/igloo2/example.v
@@ -0,0 +1,64 @@
+module example (
+ input clk,
+ input SW1,
+ input SW2,
+ output LED1,
+ output LED2,
+ output LED3,
+ output LED4,
+
+ output AA, AB, AC, AD,
+ output AE, AF, AG, CA
+);
+
+ localparam BITS = 8;
+ localparam LOG2DELAY = 22;
+
+ reg [BITS+LOG2DELAY-1:0] counter = 0;
+ reg [BITS-1:0] outcnt;
+
+ always @(posedge clk) begin
+ counter <= counter + SW1 + SW2 + 1;
+ outcnt <= counter >> LOG2DELAY;
+ end
+
+ assign {LED1, LED2, LED3, LED4} = outcnt ^ (outcnt >> 1);
+
+ // assign CA = counter[10];
+ // seg7enc seg7encinst (
+ // .seg({AA, AB, AC, AD, AE, AF, AG}),
+ // .dat(CA ? outcnt[3:0] : outcnt[7:4])
+ // );
+
+ assign {AA, AB, AC, AD, AE, AF, AG} = ~(7'b 100_0000 >> outcnt[6:4]);
+ assign CA = outcnt[7];
+endmodule
+
+module seg7enc (
+ input [3:0] dat,
+ output [6:0] seg
+);
+ reg [6:0] seg_inv;
+ always @* begin
+ seg_inv = 0;
+ case (dat)
+ 4'h0: seg_inv = 7'b 0111111;
+ 4'h1: seg_inv = 7'b 0000110;
+ 4'h2: seg_inv = 7'b 1011011;
+ 4'h3: seg_inv = 7'b 1001111;
+ 4'h4: seg_inv = 7'b 1100110;
+ 4'h5: seg_inv = 7'b 1101101;
+ 4'h6: seg_inv = 7'b 1111101;
+ 4'h7: seg_inv = 7'b 0000111;
+ 4'h8: seg_inv = 7'b 1111111;
+ 4'h9: seg_inv = 7'b 1101111;
+ 4'hA: seg_inv = 7'b 1110111;
+ 4'hB: seg_inv = 7'b 1111100;
+ 4'hC: seg_inv = 7'b 0111001;
+ 4'hD: seg_inv = 7'b 1011110;
+ 4'hE: seg_inv = 7'b 1111001;
+ 4'hF: seg_inv = 7'b 1110001;
+ endcase
+ end
+ assign seg = ~seg_inv;
+endmodule
diff --git a/examples/igloo2/libero.tcl b/examples/igloo2/libero.tcl
new file mode 100644
index 00000000..abc94e47
--- /dev/null
+++ b/examples/igloo2/libero.tcl
@@ -0,0 +1,57 @@
+# Run with "libero SCRIPT:libero.tcl"
+
+file delete -force proj
+
+new_project \
+ -name example \
+ -location proj \
+ -block_mode 0 \
+ -hdl "VERILOG" \
+ -family IGLOO2 \
+ -die PA4MGL2500 \
+ -package vf256 \
+ -speed -1
+
+import_files -hdl_source {netlist.vm}
+import_files -sdc {example.sdc}
+import_files -io_pdc {example.pdc}
+build_design_hierarchy
+set_option -synth 0
+
+organize_tool_files -tool PLACEROUTE \
+ -file {proj/constraint/example.sdc} \
+ -file {proj/constraint/io/example.pdc} \
+ -input_type constraint
+
+organize_tool_files -tool VERIFYTIMING \
+ -file {proj/constraint/example.sdc} \
+ -input_type constraint
+
+configure_tool -name PLACEROUTE \
+ -params TDPR:true \
+ -params PDPR:false \
+ -params EFFORT_LEVEL:false \
+ -params REPAIR_MIN_DELAY:false
+
+puts ""
+puts "**> COMPILE"
+run_tool -name {COMPILE}
+puts "<** COMPILE"
+
+puts ""
+puts "**> PLACEROUTE"
+run_tool -name {PLACEROUTE}
+puts "<** PLACEROUTE"
+
+puts ""
+puts "**> VERIFYTIMING"
+run_tool -name {VERIFYTIMING}
+puts "<** VERIFYTIMING"
+
+puts ""
+puts "**> BITSTREAM"
+export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC}
+puts "<** BITSTREAM"
+
+puts ""
+exit 0
diff --git a/examples/igloo2/runme.sh b/examples/igloo2/runme.sh
new file mode 100644
index 00000000..a08894e0
--- /dev/null
+++ b/examples/igloo2/runme.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+set -ex
+yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v
+export LM_LICENSE_FILE=${LM_LICENSE_FILE:-1702@localhost}
+/opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl
+cp proj/designer/example/export/example.stp .
diff --git a/examples/python-api/.gitignore b/examples/python-api/.gitignore
new file mode 100644
index 00000000..758de113
--- /dev/null
+++ b/examples/python-api/.gitignore
@@ -0,0 +1 @@
+out/**
diff --git a/examples/python-api/pass.py b/examples/python-api/pass.py
new file mode 100755
index 00000000..d67cf4a2
--- /dev/null
+++ b/examples/python-api/pass.py
@@ -0,0 +1,32 @@
+#!/usr/bin/python3
+
+from pyosys import libyosys as ys
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+class CellStatsPass(ys.Pass):
+
+ def __init__(self):
+ super().__init__("cell_stats", "Shows cell stats as plot")
+
+ def py_help(self):
+ ys.log("This pass uses the matplotlib library to display cell stats\n")
+
+ def py_execute(self, args, design):
+ ys.log_header(design, "Plotting cell stats\n")
+ cell_stats = {}
+ for module in design.selected_whole_modules_warn():
+ for cell in module.selected_cells():
+ if cell.type.str() in cell_stats:
+ cell_stats[cell.type.str()] += 1
+ else:
+ cell_stats[cell.type.str()] = 1
+ plt.bar(range(len(cell_stats)), height = list(cell_stats.values()),align='center')
+ plt.xticks(range(len(cell_stats)), list(cell_stats.keys()))
+ plt.show()
+
+ def py_clear_flags(self):
+ ys.log("Clear Flags - CellStatsPass\n")
+
+p = CellStatsPass()
diff --git a/examples/python-api/script.py b/examples/python-api/script.py
new file mode 100755
index 00000000..f0fa5a0b
--- /dev/null
+++ b/examples/python-api/script.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python3
+
+from pyosys import libyosys as ys
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+design = ys.Design()
+ys.run_pass("read_verilog ../../tests/simple/fiedler-cooley.v", design);
+ys.run_pass("prep", design)
+ys.run_pass("opt -full", design)
+
+cell_stats = {}
+for module in design.selected_whole_modules_warn():
+ for cell in module.selected_cells():
+ if cell.type.str() in cell_stats:
+ cell_stats[cell.type.str()] += 1
+ else:
+ cell_stats[cell.type.str()] = 1
+plt.bar(range(len(cell_stats)), height = list(cell_stats.values()),align='center')
+plt.xticks(range(len(cell_stats)), list(cell_stats.keys()))
+plt.show()
diff --git a/frontends/aiger/Makefile.inc b/frontends/aiger/Makefile.inc
new file mode 100644
index 00000000..bc111245
--- /dev/null
+++ b/frontends/aiger/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += frontends/aiger/aigerparse.o
+
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
new file mode 100644
index 00000000..68552fd0
--- /dev/null
+++ b/frontends/aiger/aigerparse.cc
@@ -0,0 +1,451 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Eddie Hung <eddie@fpgeh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+// [[CITE]] The AIGER And-Inverter Graph (AIG) Format Version 20071012
+// Armin Biere. The AIGER And-Inverter Graph (AIG) Format Version 20071012. Technical Report 07/1, October 2011, FMV Reports Series, Institute for Formal Models and Verification, Johannes Kepler University, Altenbergerstr. 69, 4040 Linz, Austria.
+// http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf
+
+#ifndef _WIN32
+#include <libgen.h>
+#endif
+#include <array>
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "aigerparse.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name)
+ : design(design), f(f), clk_name(clk_name)
+{
+ module = new RTLIL::Module;
+ module->name = module_name;
+ if (design->module(module->name))
+ log_error("Duplicate definition of module %s!\n", log_id(module->name));
+}
+
+void AigerReader::parse_aiger()
+{
+ std::string header;
+ f >> header;
+ if (header != "aag" && header != "aig")
+ log_error("Unsupported AIGER file!\n");
+
+ // Parse rest of header
+ if (!(f >> M >> I >> L >> O >> A))
+ log_error("Invalid AIGER header\n");
+
+ // Optional values
+ B = C = J = F = 0;
+ if (f.peek() != ' ') goto end_of_header;
+ if (!(f >> B)) log_error("Invalid AIGER header\n");
+ if (f.peek() != ' ') goto end_of_header;
+ if (!(f >> C)) log_error("Invalid AIGER header\n");
+ if (f.peek() != ' ') goto end_of_header;
+ if (!(f >> J)) log_error("Invalid AIGER header\n");
+ if (f.peek() != ' ') goto end_of_header;
+ if (!(f >> F)) log_error("Invalid AIGER header\n");
+end_of_header:
+
+ std::string line;
+ std::getline(f, line); // Ignore up to start of next line, as standard
+ // says anything that follows could be used for
+ // optional sections
+
+ log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F);
+
+ line_count = 1;
+
+ if (header == "aag")
+ parse_aiger_ascii();
+ else if (header == "aig")
+ parse_aiger_binary();
+ else
+ log_abort();
+
+ RTLIL::Wire* n0 = module->wire("\\n0");
+ if (n0)
+ module->connect(n0, RTLIL::S0);
+
+ for (unsigned i = 0; i < outputs.size(); ++i) {
+ RTLIL::Wire *wire = outputs[i];
+ if (wire->port_input) {
+ RTLIL::Wire *o_wire = module->addWire(wire->name.str() + "_o");
+ o_wire->port_output = true;
+ wire->port_output = false;
+ module->connect(o_wire, wire);
+ outputs[i] = o_wire;
+ }
+ }
+
+ // Parse footer (symbol table, comments, etc.)
+ unsigned l1;
+ std::string s;
+ for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) {
+ if (c == 'i' || c == 'l' || c == 'o' || c == 'b') {
+ f.ignore(1);
+ if (!(f >> l1 >> s))
+ log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count);
+
+ if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size()))
+ log_error("Line %u has invalid symbol position!\n", line_count);
+
+ RTLIL::Wire* wire;
+ if (c == 'i') wire = inputs[l1];
+ else if (c == 'l') wire = latches[l1];
+ else if (c == 'o') wire = outputs[l1];
+ else if (c == 'b') wire = bad_properties[l1];
+ else log_abort();
+
+ module->rename(wire, stringf("\\%s", s.c_str()));
+ }
+ else if (c == 'j' || c == 'f') {
+ // TODO
+ }
+ else if (c == 'c') {
+ f.ignore(1);
+ if (f.peek() == '\n')
+ break;
+ // Else constraint (TODO)
+ }
+ else
+ log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
+ std::getline(f, line); // Ignore up to start of next line
+ }
+
+ module->fixup_ports();
+ design->add(module);
+}
+
+static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal)
+{
+ const unsigned variable = literal >> 1;
+ const bool invert = literal & 1;
+ RTLIL::IdString wire_name(stringf("\\n%d%s", variable, invert ? "_inv" : "")); // FIXME: is "_inv" the right suffix?
+ RTLIL::Wire *wire = module->wire(wire_name);
+ if (wire) return wire;
+ log_debug("Creating %s\n", wire_name.c_str());
+ wire = module->addWire(wire_name);
+ if (!invert) return wire;
+ RTLIL::IdString wire_inv_name(stringf("\\n%d", variable));
+ RTLIL::Wire *wire_inv = module->wire(wire_inv_name);
+ if (wire_inv) {
+ if (module->cell(wire_inv_name)) return wire;
+ }
+ else {
+ log_debug("Creating %s\n", wire_inv_name.c_str());
+ wire_inv = module->addWire(wire_inv_name);
+ }
+
+ log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
+ module->addNotGate(stringf("\\n%d_not", variable), wire_inv, wire); // FIXME: is "_not" the right suffix?
+
+ return wire;
+}
+
+void AigerReader::parse_aiger_ascii()
+{
+ std::string line;
+ std::stringstream ss;
+
+ unsigned l1, l2, l3;
+
+ // Parse inputs
+ for (unsigned i = 1; i <= I; ++i, ++line_count) {
+ if (!(f >> l1))
+ log_error("Line %u cannot be interpreted as an input!\n", line_count);
+ log_debug("%d is an input\n", l1);
+ log_assert(!(l1 & 1)); // TODO: Inputs can't be inverted?
+ RTLIL::Wire *wire = createWireIfNotExists(module, l1);
+ wire->port_input = true;
+ inputs.push_back(wire);
+ }
+
+ // Parse latches
+ RTLIL::Wire *clk_wire = nullptr;
+ if (L > 0) {
+ clk_wire = module->wire(clk_name);
+ log_assert(!clk_wire);
+ log_debug("Creating %s\n", clk_name.c_str());
+ clk_wire = module->addWire(clk_name);
+ clk_wire->port_input = true;
+ }
+ for (unsigned i = 0; i < L; ++i, ++line_count) {
+ if (!(f >> l1 >> l2))
+ log_error("Line %u cannot be interpreted as a latch!\n", line_count);
+ log_debug("%d %d is a latch\n", l1, l2);
+ log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted?
+ RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
+ RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
+
+ module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire);
+
+ // Reset logic is optional in AIGER 1.9
+ if (f.peek() == ' ') {
+ if (!(f >> l3))
+ log_error("Line %u cannot be interpreted as a latch!\n", line_count);
+
+ if (l3 == 0)
+ q_wire->attributes["\\init"] = RTLIL::S0;
+ else if (l3 == 1)
+ q_wire->attributes["\\init"] = RTLIL::S1;
+ else if (l3 == l1) {
+ //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
+ }
+ else
+ log_error("Line %u has invalid reset literal for latch!\n", line_count);
+ }
+ else {
+ // AIGER latches are assumed to be initialized to zero
+ q_wire->attributes["\\init"] = RTLIL::S0;
+ }
+ latches.push_back(q_wire);
+ }
+
+ // Parse outputs
+ for (unsigned i = 0; i < O; ++i, ++line_count) {
+ if (!(f >> l1))
+ log_error("Line %u cannot be interpreted as an output!\n", line_count);
+
+ log_debug("%d is an output\n", l1);
+ RTLIL::Wire *wire = createWireIfNotExists(module, l1);
+ wire->port_output = true;
+ outputs.push_back(wire);
+ }
+
+ // Parse bad properties
+ for (unsigned i = 0; i < B; ++i, ++line_count) {
+ if (!(f >> l1))
+ log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
+
+ log_debug("%d is a bad state property\n", l1);
+ RTLIL::Wire *wire = createWireIfNotExists(module, l1);
+ wire->port_output = true;
+ bad_properties.push_back(wire);
+ }
+
+ // TODO: Parse invariant constraints
+ for (unsigned i = 0; i < C; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // TODO: Parse justice properties
+ for (unsigned i = 0; i < J; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // TODO: Parse fairness constraints
+ for (unsigned i = 0; i < F; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // Parse AND
+ for (unsigned i = 0; i < A; ++i) {
+ if (!(f >> l1 >> l2 >> l3))
+ log_error("Line %u cannot be interpreted as an AND!\n", line_count);
+
+ log_debug("%d %d %d is an AND\n", l1, l2, l3);
+ log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
+ RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
+ RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
+ RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
+ module->addAndGate(NEW_ID, i1_wire, i2_wire, o_wire);
+ }
+ std::getline(f, line); // Ignore up to start of next line
+}
+
+static unsigned parse_next_delta_literal(std::istream &f, unsigned ref)
+{
+ unsigned x = 0, i = 0;
+ unsigned char ch;
+ while ((ch = f.get()) & 0x80)
+ x |= (ch & 0x7f) << (7 * i++);
+ return ref - (x | (ch << (7 * i)));
+}
+
+void AigerReader::parse_aiger_binary()
+{
+ unsigned l1, l2, l3;
+ std::string line;
+
+ // Parse inputs
+ for (unsigned i = 1; i <= I; ++i) {
+ RTLIL::Wire *wire = createWireIfNotExists(module, i << 1);
+ wire->port_input = true;
+ inputs.push_back(wire);
+ }
+
+ // Parse latches
+ RTLIL::Wire *clk_wire = nullptr;
+ if (L > 0) {
+ clk_wire = module->wire(clk_name);
+ log_assert(!clk_wire);
+ log_debug("Creating %s\n", clk_name.c_str());
+ clk_wire = module->addWire(clk_name);
+ clk_wire->port_input = true;
+ }
+ l1 = (I+1) * 2;
+ for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) {
+ if (!(f >> l2))
+ log_error("Line %u cannot be interpreted as a latch!\n", line_count);
+ log_debug("%d %d is a latch\n", l1, l2);
+ RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
+ RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
+
+ module->addDff(NEW_ID, clk_wire, d_wire, q_wire);
+
+ // Reset logic is optional in AIGER 1.9
+ if (f.peek() == ' ') {
+ if (!(f >> l3))
+ log_error("Line %u cannot be interpreted as a latch!\n", line_count);
+
+ if (l3 == 0)
+ q_wire->attributes["\\init"] = RTLIL::S0;
+ else if (l3 == 1)
+ q_wire->attributes["\\init"] = RTLIL::S1;
+ else if (l3 == l1) {
+ //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
+ }
+ else
+ log_error("Line %u has invalid reset literal for latch!\n", line_count);
+ }
+ else {
+ // AIGER latches are assumed to be initialized to zero
+ q_wire->attributes["\\init"] = RTLIL::S0;
+ }
+ latches.push_back(q_wire);
+ }
+
+ // Parse outputs
+ for (unsigned i = 0; i < O; ++i, ++line_count) {
+ if (!(f >> l1))
+ log_error("Line %u cannot be interpreted as an output!\n", line_count);
+
+ log_debug("%d is an output\n", l1);
+ RTLIL::Wire *wire = createWireIfNotExists(module, l1);
+ wire->port_output = true;
+ outputs.push_back(wire);
+ }
+ std::getline(f, line); // Ignore up to start of next line
+
+ // Parse bad properties
+ for (unsigned i = 0; i < B; ++i, ++line_count) {
+ if (!(f >> l1))
+ log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
+
+ log_debug("%d is a bad state property\n", l1);
+ RTLIL::Wire *wire = createWireIfNotExists(module, l1);
+ wire->port_output = true;
+ bad_properties.push_back(wire);
+ }
+ if (B > 0)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // TODO: Parse invariant constraints
+ for (unsigned i = 0; i < C; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // TODO: Parse justice properties
+ for (unsigned i = 0; i < J; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // TODO: Parse fairness constraints
+ for (unsigned i = 0; i < F; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // Parse AND
+ l1 = (I+L+1) << 1;
+ for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) {
+ l2 = parse_next_delta_literal(f, l1);
+ l3 = parse_next_delta_literal(f, l2);
+
+ log_debug("%d %d %d is an AND\n", l1, l2, l3);
+ log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
+ RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
+ RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
+ RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
+
+ RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$_AND_");
+ and_cell->setPort("\\A", i1_wire);
+ and_cell->setPort("\\B", i2_wire);
+ and_cell->setPort("\\Y", o_wire);
+ }
+}
+
+struct AigerFrontend : public Frontend {
+ AigerFrontend() : Frontend("aiger", "read AIGER file") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" read_aiger [options] [filename]\n");
+ log("\n");
+ log("Load module from an AIGER file into the current design.\n");
+ log("\n");
+ log(" -module_name <module_name>\n");
+ log(" Name of module to be created (default: "
+#ifdef _WIN32
+ "top" // FIXME
+#else
+ "<filename>"
+#endif
+ ")\n");
+ log("\n");
+ log(" -clk_name <wire_name>\n");
+ log(" AIGER latches to be transformed into posedge DFFs clocked by wire of");
+ log(" this name (default: clk)\n");
+ log("\n");
+ }
+ void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing AIGER frontend.\n");
+
+ RTLIL::IdString clk_name = "\\clk";
+ RTLIL::IdString module_name;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ std::string arg = args[argidx];
+ if (arg == "-module_name" && argidx+1 < args.size()) {
+ module_name = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
+ if (arg == "-clk_name" && argidx+1 < args.size()) {
+ clk_name = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ if (module_name.empty()) {
+#ifdef _WIN32
+ module_name = "top"; // FIXME: basename equivalent on Win32?
+#else
+ char* bn = strdup(filename.c_str());
+ module_name = RTLIL::escape_id(bn);
+ free(bn);
+#endif
+ }
+
+ AigerReader reader(design, *f, module_name, clk_name);
+ reader.parse_aiger();
+ }
+} AigerFrontend;
+
+YOSYS_NAMESPACE_END
diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h
new file mode 100644
index 00000000..0e3719cc
--- /dev/null
+++ b/frontends/aiger/aigerparse.h
@@ -0,0 +1,52 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Eddie Hung <eddie@fpgeh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef ABC_AIGERPARSE
+#define ABC_AIGERPARSE
+
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+struct AigerReader
+{
+ RTLIL::Design *design;
+ std::istream &f;
+ RTLIL::IdString clk_name;
+ RTLIL::Module *module;
+
+ unsigned M, I, L, O, A;
+ unsigned B, C, J, F; // Optional in AIGER 1.9
+ unsigned line_count;
+
+ std::vector<RTLIL::Wire*> inputs;
+ std::vector<RTLIL::Wire*> latches;
+ std::vector<RTLIL::Wire*> outputs;
+ std::vector<RTLIL::Wire*> bad_properties;
+
+ AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name);
+ void parse_aiger();
+ void parse_aiger_ascii();
+ void parse_aiger_binary();
+};
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index e79be953..3d066af5 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -2,6 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018 Ruben Undheim <ruben.undheim@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -35,17 +36,17 @@ YOSYS_NAMESPACE_BEGIN
using namespace AST;
using namespace AST_INTERNAL;
-// instanciate global variables (public API)
+// instantiate global variables (public API)
namespace AST {
std::string current_filename;
void (*set_line_num)(int) = NULL;
int (*get_line_num)() = NULL;
}
-// instanciate global variables (private API)
+// instantiate global variables (private API)
namespace AST_INTERNAL {
- bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
- bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+ bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
+ bool flag_nomem2reg, flag_mem2reg, flag_noblackbox, flag_lib, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_autowire;
AstNode *current_ast, *current_ast_mod;
std::map<std::string, AstNode*> current_scope;
const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
@@ -153,6 +154,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_GENIF)
X(AST_GENCASE)
X(AST_GENBLOCK)
+ X(AST_TECALL)
X(AST_POSEDGE)
X(AST_NEGEDGE)
X(AST_EDGE)
@@ -171,8 +173,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
AstNode *attr = attributes.at(id);
if (attr->type != AST_CONSTANT)
- log_file_error(attr->filename, attr->linenum, "Attribute `%s' with non-constant value!\n",
- id.c_str());
+ log_file_error(attr->filename, attr->linenum, "Attribute `%s' with non-constant value!\n", id.c_str());
return attr->integer != 0;
}
@@ -194,6 +195,9 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
is_logic = false;
is_signed = false;
is_string = false;
+ is_wand = false;
+ is_wor = false;
+ is_unsized = false;
was_checked = false;
range_valid = false;
range_swapped = false;
@@ -431,9 +435,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
break;
case AST_RANGE:
- if (range_valid)
- fprintf(f, "[%d:%d]", range_left, range_right);
- else {
+ if (range_valid) {
+ if (range_swapped)
+ fprintf(f, "[%d:%d]", range_right, range_left);
+ else
+ fprintf(f, "[%d:%d]", range_left, range_right);
+ } else {
for (auto child : children) {
fprintf(f, "%c", first ? '[' : ':');
child->dumpVlog(f, "");
@@ -562,7 +569,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
case AST_CONCAT:
fprintf(f, "{");
- for (auto child : children) {
+ for (int i = GetSize(children)-1; i >= 0; i--) {
+ auto child = children[i];
if (!first)
fprintf(f, ", ");
child->dumpVlog(f, "");
@@ -718,7 +726,7 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
}
// create an AST node for a constant (using a bit vector as value)
-AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed)
+AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized)
{
AstNode *node = new AstNode(AST_CONSTANT);
node->is_signed = is_signed;
@@ -732,9 +740,15 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
node->range_valid = true;
node->range_left = node->bits.size()-1;
node->range_right = 0;
+ node->is_unsized = is_unsized;
return node;
}
+AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed)
+{
+ return mkconst_bits(v, is_signed, false);
+}
+
// create an AST node for a constant (using a string in bit vector form as value)
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
{
@@ -771,6 +785,14 @@ bool AstNode::bits_only_01() const
return true;
}
+RTLIL::Const AstNode::bitsAsUnsizedConst(int width)
+{
+ RTLIL::State extbit = bits.back();
+ while (width > int(bits.size()))
+ bits.push_back(extbit);
+ return RTLIL::Const(bits);
+}
+
RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed)
{
std::vector<RTLIL::State> bits = this->bits;
@@ -903,9 +925,9 @@ RTLIL::Const AstNode::realAsConst(int width)
}
// create a new AstModule from an AST_MODULE AST node
-static AstModule* process_module(AstNode *ast, bool defer)
+static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast = NULL)
{
- log_assert(ast->type == AST_MODULE);
+ log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE);
if (defer)
log("Storing AST representation for module `%s'.\n", ast->str.c_str());
@@ -916,33 +938,116 @@ static AstModule* process_module(AstNode *ast, bool defer)
current_module->ast = NULL;
current_module->name = ast->str;
current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum);
+ current_module->set_bool_attribute("\\cells_not_processed");
current_ast_mod = ast;
- AstNode *ast_before_simplify = ast->clone();
+ AstNode *ast_before_simplify;
+ if (original_ast != NULL)
+ ast_before_simplify = original_ast;
+ else
+ ast_before_simplify = ast->clone();
if (flag_dump_ast1) {
- log("Dumping Verilog AST before simplification:\n");
+ log("Dumping AST before simplification:\n");
ast->dumpAst(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
+ if (flag_dump_vlog1) {
+ log("Dumping Verilog AST before simplification:\n");
+ ast->dumpVlog(NULL, " ");
+ log("--- END OF AST DUMP ---\n");
+ }
if (!defer)
{
+ bool blackbox_module = flag_lib;
+
+ if (!blackbox_module && !flag_noblackbox) {
+ blackbox_module = true;
+ for (auto child : ast->children) {
+ if (child->type == AST_WIRE && (child->is_input || child->is_output))
+ continue;
+ if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
+ continue;
+ if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
+ (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule"))
+ continue;
+ blackbox_module = false;
+ break;
+ }
+ }
+
while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
if (flag_dump_ast2) {
- log("Dumping Verilog AST after simplification:\n");
+ log("Dumping AST after simplification:\n");
ast->dumpAst(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
- if (flag_dump_vlog) {
- log("Dumping Verilog AST (as requested by dump_vlog option):\n");
+ if (flag_dump_vlog2) {
+ log("Dumping Verilog AST after simplification:\n");
ast->dumpVlog(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
- if (flag_lib) {
+ if (flag_nowb && ast->attributes.count("\\whitebox")) {
+ delete ast->attributes.at("\\whitebox");
+ ast->attributes.erase("\\whitebox");
+ }
+
+ if (ast->attributes.count("\\lib_whitebox")) {
+ if (!flag_lib || flag_nowb) {
+ delete ast->attributes.at("\\lib_whitebox");
+ ast->attributes.erase("\\lib_whitebox");
+ } else {
+ if (ast->attributes.count("\\whitebox")) {
+ delete ast->attributes.at("\\whitebox");
+ ast->attributes.erase("\\whitebox");
+ }
+ AstNode *n = ast->attributes.at("\\lib_whitebox");
+ ast->attributes["\\whitebox"] = n;
+ ast->attributes.erase("\\lib_whitebox");
+ }
+ }
+
+ if (!blackbox_module && ast->attributes.count("\\blackbox")) {
+ AstNode *n = ast->attributes.at("\\blackbox");
+ if (n->type != AST_CONSTANT)
+ log_file_error(ast->filename, ast->linenum, "Got blackbox attribute with non-constant value!\n");
+ blackbox_module = n->asBool();
+ }
+
+ if (blackbox_module && ast->attributes.count("\\whitebox")) {
+ AstNode *n = ast->attributes.at("\\whitebox");
+ if (n->type != AST_CONSTANT)
+ log_file_error(ast->filename, ast->linenum, "Got whitebox attribute with non-constant value!\n");
+ blackbox_module = !n->asBool();
+ }
+
+ if (ast->attributes.count("\\noblackbox")) {
+ if (blackbox_module) {
+ AstNode *n = ast->attributes.at("\\noblackbox");
+ if (n->type != AST_CONSTANT)
+ log_file_error(ast->filename, ast->linenum, "Got noblackbox attribute with non-constant value!\n");
+ blackbox_module = !n->asBool();
+ }
+ delete ast->attributes.at("\\noblackbox");
+ ast->attributes.erase("\\noblackbox");
+ }
+
+ if (blackbox_module)
+ {
+ if (ast->attributes.count("\\whitebox")) {
+ delete ast->attributes.at("\\whitebox");
+ ast->attributes.erase("\\whitebox");
+ }
+
+ if (ast->attributes.count("\\lib_whitebox")) {
+ delete ast->attributes.at("\\lib_whitebox");
+ ast->attributes.erase("\\lib_whitebox");
+ }
+
std::vector<AstNode*> new_children;
for (auto child : ast->children) {
if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
@@ -951,20 +1056,26 @@ static AstModule* process_module(AstNode *ast, bool defer)
child->delete_children();
child->children.push_back(AstNode::mkconst_int(0, false, 0));
new_children.push_back(child);
+ } else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
+ (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) {
+ new_children.push_back(child);
} else {
delete child;
}
}
+
ast->children.swap(new_children);
- ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
+
+ if (ast->attributes.count("\\blackbox") == 0) {
+ ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
+ }
}
ignoreThisSignalsInInitial = RTLIL::SigSpec();
for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
current_module->attributes[attr.first] = attr.second->asAttrConst();
}
for (size_t i = 0; i < ast->children.size(); i++) {
@@ -989,14 +1100,19 @@ static AstModule* process_module(AstNode *ast, bool defer)
ignoreThisSignalsInInitial = RTLIL::SigSpec();
}
+ if (ast->type == AST_INTERFACE)
+ current_module->set_bool_attribute("\\is_interface");
current_module->ast = ast_before_simplify;
current_module->nolatches = flag_nolatches;
current_module->nomeminit = flag_nomeminit;
current_module->nomem2reg = flag_nomem2reg;
current_module->mem2reg = flag_mem2reg;
+ current_module->noblackbox = flag_noblackbox;
current_module->lib = flag_lib;
+ current_module->nowb = flag_nowb;
current_module->noopt = flag_noopt;
current_module->icells = flag_icells;
+ current_module->pwires = flag_pwires;
current_module->autowire = flag_autowire;
current_module->fixup_ports();
@@ -1010,28 +1126,32 @@ static AstModule* process_module(AstNode *ast, bool defer)
}
// create AstModule instances for all modules in the AST tree and add them to 'design'
-void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog, bool dump_rtlil,
- bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
+void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil,
+ bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire)
{
current_ast = ast;
flag_dump_ast1 = dump_ast1;
flag_dump_ast2 = dump_ast2;
flag_no_dump_ptr = no_dump_ptr;
- flag_dump_vlog = dump_vlog;
+ flag_dump_vlog1 = dump_vlog1;
+ flag_dump_vlog2 = dump_vlog2;
flag_dump_rtlil = dump_rtlil;
flag_nolatches = nolatches;
flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
+ flag_noblackbox = noblackbox;
flag_lib = lib;
+ flag_nowb = nowb;
flag_noopt = noopt;
flag_icells = icells;
+ flag_pwires = pwires;
flag_autowire = autowire;
log_assert(current_ast->type == AST_DESIGN);
for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++)
{
- if ((*it)->type == AST_MODULE)
+ if ((*it)->type == AST_MODULE || (*it)->type == AST_INTERFACE)
{
for (auto n : design->verilog_globals)
(*it)->children.push_back(n->clone());
@@ -1053,8 +1173,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
if (design->has((*it)->str)) {
RTLIL::Module *existing_mod = design->module((*it)->str);
if (!nooverwrite && !overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
- log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n",
- (*it)->str.c_str());
+ log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n", (*it)->str.c_str());
} else if (nooverwrite) {
log("Ignoring re-definition of module `%s' at %s:%d.\n",
(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
@@ -1083,8 +1202,264 @@ AstModule::~AstModule()
delete ast;
}
+
+// An interface port with modport is specified like this:
+// <interface_name>.<modport_name>
+// This function splits the interface_name from the modport_name, and fails if it is not a valid combination
+std::pair<std::string,std::string> AST::split_modport_from_type(std::string name_type)
+{
+ std::string interface_type = "";
+ std::string interface_modport = "";
+ size_t ndots = std::count(name_type.begin(), name_type.end(), '.');
+ // Separate the interface instance name from any modports:
+ if (ndots == 0) { // Does not have modport
+ interface_type = name_type;
+ }
+ else {
+ std::stringstream name_type_stream(name_type);
+ std::string segment;
+ std::vector<std::string> seglist;
+ while(std::getline(name_type_stream, segment, '.')) {
+ seglist.push_back(segment);
+ }
+ if (ndots == 1) { // Has modport
+ interface_type = seglist[0];
+ interface_modport = seglist[1];
+ }
+ else { // Erroneous port type
+ log_error("More than two '.' in signal port type (%s)\n", name_type.c_str());
+ }
+ }
+ return std::pair<std::string,std::string>(interface_type, interface_modport);
+
+}
+
+AstNode * AST::find_modport(AstNode *intf, std::string name)
+{
+ for (auto &ch : intf->children)
+ if (ch->type == AST_MODPORT)
+ if (ch->str == name) // Modport found
+ return ch;
+ return NULL;
+}
+
+// Iterate over all wires in an interface and add them as wires in the AST module:
+void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport)
+{
+ for (auto &wire_it : intfmodule->wires_){
+ AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true)));
+ std::string origname = log_id(wire_it.first);
+ std::string newname = intfname + "." + origname;
+ wire->str = newname;
+ if (modport != NULL) {
+ bool found_in_modport = false;
+ // Search for the current wire in the wire list for the current modport
+ for (auto &ch : modport->children) {
+ if (ch->type == AST_MODPORTMEMBER) {
+ std::string compare_name = "\\" + origname;
+ if (ch->str == compare_name) { // Found signal. The modport decides whether it is input or output
+ found_in_modport = true;
+ wire->is_input = ch->is_input;
+ wire->is_output = ch->is_output;
+ break;
+ }
+ }
+ }
+ if (found_in_modport) {
+ module_ast->children.push_back(wire);
+ }
+ else { // If not found in modport, do not create port
+ delete wire;
+ }
+ }
+ else { // If no modport, set inout
+ wire->is_input = true;
+ wire->is_output = true;
+ module_ast->children.push_back(wire);
+ }
+ }
+}
+
+// When an interface instance is found in a module, the whole RTLIL for the module will be rederived again
+// from AST. The interface members are copied into the AST module with the prefix of the interface.
+void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module*> local_interfaces)
+{
+ bool is_top = false;
+ AstNode *new_ast = ast->clone();
+ for (auto &intf : local_interfaces) {
+ std::string intfname = intf.first.str();
+ RTLIL::Module *intfmodule = intf.second;
+ for (auto &wire_it : intfmodule->wires_){
+ AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true)));
+ std::string newname = log_id(wire_it.first);
+ newname = intfname + "." + newname;
+ wire->str = newname;
+ new_ast->children.push_back(wire);
+ }
+ }
+
+ AstNode *ast_before_replacing_interface_ports = new_ast->clone();
+
+ // Explode all interface ports. Note this will only have an effect on 'top
+ // level' modules. Other sub-modules will have their interface ports
+ // exploded via the derive(..) function
+ for (size_t i =0; i<new_ast->children.size(); i++)
+ {
+ AstNode *ch2 = new_ast->children[i];
+ if (ch2->type == AST_INTERFACEPORT) { // Is an interface port
+ std::string name_port = ch2->str; // Name of the interface port
+ if (ch2->children.size() > 0) {
+ for(size_t j=0; j<ch2->children.size();j++) {
+ AstNode *ch = ch2->children[j];
+ if(ch->type == AST_INTERFACEPORTTYPE) { // Found the AST node containing the type of the interface
+ std::pair<std::string,std::string> res = split_modport_from_type(ch->str);
+ std::string interface_type = res.first;
+ std::string interface_modport = res.second; // Is "", if no modport
+ if (design->modules_.count(interface_type) > 0) {
+ // Add a cell to the module corresponding to the interface port such that
+ // it can further propagated down if needed:
+ AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE);
+ celltype_for_intf->str = interface_type;
+ AstNode *cell_for_intf = new AstNode(AST_CELL, celltype_for_intf);
+ cell_for_intf->str = name_port + "_inst_from_top_dummy";
+ new_ast->children.push_back(cell_for_intf);
+
+ // Get all members of this non-overridden dummy interface instance:
+ RTLIL::Module *intfmodule = design->modules_[interface_type]; // All interfaces should at this point in time (assuming
+ // reprocess_module is called from the hierarchy pass) be
+ // present in design->modules_
+ AstModule *ast_module_of_interface = (AstModule*)intfmodule;
+ std::string interface_modport_compare_str = "\\" + interface_modport;
+ AstNode *modport = find_modport(ast_module_of_interface->ast, interface_modport_compare_str); // modport == NULL if no modport
+ // Iterate over all wires in the interface and add them to the module:
+ explode_interface_port(new_ast, intfmodule, name_port, modport);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // The old module will be deleted. Rename and mark for deletion:
+ std::string original_name = this->name.str();
+ std::string changed_name = original_name + "_before_replacing_local_interfaces";
+ design->rename(this, changed_name);
+ this->set_bool_attribute("\\to_delete");
+
+ // Check if the module was the top module. If it was, we need to remove the top attribute and put it on the
+ // new module.
+ if (this->get_bool_attribute("\\initial_top")) {
+ this->attributes.erase("\\initial_top");
+ is_top = true;
+ }
+
+ // Generate RTLIL from AST for the new module and add to the design:
+ AstModule *newmod = process_module(new_ast, false, ast_before_replacing_interface_ports);
+ delete(new_ast);
+ design->add(newmod);
+ RTLIL::Module* mod = design->module(original_name);
+ if (is_top)
+ mod->set_bool_attribute("\\top");
+
+ // Set the attribute "interfaces_replaced_in_module" so that it does not happen again.
+ mod->set_bool_attribute("\\interfaces_replaced_in_module");
+}
+
+// create a new parametric module (when needed) and return the name of the generated module - WITH support for interfaces
+// This method is used to explode the interface when the interface is a port of the module (not instantiated inside)
+RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail)
+{
+ AstNode *new_ast = NULL;
+ std::string modname = derive_common(design, parameters, &new_ast, mayfail);
+
+ // Since interfaces themselves may be instantiated with different parameters,
+ // "modname" must also take those into account, so that unique modules
+ // are derived for any variant of interface connections:
+ std::string interf_info = "";
+
+ bool has_interfaces = false;
+ for(auto &intf : interfaces) {
+ interf_info += log_id(intf.second->name);
+ has_interfaces = true;
+ }
+
+ if (has_interfaces)
+ modname += "$interfaces$" + interf_info;
+
+
+ if (!design->has(modname)) {
+ new_ast->str = modname;
+
+ // Iterate over all interfaces which are ports in this module:
+ for(auto &intf : interfaces) {
+ RTLIL::Module * intfmodule = intf.second;
+ std::string intfname = intf.first.str();
+ // Check if a modport applies for the interface port:
+ AstNode *modport = NULL;
+ if (modports.count(intfname) > 0) {
+ std::string interface_modport = modports.at(intfname).str();
+ AstModule *ast_module_of_interface = (AstModule*)intfmodule;
+ AstNode *ast_node_of_interface = ast_module_of_interface->ast;
+ modport = find_modport(ast_node_of_interface, interface_modport);
+ }
+ // Iterate over all wires in the interface and add them to the module:
+ explode_interface_port(new_ast, intfmodule, intfname, modport);
+ }
+
+ design->add(process_module(new_ast, false));
+ design->module(modname)->check();
+
+ RTLIL::Module* mod = design->module(modname);
+
+ // Now that the interfaces have been exploded, we can delete the dummy port related to every interface.
+ for(auto &intf : interfaces) {
+ if(mod->wires_.count(intf.first)) {
+ mod->wires_.erase(intf.first);
+ mod->fixup_ports();
+ // We copy the cell of the interface to the sub-module such that it can further be found if it is propagated
+ // down to sub-sub-modules etc.
+ RTLIL::Cell * new_subcell = mod->addCell(intf.first, intf.second->name);
+ new_subcell->set_bool_attribute("\\is_interface");
+ }
+ else {
+ log_error("No port with matching name found (%s) in %s. Stopping\n", log_id(intf.first), modname.c_str());
+ }
+ }
+
+ // If any interfaces were replaced, set the attribute 'interfaces_replaced_in_module':
+ if (interfaces.size() > 0) {
+ mod->set_bool_attribute("\\interfaces_replaced_in_module");
+ }
+
+ } else {
+ log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
+ }
+
+ delete new_ast;
+ return modname;
+}
+
+// create a new parametric module (when needed) and return the name of the generated module - without support for interfaces
+RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail)
+{
+ AstNode *new_ast = NULL;
+ std::string modname = derive_common(design, parameters, &new_ast, mayfail);
+
+ if (!design->has(modname)) {
+ new_ast->str = modname;
+ design->add(process_module(new_ast, false));
+ design->module(modname)->check();
+ } else {
+ log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
+ }
+
+ delete new_ast;
+ return modname;
+}
+
// create a new parametric module (when needed) and return the name of the generated module
-RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool)
+std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool)
{
std::string stripped_name = name.str();
@@ -1096,14 +1471,18 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
current_ast = NULL;
flag_dump_ast1 = false;
flag_dump_ast2 = false;
- flag_dump_vlog = false;
+ flag_dump_vlog1 = false;
+ flag_dump_vlog2 = false;
flag_nolatches = nolatches;
flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
+ flag_noblackbox = noblackbox;
flag_lib = lib;
+ flag_nowb = nowb;
flag_noopt = noopt;
flag_icells = icells;
+ flag_pwires = pwires;
flag_autowire = autowire;
use_internal_line_num();
@@ -1156,15 +1535,8 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
else
modname = "$paramod" + stripped_name + para_info;
- if (!design->has(modname)) {
- new_ast->str = modname;
- design->add(process_module(new_ast, false));
- design->module(modname)->check();
- } else {
- log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
- }
- delete new_ast;
+ (*new_ast_out) = new_ast;
return modname;
}
@@ -1182,6 +1554,7 @@ RTLIL::Module *AstModule::clone() const
new_mod->lib = lib;
new_mod->noopt = noopt;
new_mod->icells = icells;
+ new_mod->pwires = pwires;
new_mod->autowire = autowire;
return new_mod;
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 7e97bdb3..54b2fb31 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -137,11 +137,17 @@ namespace AST
AST_GENIF,
AST_GENCASE,
AST_GENBLOCK,
-
+ AST_TECALL,
+
AST_POSEDGE,
AST_NEGEDGE,
AST_EDGE,
+ AST_INTERFACE,
+ AST_INTERFACEPORT,
+ AST_INTERFACEPORTTYPE,
+ AST_MODPORT,
+ AST_MODPORTMEMBER,
AST_PACKAGE
};
@@ -168,7 +174,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_logic, is_signed, is_string, range_valid, range_swapped, was_checked;
+ bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized;
int port_id, range_left, range_right;
uint32_t integer;
double realvalue;
@@ -209,6 +215,8 @@ namespace AST
MEM2REG_FL_SET_ASYNC = 0x00000800,
MEM2REG_FL_EQ2 = 0x00001000,
MEM2REG_FL_CMPLX_LHS = 0x00002000,
+ MEM2REG_FL_CONST_LHS = 0x00004000,
+ MEM2REG_FL_VAR_LHS = 0x00008000,
/* proc flags */
MEM2REG_FL_EQ1 = 0x01000000,
@@ -232,6 +240,7 @@ namespace AST
bool has_const_only_constructs(bool &recommend_const_eval);
void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
AstNode *eval_const_function(AstNode *fcall);
+ bool is_simple_const_expr();
// create a human-readable text representation of the AST (for debugging)
void dumpAst(FILE *f, std::string indent) const;
@@ -254,6 +263,7 @@ namespace AST
// helper functions for creating AST nodes for constants
static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32);
+ static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed);
static AstNode *mkconst_str(const std::vector<RTLIL::State> &v);
static AstNode *mkconst_str(const std::string &str);
@@ -261,6 +271,7 @@ namespace AST
// helper function for creating sign-extended const objects
RTLIL::Const bitsAsConst(int width, bool is_signed);
RTLIL::Const bitsAsConst(int width = -1);
+ RTLIL::Const bitsAsUnsizedConst(int width);
RTLIL::Const asAttrConst();
RTLIL::Const asParaConst();
uint64_t asInt(bool is_signed);
@@ -274,16 +285,19 @@ namespace AST
};
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
- void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog, bool dump_rtlil, bool nolatches, bool nomeminit,
- bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
+ void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit,
+ bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, 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;
+ bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire;
~AstModule() YS_OVERRIDE;
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE;
+ RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE;
+ std::string derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool mayfail);
+ void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces) YS_OVERRIDE;
RTLIL::Module *clone() const YS_OVERRIDE;
};
@@ -300,13 +314,18 @@ namespace AST
// call a DPI function
AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args);
+
+ // Helper functions related to handling SystemVerilog interfaces
+ std::pair<std::string,std::string> split_modport_from_type(std::string name_type);
+ AstNode * find_modport(AstNode *intf, std::string name);
+ void explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport);
}
namespace AST_INTERNAL
{
// internal state variables
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 bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_pwires, flag_autowire;
extern AST::AstNode *current_ast, *current_ast_mod;
extern std::map<std::string, AST::AstNode*> current_scope;
extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 0f7e910f..cee344a2 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -55,8 +55,7 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_wi
if (gen_attributes)
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -89,8 +88,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
if (that != NULL)
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -117,8 +115,7 @@ static RTLIL::SigSpec binop2rtlil(AstNode *that, std::string type, int result_wi
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -152,8 +149,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -480,8 +476,7 @@ struct AST_INTERNAL::ProcessGenerator
for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
sw->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -509,6 +504,7 @@ struct AST_INTERNAL::ProcessGenerator
RTLIL::CaseRule *backup_case = current_case;
current_case = new RTLIL::CaseRule;
+ current_case->attributes["\\src"] = stringf("%s:%d", child->filename.c_str(), child->linenum);
last_generated_case = current_case;
addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
for (auto node : child->children) {
@@ -530,7 +526,16 @@ struct AST_INTERNAL::ProcessGenerator
}
if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) {
+ #if 0
+ // this is a valid transformation, but as optimization it is premature.
+ // better: add a default case that assigns 'x' to everything, and let later
+ // optimizations take care of the rest
last_generated_case->compare.clear();
+ #else
+ default_case = new RTLIL::CaseRule;
+ addChunkActions(default_case->actions, this_case_eq_ltemp, SigSpec(State::Sx, GetSize(this_case_eq_rvalue)));
+ sw->cases.push_back(default_case);
+ #endif
} else {
if (default_case == NULL) {
default_case = new RTLIL::CaseRule;
@@ -549,7 +554,11 @@ struct AST_INTERNAL::ProcessGenerator
break;
case AST_WIRE:
- log_file_error(ast->filename, ast->linenum, "Found wire declaration in block without label!\n");
+ log_file_error(ast->filename, ast->linenum, "Found reg declaration in block without label!\n");
+ break;
+
+ case AST_ASSIGN:
+ log_file_error(ast->filename, ast->linenum, "Found continuous assignment in always/initial block!\n");
break;
case AST_PARAMETER:
@@ -637,6 +646,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id_ast->children[0]->range_valid)
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;
+ if (children.size() > 1)
+ range = children[1];
} else
log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
if (range) {
@@ -648,9 +659,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n",
- str.c_str());
- this_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
+ this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
delete left_at_zero_ast;
delete right_at_zero_ast;
} else
@@ -778,7 +788,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { }
if (children[0]->type != AST_CONSTANT)
log_file_error(filename, linenum, "System function %s called with non-const argument!\n",
- RTLIL::unescape_id(str).c_str());
+ RTLIL::unescape_id(str).c_str());
width_hint = max(width_hint, int(children[0]->asInt(true)));
}
break;
@@ -798,9 +808,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
// everything should have been handled above -> print error if not.
default:
for (auto f : log_files)
- current_ast->dumpAst(f, "verilog-ast> ");
- log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n",
- type2str(type).c_str());
+ current_ast_mod->dumpAst(f, "verilog-ast> ");
+ log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n", type2str(type).c_str());
}
if (*found_real)
@@ -845,7 +854,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_FUNCTION:
case AST_DPI_FUNCTION:
case AST_AUTOWIRE:
- case AST_LOCALPARAM:
case AST_DEFPARAM:
case AST_GENVAR:
case AST_GENFOR:
@@ -853,23 +861,71 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_GENIF:
case AST_GENCASE:
case AST_PACKAGE:
+ case AST_MODPORT:
+ case AST_MODPORTMEMBER:
+ break;
+ case AST_INTERFACEPORT: {
+ // If a port in a module with unknown type is found, mark it with the attribute 'is_interface'
+ // This is used by the hierarchy pass to know when it can replace interface connection with the individual
+ // signals.
+ RTLIL::Wire *wire = current_module->addWire(str, 1);
+ wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
+ wire->start_offset = 0;
+ wire->port_id = port_id;
+ wire->port_input = true;
+ wire->port_output = true;
+ wire->set_bool_attribute("\\is_interface");
+ if (children.size() > 0) {
+ for(size_t i=0; i<children.size();i++) {
+ if(children[i]->type == AST_INTERFACEPORTTYPE) {
+ std::pair<std::string,std::string> res = AST::split_modport_from_type(children[i]->str);
+ wire->attributes["\\interface_type"] = res.first;
+ if (res.second != "")
+ wire->attributes["\\interface_modport"] = res.second;
+ break;
+ }
+ }
+ }
+ wire->upto = 0;
+ }
+ break;
+ case AST_INTERFACEPORTTYPE:
break;
// remember the parameter, needed for example in techmap
case AST_PARAMETER:
current_module->avail_parameters.insert(str);
+ /* fall through */
+ case AST_LOCALPARAM:
+ if (flag_pwires)
+ {
+ if (GetSize(children) < 1 || children[0]->type != AST_CONSTANT)
+ log_file_error(filename, linenum, "Parameter `%s' with non-constant value!\n", str.c_str());
+
+ RTLIL::Const val = children[0]->bitsAsConst();
+ RTLIL::Wire *wire = current_module->addWire(str, GetSize(val));
+ current_module->connect(wire, val);
+
+ wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
+ wire->attributes[type == AST_PARAMETER ? "\\parameter" : "\\localparam"] = 1;
+
+ for (auto &attr : attributes) {
+ if (attr.second->type != AST_CONSTANT)
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
+ wire->attributes[attr.first] = attr.second->asAttrConst();
+ }
+ }
break;
// create an RTLIL::Wire for an AST_WIRE node
case AST_WIRE: {
if (current_module->wires_.count(str) != 0)
- log_file_error(filename, linenum, "Re-definition of signal `%s'!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Re-definition of signal `%s'!\n", str.c_str());
if (!range_valid)
- log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n", str.c_str());
- log_assert(range_left >= range_right || (range_left == -1 && range_right == 0));
+ if (!(range_left >= range_right || (range_left == -1 && range_right == 0)))
+ log_file_error(filename, linenum, "Signal `%s' with invalid width range %d!\n", str.c_str(), range_left - range_right + 1);
RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1);
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@@ -881,26 +937,26 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
wire->attributes[attr.first] = attr.second->asAttrConst();
}
+
+ if (is_wand) wire->set_bool_attribute("\\wand");
+ if (is_wor) wire->set_bool_attribute("\\wor");
}
break;
// create an RTLIL::Memory for an AST_MEMORY node
case AST_MEMORY: {
if (current_module->memories.count(str) != 0)
- log_file_error(filename, linenum, "Re-definition of memory `%s'!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Re-definition of memory `%s'!\n", str.c_str());
log_assert(children.size() >= 2);
log_assert(children[0]->type == AST_RANGE);
log_assert(children[1]->type == AST_RANGE);
if (!children[0]->range_valid || !children[1]->range_valid)
- log_file_error(filename, linenum, "Memory `%s' with non-constant width or size!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Memory `%s' with non-constant width or size!\n", str.c_str());
RTLIL::Memory *memory = new RTLIL::Memory;
memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@@ -917,8 +973,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
memory->attributes[attr.first] = attr.second->asAttrConst();
}
}
@@ -926,19 +981,22 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// simply return the corresponding RTLIL::SigSpec for an AST_CONSTANT node
case AST_CONSTANT:
+ case AST_REALVALUE:
{
if (width_hint < 0)
detectSignWidth(width_hint, sign_hint);
-
is_signed = sign_hint;
- return RTLIL::SigSpec(bitsAsConst());
- }
- case AST_REALVALUE:
- {
+ if (type == AST_CONSTANT) {
+ if (is_unsized) {
+ return RTLIL::SigSpec(bitsAsUnsizedConst(width_hint));
+ } else {
+ return RTLIL::SigSpec(bitsAsConst());
+ }
+ }
+
RTLIL::SigSpec sig = realAsConst(width_hint);
- log_file_warning(filename, linenum, "converting real value %e to binary %s.\n",
- realvalue, log_signal(sig));
+ log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
return sig;
}
@@ -949,6 +1007,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
{
RTLIL::Wire *wire = NULL;
RTLIL::SigChunk chunk;
+ bool is_interface = false;
int add_undef_bits_msb = 0;
int add_undef_bits_lsb = 0;
@@ -964,19 +1023,42 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM) {
if (id2ast->children[0]->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n", str.c_str());
chunk = RTLIL::Const(id2ast->children[0]->bits);
goto use_const_chunk;
}
- else if (!id2ast || (id2ast->type != AST_WIRE && id2ast->type != AST_AUTOWIRE &&
- id2ast->type != AST_MEMORY) || current_module->wires_.count(str) == 0)
- log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n",
- str.c_str());
+ else if (id2ast && (id2ast->type == AST_WIRE || id2ast->type == AST_AUTOWIRE || id2ast->type == AST_MEMORY) && current_module->wires_.count(str) != 0) {
+ RTLIL::Wire *current_wire = current_module->wire(str);
+ if (current_wire->get_bool_attribute("\\is_interface"))
+ is_interface = true;
+ // Ignore
+ }
+ // If an identifier is found that is not already known, assume that it is an interface:
+ else if (1) { // FIXME: Check if sv_mode first?
+ is_interface = true;
+ }
+ else {
+ log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n", str.c_str());
+ }
if (id2ast->type == AST_MEMORY)
- log_file_error(filename, linenum, "Identifier `%s' does map to an unexpanded memory!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Identifier `%s' does map to an unexpanded memory!\n", str.c_str());
+
+ // If identifier is an interface, create a RTLIL::SigSpec with a dummy wire with a attribute called 'is_interface'
+ // This makes it possible for the hierarchy pass to see what are interface connections and then replace them
+ // with the individual signals:
+ if (is_interface) {
+ RTLIL::Wire *dummy_wire;
+ std::string dummy_wire_name = "$dummywireforinterface" + str;
+ if (current_module->wires_.count(dummy_wire_name))
+ dummy_wire = current_module->wires_[dummy_wire_name];
+ else {
+ dummy_wire = current_module->addWire(dummy_wire_name);
+ dummy_wire->set_bool_attribute("\\is_interface");
+ }
+ RTLIL::SigSpec tmp = RTLIL::SigSpec(dummy_wire);
+ return tmp;
+ }
wire = current_module->wires_[str];
chunk.wire = wire;
@@ -985,7 +1067,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
use_const_chunk:
if (children.size() != 0) {
- log_assert(children[0]->type == AST_RANGE);
+ if (children[0]->type != AST_RANGE)
+ log_file_error(filename, linenum, "Single range expected.\n");
int source_width = id2ast->range_left - id2ast->range_right + 1;
int source_offset = id2ast->range_right;
if (!children[0]->range_valid) {
@@ -994,9 +1077,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n",
- str.c_str());
- int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
+ int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ?
children[0]->children[1]->clone() : children[0]->children[0]->clone());
fake_ast->children[0]->delete_children();
@@ -1024,10 +1106,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (chunk.offset >= source_width || chunk.offset + chunk.width < 0) {
if (chunk.width == 1)
log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
- str.c_str());
+ str.c_str());
else
- log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting all %d result bits to undef.\n",
- str.c_str(), chunk.width);
+ log_file_warning(filename, linenum, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n",
+ children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width);
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
} else {
if (chunk.width + chunk.offset > source_width) {
@@ -1040,11 +1122,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset += add_undef_bits_lsb;
}
if (add_undef_bits_lsb)
- log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
- str.c_str(), add_undef_bits_lsb);
+ log_file_warning(filename, linenum, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
+ children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb);
if (add_undef_bits_msb)
- log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
- str.c_str(), add_undef_bits_msb);
+ log_file_warning(filename, linenum, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
+ children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb);
}
}
}
@@ -1371,16 +1453,21 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (GetSize(en) != 1)
en = current_module->ReduceBool(NEW_ID, en);
- std::stringstream sstr;
- sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
+ IdString cellname;
+ if (str.empty()) {
+ std::stringstream sstr;
+ sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
+ cellname = sstr.str();
+ } else {
+ cellname = str;
+ }
- RTLIL::Cell *cell = current_module->addCell(sstr.str(), celltype);
+ RTLIL::Cell *cell = current_module->addCell(cellname, celltype);
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -1402,9 +1489,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
new_right.append(right[i]);
}
log_file_warning(filename, linenum, "Ignoring assignment to constant bits:\n"
- " old assignment: %s = %s\n new assignment: %s = %s.\n",
- log_signal(left), log_signal(right),
- log_signal(new_left), log_signal(new_right));
+ " old assignment: %s = %s\n new assignment: %s = %s.\n",
+ log_signal(left), log_signal(right),
+ log_signal(new_left), log_signal(new_right));
left = new_left;
right = new_right;
}
@@ -1422,6 +1509,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::Cell *cell = current_module->addCell(str, "");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
+ // Set attribute 'module_not_derived' which will be cleared again after the hierarchy pass
+ cell->set_bool_attribute("\\module_not_derived");
for (auto it = children.begin(); it != children.end(); it++) {
AstNode *child = *it;
@@ -1432,18 +1521,21 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
continue;
}
if (child->type == AST_PARASET) {
+ int extra_const_flags = 0;
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
if (child->children[0]->type == AST_REALVALUE) {
log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n",
- log_id(cell), log_id(paraname), child->children[0]->realvalue);
+ log_id(cell), log_id(paraname), child->children[0]->realvalue);
+ extra_const_flags = RTLIL::CONST_FLAG_REAL;
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
strnode->cloneInto(child->children[0]);
delete strnode;
}
if (child->children[0]->type != AST_CONSTANT)
log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n",
- log_id(cell), log_id(paraname));
+ log_id(cell), log_id(paraname));
cell->parameters[paraname] = child->children[0]->asParaConst();
+ cell->parameters[paraname].flags |= extra_const_flags;
continue;
}
if (child->type == AST_ARGUMENT) {
@@ -1463,10 +1555,29 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value.\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
+ if (cell->type.in("$specify2", "$specify3")) {
+ int src_width = GetSize(cell->getPort("\\SRC"));
+ int dst_width = GetSize(cell->getPort("\\DST"));
+ bool full = cell->getParam("\\FULL").as_bool();
+ if (!full && src_width != dst_width)
+ log_file_error(filename, linenum, "Parallel specify SRC width does not match DST width.\n");
+ if (cell->type == "$specify3") {
+ int dat_width = GetSize(cell->getPort("\\DAT"));
+ if (dat_width != dst_width)
+ log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n");
+ }
+ cell->setParam("\\SRC_WIDTH", Const(src_width));
+ cell->setParam("\\DST_WIDTH", Const(dst_width));
+ }
+ if (cell->type == "$specrule") {
+ int src_width = GetSize(cell->getPort("\\SRC"));
+ int dst_width = GetSize(cell->getPort("\\DST"));
+ cell->setParam("\\SRC_WIDTH", Const(src_width));
+ cell->setParam("\\DST_WIDTH", Const(dst_width));
+ }
}
break;
@@ -1484,6 +1595,37 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
delete always;
} break;
+ case AST_TECALL: {
+ int sz = children.size();
+ if (str == "$info") {
+ if (sz > 0)
+ log_file_info(filename, linenum, "%s.\n", children[0]->str.c_str());
+ else
+ log_file_info(filename, linenum, "\n");
+ } else if (str == "$warning") {
+ if (sz > 0)
+ log_file_warning(filename, linenum, "%s.\n", children[0]->str.c_str());
+ else
+ log_file_warning(filename, linenum, "\n");
+ } else if (str == "$error") {
+ if (sz > 0)
+ log_file_error(filename, linenum, "%s.\n", children[0]->str.c_str());
+ else
+ log_file_error(filename, linenum, "\n");
+ } else if (str == "$fatal") {
+ // TODO: 1st parameter, if exists, is 0,1 or 2, and passed to $finish()
+ // if no parameter is given, default value is 1
+ // dollar_finish(sz ? children[0] : 1);
+ // perhaps create & use log_file_fatal()
+ if (sz > 0)
+ log_file_error(filename, linenum, "FATAL: %s.\n", children[0]->str.c_str());
+ else
+ log_file_error(filename, linenum, "FATAL.\n");
+ } else {
+ log_file_error(filename, linenum, "Unknown elabortoon system task '%s'.\n", str.c_str());
+ }
+ } break;
+
case AST_FCALL: {
if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq")
{
@@ -1492,18 +1634,17 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (GetSize(children) > 1)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 0.\n",
- RTLIL::unescape_id(str).c_str(), GetSize(children));
+ RTLIL::unescape_id(str).c_str(), GetSize(children));
if (GetSize(children) == 1) {
if (children[0]->type != AST_CONSTANT)
log_file_error(filename, linenum, "System function %s called with non-const argument!\n",
- RTLIL::unescape_id(str).c_str());
+ RTLIL::unescape_id(str).c_str());
width = children[0]->asInt(true);
}
if (width <= 0)
- log_file_error(filename, linenum, "Failed to detect width of %s!\n",
- RTLIL::unescape_id(str).c_str());
+ log_file_error(filename, linenum, "Failed to detect width of %s!\n", RTLIL::unescape_id(str).c_str());
Cell *cell = current_module->addCell(myid, str.substr(1));
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@@ -1528,10 +1669,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// everything should have been handled above -> print error if not.
default:
for (auto f : log_files)
- current_ast->dumpAst(f, "verilog-ast> ");
+ current_ast_mod->dumpAst(f, "verilog-ast> ");
type_name = type2str(type);
- log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n",
- type_name.c_str());
+ log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n", type_name.c_str());
}
return RTLIL::SigSpec();
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index aa3b982d..e947125b 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -50,7 +50,6 @@ using namespace AST_INTERNAL;
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
{
static int recursion_counter = 0;
- static pair<string, int> last_blocking_assignment_warn;
static bool deep_recursion_warning = false;
if (recursion_counter++ == 1000 && deep_recursion_warning) {
@@ -71,8 +70,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (stage == 0)
{
- log_assert(type == AST_MODULE);
- last_blocking_assignment_warn = pair<string, int>();
+ log_assert(type == AST_MODULE || type == AST_INTERFACE);
deep_recursion_warning = true;
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
@@ -113,6 +111,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS)
goto verbose_activate;
+ if ((memflags & AstNode::MEM2REG_FL_CONST_LHS) && !(memflags & AstNode::MEM2REG_FL_VAR_LHS))
+ goto verbose_activate;
+
// log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags));
continue;
@@ -137,9 +138,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int mem_width, mem_size, addr_bits;
node->meminfo(mem_width, mem_size, addr_bits);
+ int data_range_left = node->children[0]->range_left;
+ int data_range_right = node->children[0]->range_right;
+
+ if (node->children[0]->range_swapped)
+ std::swap(data_range_left, data_range_right);
+
for (int i = 0; i < mem_size; i++) {
AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE,
- mkconst_int(mem_width-1, true), mkconst_int(0, true)));
+ mkconst_int(data_range_left, true), mkconst_int(data_range_right, true)));
reg->str = stringf("%s[%d]", node->str.c_str(), i);
reg->is_reg = true;
reg->is_signed = node->is_signed;
@@ -196,7 +203,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int nargs = GetSize(children);
if (nargs < 1)
log_file_error(filename, linenum, "System task `%s' got %d arguments, expected >= 1.\n",
- str.c_str(), int(children.size()));
+ str.c_str(), int(children.size()));
// First argument is the format string
AstNode *node_string = children[0];
@@ -240,7 +247,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
case 'X':
if (next_arg >= GetSize(children))
log_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n",
- cformat, str.c_str());
+ cformat, str.c_str());
node_arg = children[next_arg++];
while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
@@ -325,6 +332,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
for (size_t i = 0; i < children.size(); i++) {
AstNode *node = children[i];
if (node->type == AST_WIRE) {
+ if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
+ for (auto c : node->children[0]->children) {
+ if (!c->is_simple_const_expr()) {
+ if (attributes.count("\\dynports"))
+ delete attributes.at("\\dynports");
+ attributes["\\dynports"] = AstNode::mkconst_int(1, true);
+ }
+ }
+ }
if (this_wire_scope.count(node->str) > 0) {
AstNode *first_node = this_wire_scope[node->str];
if (first_node->is_input && node->is_reg)
@@ -450,8 +466,21 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
children[0]->id2ast->is_reg = true; // if logic type is used in a block asignment
if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && !children[0]->id2ast->is_reg)
log_warning("wire '%s' is assigned in a block at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum);
- if (type == AST_ASSIGN && children[0]->id2ast->is_reg)
- log_warning("reg '%s' is assigned in a continuous assignment at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum);
+ if (type == AST_ASSIGN && children[0]->id2ast->is_reg) {
+ bool is_rand_reg = false;
+ if (children[1]->type == AST_FCALL) {
+ if (children[1]->str == "\\$anyconst")
+ is_rand_reg = true;
+ if (children[1]->str == "\\$anyseq")
+ is_rand_reg = true;
+ if (children[1]->str == "\\$allconst")
+ is_rand_reg = true;
+ if (children[1]->str == "\\$allseq")
+ is_rand_reg = true;
+ }
+ if (!is_rand_reg)
+ log_warning("reg '%s' is assigned in a continuous assignment at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum);
+ }
children[0]->was_checked = true;
}
break;
@@ -629,6 +658,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// (iterate by index as e.g. auto wires can add new children in the process)
for (size_t i = 0; i < children.size(); i++) {
bool did_something_here = true;
+ bool backup_flag_autowire = flag_autowire;
if ((type == AST_GENFOR || type == AST_FOR) && i >= 3)
break;
if ((type == AST_GENIF || type == AST_GENCASE) && i >= 1)
@@ -639,6 +669,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
break;
if (type == AST_PREFIX && i >= 1)
break;
+ if (type == AST_DEFPARAM && i == 0)
+ flag_autowire = true;
while (did_something_here && i < children.size()) {
bool const_fold_here = const_fold, in_lvalue_here = in_lvalue;
int width_hint_here = width_hint;
@@ -673,6 +705,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
children.erase(children.begin() + (i--));
did_something = true;
}
+ flag_autowire = backup_flag_autowire;
}
for (auto &attr : attributes) {
while (attr.second->simplify(true, false, false, stage, -1, false, true))
@@ -732,7 +765,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (current_scope.at(modname)->type != AST_CELL)
log_file_error(filename, linenum, "Defparam argument `%s . %s` does not match a cell!\n",
- RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str());
+ RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str());
AstNode *paraset = new AstNode(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : NULL);
paraset->str = paramname;
@@ -880,7 +913,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (children[0]->type == AST_REALVALUE) {
RTLIL::Const constvalue = children[0]->realAsConst(width);
log_file_warning(filename, linenum, "converting real value %e to binary %s.\n",
- children[0]->realvalue, log_signal(constvalue));
+ children[0]->realvalue, log_signal(constvalue));
delete children[0];
children[0] = mkconst_bits(constvalue.bits, sign_hint);
did_something = true;
@@ -921,12 +954,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
if (current_scope.count(str) == 0) {
- // log_warning("Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str());
- AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
- auto_wire->str = str;
- current_ast_mod->children.push_back(auto_wire);
- current_scope[str] = auto_wire;
- did_something = true;
+ if (flag_autowire || str == "\\$global_clock") {
+ AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
+ auto_wire->str = str;
+ current_ast_mod->children.push_back(auto_wire);
+ current_scope[str] = auto_wire;
+ did_something = true;
+ } else {
+ log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
+ }
}
if (id2ast != current_scope[str]) {
id2ast = current_scope[str];
@@ -946,6 +982,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int data_range_left = id2ast->children[0]->range_left;
int data_range_right = id2ast->children[0]->range_right;
+ if (id2ast->children[0]->range_swapped)
+ std::swap(data_range_left, data_range_right);
+
std::stringstream sstr;
sstr << "$mem2bits$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string wire_id = sstr.str();
@@ -991,7 +1030,26 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n");
if (type == AST_REPEAT)
- log_file_error(filename, linenum, "Repeat loops are only allowed in constant functions!\n");
+ {
+ AstNode *count = children[0];
+ AstNode *body = children[1];
+
+ // eval count expression
+ while (count->simplify(true, false, false, stage, 32, true, false)) { }
+
+ if (count->type != AST_CONSTANT)
+ log_file_error(filename, linenum, "Repeat loops outside must have constant repeat counts!\n");
+
+ // convert to a block with the body repeated n times
+ type = AST_BLOCK;
+ children.clear();
+ for (int i = 0; i < count->bitsAsConst().as_int(); i++)
+ children.insert(children.begin(), body->clone());
+
+ delete count;
+ delete body;
+ did_something = true;
+ }
// unroll for loops and generate-for blocks
if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0)
@@ -1027,7 +1085,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 1st expression
AstNode *varbuf = init_ast->children[1]->clone();
- while (varbuf->simplify(true, false, false, stage, 32, true, false)) { }
+ {
+ int expr_width_hint = -1;
+ bool expr_sign_hint = true;
+ varbuf->detectSignWidth(expr_width_hint, expr_sign_hint);
+ while (varbuf->simplify(true, false, false, stage, 32, true, false)) { }
+ }
if (varbuf->type != AST_CONSTANT)
log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n");
@@ -1049,7 +1112,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
// eval 2nd expression
AstNode *buf = while_ast->clone();
- while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ {
+ int expr_width_hint = -1;
+ bool expr_sign_hint = true;
+ buf->detectSignWidth(expr_width_hint, expr_sign_hint);
+ while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, false)) { }
+ }
if (buf->type != AST_CONSTANT)
log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n");
@@ -1090,7 +1158,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 3rd expression
buf = next_ast->children[1]->clone();
- while (buf->simplify(true, false, false, stage, 32, true, false)) { }
+ {
+ int expr_width_hint = -1;
+ bool expr_sign_hint = true;
+ buf->detectSignWidth(expr_width_hint, expr_sign_hint);
+ while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, true)) { }
+ }
if (buf->type != AST_CONSTANT)
log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n");
@@ -1099,6 +1172,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
varbuf->children[0] = buf;
}
+ if (type == AST_FOR) {
+ AstNode *buf = next_ast->clone();
+ delete buf->children[1];
+ buf->children[1] = varbuf->children[0]->clone();
+ current_block->children.insert(current_block->children.begin() + current_block_idx++, buf);
+ }
+
current_scope[varbuf->str] = backup_scope_varbuf;
delete varbuf;
delete_children();
@@ -1299,8 +1379,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_PRIMITIVE)
{
if (children.size() < 2)
- log_file_error(filename, linenum, "Insufficient number of arguments for primitive `%s'!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Insufficient number of arguments for primitive `%s'!\n", str.c_str());
std::vector<AstNode*> children_list;
for (auto child : children) {
@@ -1315,8 +1394,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (str == "bufif0" || str == "bufif1" || str == "notif0" || str == "notif1")
{
if (children_list.size() != 3)
- log_file_error(filename, linenum, "Invalid number of arguments for primitive `%s'!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Invalid number of arguments for primitive `%s'!\n", str.c_str());
std::vector<RTLIL::State> z_const(1, RTLIL::State::Sz);
@@ -1336,6 +1414,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
str.clear();
type = AST_ASSIGN;
children.push_back(children_list.at(0));
+ children.back()->was_checked = true;
children.push_back(node);
did_something = true;
}
@@ -1372,6 +1451,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
str.clear();
type = AST_ASSIGN;
children.push_back(children_list[0]);
+ children.back()->was_checked = true;
children.push_back(node);
did_something = true;
}
@@ -1401,8 +1481,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
while (left_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
}
did_something = true;
@@ -1480,6 +1559,7 @@ skip_dynamic_range_lvalue_expansion:;
newNode->children.push_back(assign_en);
AstNode *assertnode = new AstNode(type);
+ assertnode->str = str;
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children[0]->str = id_check;
@@ -1525,11 +1605,13 @@ skip_dynamic_range_lvalue_expansion:;
current_scope[wire_tmp->str] = wire_tmp;
wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { }
+ wire_tmp->is_logic = true;
AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER);
wire_tmp_id->str = wire_tmp->str;
newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, wire_tmp_id, children[1]->clone()));
+ newNode->children.back()->was_checked = true;
int cursor = 0;
for (auto child : children[0]->children)
@@ -1559,14 +1641,6 @@ skip_dynamic_range_lvalue_expansion:;
sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
- if (type == AST_ASSIGN_EQ) {
- pair<string, int> this_blocking_assignment_warn(filename, linenum);
- if (this_blocking_assignment_warn != last_blocking_assignment_warn)
- log_warning("Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
- filename.c_str(), linenum);
- last_blocking_assignment_warn = this_blocking_assignment_warn;
- }
-
int mem_width, mem_size, addr_bits;
bool mem_signed = children[0]->id2ast->is_signed;
children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
@@ -1676,7 +1750,7 @@ skip_dynamic_range_lvalue_expansion:;
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
- int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
+ int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));
@@ -1765,18 +1839,18 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "\\$past")
{
- if (width_hint <= 0)
+ if (width_hint < 0)
goto replace_fcall_later;
int num_steps = 1;
if (GetSize(children) != 1 && GetSize(children) != 2)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
if (!current_always_clocked)
log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n",
- RTLIL::unescape_id(str).c_str());
+ RTLIL::unescape_id(str).c_str());
if (GetSize(children) == 2)
{
@@ -1797,6 +1871,11 @@ skip_dynamic_range_lvalue_expansion:;
log_assert(block != nullptr);
+ if (num_steps == 0) {
+ newNode = children[0]->clone();
+ goto apply_newNode;
+ }
+
int myidx = autoidx++;
AstNode *outreg = nullptr;
@@ -1815,6 +1894,7 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *regid = new AstNode(AST_IDENTIFIER);
regid->str = reg->str;
regid->id2ast = reg;
+ regid->was_checked = true;
AstNode *rhs = nullptr;
@@ -1836,15 +1916,15 @@ skip_dynamic_range_lvalue_expansion:;
goto apply_newNode;
}
- if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell")
+ if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell" || str == "\\$changed")
{
if (GetSize(children) != 1)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
if (!current_always_clocked)
log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n",
- RTLIL::unescape_id(str).c_str());
+ RTLIL::unescape_id(str).c_str());
AstNode *present = children.at(0)->clone();
AstNode *past = clone();
@@ -1853,11 +1933,18 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "\\$stable")
newNode = new AstNode(AST_EQ, past, present);
+ else if (str == "\\$changed")
+ newNode = new AstNode(AST_NE, past, present);
+
else if (str == "\\$rose")
- newNode = new AstNode(AST_LOGIC_AND, new AstNode(AST_LOGIC_NOT, past), present);
+ newNode = new AstNode(AST_LOGIC_AND,
+ new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, past, mkconst_int(1,false))),
+ new AstNode(AST_BIT_AND, present, mkconst_int(1,false)));
else if (str == "\\$fell")
- newNode = new AstNode(AST_LOGIC_AND, past, new AstNode(AST_LOGIC_NOT, present));
+ newNode = new AstNode(AST_LOGIC_AND,
+ new AstNode(AST_BIT_AND, past, mkconst_int(1,false)),
+ new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, present, mkconst_int(1,false))));
else
log_abort();
@@ -1875,7 +1962,7 @@ skip_dynamic_range_lvalue_expansion:;
{
if (children.size() != 1)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
AstNode *buf = children[0]->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
@@ -1892,7 +1979,7 @@ skip_dynamic_range_lvalue_expansion:;
if (arg_value.bits.at(i) == RTLIL::State::S1)
result = i + 1;
- newNode = mkconst_int(result, false);
+ newNode = mkconst_int(result, true);
goto apply_newNode;
}
@@ -1900,11 +1987,11 @@ skip_dynamic_range_lvalue_expansion:;
{
if (str == "\\$bits" && children.size() != 1)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
if (str == "\\$size" && children.size() != 1 && children.size() != 2)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
int dim = 1;
if (str == "\\$size" && children.size() == 2) {
@@ -1978,18 +2065,18 @@ skip_dynamic_range_lvalue_expansion:;
if (func_with_two_arguments) {
if (children.size() != 2)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 2.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
} else {
if (children.size() != 1)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
}
if (children.size() >= 1) {
while (children[0]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (!children[0]->isConst())
log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n",
- RTLIL::unescape_id(str).c_str());
+ RTLIL::unescape_id(str).c_str());
int child_width_hint = width_hint;
bool child_sign_hint = sign_hint;
children[0]->detectSignWidth(child_width_hint, child_sign_hint);
@@ -2000,7 +2087,7 @@ skip_dynamic_range_lvalue_expansion:;
while (children[1]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (!children[1]->isConst())
log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n",
- RTLIL::unescape_id(str).c_str());
+ RTLIL::unescape_id(str).c_str());
int child_width_hint = width_hint;
bool child_sign_hint = sign_hint;
children[1]->detectSignWidth(child_width_hint, child_sign_hint);
@@ -2088,7 +2175,7 @@ skip_dynamic_range_lvalue_expansion:;
{
if (GetSize(children) < 2 || GetSize(children) > 4)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 2-4.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
AstNode *node_filename = children[0]->clone();
while (node_filename->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
@@ -2136,6 +2223,8 @@ skip_dynamic_range_lvalue_expansion:;
}
newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init);
+ delete node_filename;
+ delete node_memory;
goto apply_newNode;
}
@@ -2177,6 +2266,8 @@ skip_dynamic_range_lvalue_expansion:;
std::map<std::string, std::string> replace_rules;
vector<AstNode*> added_mod_children;
dict<std::string, AstNode*> wire_cache;
+ vector<AstNode*> new_stmts;
+ vector<AstNode*> output_assignments;
if (current_block == NULL)
{
@@ -2201,6 +2292,8 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *always = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK,
new AstNode(AST_ASSIGN_EQ, lvalue, clone())));
+ always->children[0]->children[0]->was_checked = true;
+
current_ast_mod->children.push_back(always);
goto replace_fcall_with_id;
@@ -2250,6 +2343,7 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *assign = child->is_input ?
new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg) :
new AstNode(AST_ASSIGN_EQ, arg, wire_id->clone());
+ assign->children[0]->was_checked = true;
for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
if (*it != current_block_child)
@@ -2298,8 +2392,8 @@ skip_dynamic_range_lvalue_expansion:;
wire->port_id = 0;
wire->is_input = false;
wire->is_output = false;
- if (!child->is_output)
- wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
+ wire->is_reg = true;
+ wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
wire_cache[child->str] = wire;
current_ast_mod->children.push_back(wire);
@@ -2320,13 +2414,11 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *assign = child->is_input ?
new AstNode(AST_ASSIGN_EQ, wire_id, arg) :
new AstNode(AST_ASSIGN_EQ, arg, wire_id);
-
- for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
- if (*it != current_block_child)
- continue;
- current_block->children.insert(it, assign);
- break;
- }
+ assign->children[0]->was_checked = true;
+ if (child->is_input)
+ new_stmts.push_back(assign);
+ else
+ output_assignments.push_back(assign);
}
}
@@ -2340,14 +2432,18 @@ skip_dynamic_range_lvalue_expansion:;
{
AstNode *stmt = child->clone();
stmt->replace_ids(prefix, replace_rules);
+ new_stmts.push_back(stmt);
+ }
- for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
- if (*it != current_block_child)
- continue;
- current_block->children.insert(it, stmt);
- break;
- }
+ new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end());
+
+ for (auto it = current_block->children.begin(); ; it++) {
+ log_assert(it != current_block->children.end());
+ if (*it == current_block_child) {
+ current_block->children.insert(it, new_stmts.begin(), new_stmts.end());
+ break;
}
+ }
replace_fcall_with_id:
if (type == AST_FCALL) {
@@ -2759,6 +2855,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value));
block->children.back()->children[0]->str = memory->str;
block->children.back()->children[0]->id2ast = memory;
+ block->children.back()->children[0]->was_checked = true;
}
cursor += increment;
@@ -2817,7 +2914,11 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
for (size_t i = 0; i < children.size(); i++) {
AstNode *child = children[i];
- if (child->type != AST_FUNCTION && child->type != AST_TASK && child->type != AST_PREFIX)
+ // AST_PREFIX member names should not be prefixed; a nested AST_PREFIX
+ // still needs to recursed-into
+ if (type == AST_PREFIX && i == 1 && child->type == AST_IDENTIFIER)
+ continue;
+ if (child->type != AST_FUNCTION && child->type != AST_TASK)
child->expand_genblock(index_var, prefix, name_map);
}
@@ -2872,7 +2973,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
{
uint32_t children_flags = 0;
- int ignore_children_counter = 0;
+ int lhs_children_counter = 0;
if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)
{
@@ -2898,6 +2999,16 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1;
}
+ // for proper (non-init) writes: remember if this is a constant index or not
+ if ((flags & MEM2REG_FL_INIT) == 0) {
+ if (children[0]->children.size() && children[0]->children[0]->type == AST_RANGE && children[0]->children[0]->children.size()) {
+ if (children[0]->children[0]->children[0]->type == AST_CONSTANT)
+ mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS;
+ else
+ mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS;
+ }
+ }
+
// remember where this is
if (flags & MEM2REG_FL_INIT) {
if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT))
@@ -2910,7 +3021,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
}
}
- ignore_children_counter = 1;
+ lhs_children_counter = 1;
}
if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY)
@@ -2953,12 +3064,23 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
log_assert((flags & ~0x000000ff) == 0);
for (auto child : children)
- if (ignore_children_counter > 0)
- ignore_children_counter--;
- else if (proc_flags_p)
+ {
+ if (lhs_children_counter > 0) {
+ lhs_children_counter--;
+ if (child->children.size() && child->children[0]->type == AST_RANGE && child->children[0]->children.size()) {
+ for (auto c : child->children[0]->children) {
+ if (proc_flags_p)
+ c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
+ else
+ c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
+ }
+ }
+ } else
+ if (proc_flags_p)
child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
else
child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
+ }
flags &= ~children_flags | backup_flags;
@@ -3010,6 +3132,39 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
if (type == AST_FUNCTION || type == AST_TASK)
return false;
+ if (type == AST_MEMINIT && id2ast && mem2reg_set.count(id2ast))
+ {
+ log_assert(children[0]->type == AST_CONSTANT);
+ log_assert(children[1]->type == AST_CONSTANT);
+ log_assert(children[2]->type == AST_CONSTANT);
+
+ int cursor = children[0]->asInt(false);
+ Const data = children[1]->bitsAsConst();
+ int length = children[2]->asInt(false);
+
+ if (length != 0)
+ {
+ AstNode *block = new AstNode(AST_INITIAL, new AstNode(AST_BLOCK));
+ mod->children.push_back(block);
+ block = block->children[0];
+
+ int wordsz = GetSize(data) / length;
+
+ for (int i = 0; i < length; i++) {
+ block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false))), mkconst_bits(data.extract(i*wordsz, wordsz).bits, false)));
+ block->children.back()->children[0]->str = str;
+ block->children.back()->children[0]->id2ast = id2ast;
+ block->children.back()->children[0]->was_checked = true;
+ }
+ }
+
+ AstNode *newNode = new AstNode(AST_NONE);
+ newNode->cloneInto(this);
+ delete newNode;
+
+ did_something = true;
+ }
+
if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set))
{
if (async_block == NULL) {
@@ -3019,6 +3174,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
AstNode *newNode = clone();
newNode->type = AST_ASSIGN_EQ;
+ newNode->children[0]->was_checked = true;
async_block->children[0]->children.push_back(newNode);
newNode = new AstNode(AST_NONE);
@@ -3064,6 +3220,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone());
assign_addr->children[0]->str = id_addr;
+ assign_addr->children[0]->was_checked = true;
block->children.insert(block->children.begin()+assign_idx+1, assign_addr);
AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER));
@@ -3087,6 +3244,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
children[0]->id2ast = NULL;
children[0]->str = id_data;
type = AST_ASSIGN_EQ;
+ children[0]->was_checked = true;
did_something = true;
}
@@ -3236,6 +3394,16 @@ bool AstNode::has_const_only_constructs(bool &recommend_const_eval)
return false;
}
+bool AstNode::is_simple_const_expr()
+{
+ if (type == AST_IDENTIFIER)
+ return false;
+ for (auto child : children)
+ if (!child->is_simple_const_expr())
+ return false;
+ return true;
+}
+
// helper function for AstNode::eval_const_function()
void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall)
{
@@ -3244,12 +3412,12 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia
if (!children.empty()) {
if (children.size() != 1 || children.at(0)->type != AST_RANGE)
log_file_error(filename, linenum, "Memory access in constant function is not supported\n%s:%d: ...called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
children.at(0)->replace_variables(variables, fcall);
while (simplify(true, false, false, 1, -1, false, true)) { }
if (!children.at(0)->range_valid)
log_file_error(filename, linenum, "Non-constant range\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
offset = min(children.at(0)->range_left, children.at(0)->range_right);
width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
}
@@ -3289,7 +3457,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
while (child->simplify(true, false, false, 1, -1, false, true)) { }
if (!child->range_valid)
log_file_error(child->filename, child->linenum, "Can't determine size of variable %s\n%s:%d: ... called from here.\n",
- child->str.c_str(), fcall->filename.c_str(), fcall->linenum);
+ child->str.c_str(), fcall->filename.c_str(), fcall->linenum);
variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1);
variables[child->str].offset = min(child->range_left, child->range_right);
variables[child->str].is_signed = child->is_signed;
@@ -3333,15 +3501,15 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (stmt->children.at(1)->type != AST_CONSTANT)
log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here. X\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
if (stmt->children.at(0)->type != AST_IDENTIFIER)
log_file_error(stmt->filename, stmt->linenum, "Unsupported composite left hand side in constant function\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
if (!variables.count(stmt->children.at(0)->str))
log_file_error(stmt->filename, stmt->linenum, "Assignment to non-local variable in constant function\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
if (stmt->children.at(0)->children.empty()) {
variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size());
@@ -3349,7 +3517,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
AstNode *range = stmt->children.at(0)->children.at(0);
if (!range->range_valid)
log_file_error(range->filename, range->linenum, "Non-constant range\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
int offset = min(range->range_left, range->range_right);
int width = std::abs(range->range_left - range->range_right) + 1;
varinfo_t &v = variables[stmt->children.at(0)->str];
@@ -3381,7 +3549,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (cond->type != AST_CONSTANT)
log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
if (cond->asBool()) {
block->children.insert(block->children.begin(), stmt->children.at(1)->clone());
@@ -3402,7 +3570,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (num->type != AST_CONSTANT)
log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
block->children.erase(block->children.begin());
for (int i = 0; i < num->bitsAsConst().as_int(); i++)
@@ -3440,7 +3608,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (cond->type != AST_CONSTANT)
log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
found_match = cond->asBool();
delete cond;
@@ -3470,7 +3638,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
}
log_file_error(stmt->filename, stmt->linenum, "Unsupported language construct in constant function\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
log_abort();
}
diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc
index 9116b257..a6a07863 100644
--- a/frontends/blif/blifparse.cc
+++ b/frontends/blif/blifparse.cc
@@ -584,7 +584,7 @@ struct BlifFrontend : public Frontend {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" read_blif [filename]\n");
+ log(" read_blif [options] [filename]\n");
log("\n");
log("Load modules from a BLIF file into the current design.\n");
log("\n");
diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc
index d8783ac1..30d9ff79 100644
--- a/frontends/ilang/ilang_frontend.cc
+++ b/frontends/ilang/ilang_frontend.cc
@@ -44,11 +44,47 @@ struct IlangFrontend : public Frontend {
log("Load modules from an ilang file to the current design. (ilang is a text\n");
log("representation of a design in yosys's internal format.)\n");
log("\n");
+ log(" -nooverwrite\n");
+ log(" ignore re-definitions of modules. (the default behavior is to\n");
+ log(" create an error message if the existing module is not a blackbox\n");
+ log(" module, and overwrite the existing module if it is a blackbox module.)\n");
+ log("\n");
+ log(" -overwrite\n");
+ log(" overwrite existing modules with the same name\n");
+ log("\n");
+ log(" -lib\n");
+ log(" only create empty blackbox modules\n");
+ log("\n");
}
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
+ ILANG_FRONTEND::flag_nooverwrite = false;
+ ILANG_FRONTEND::flag_overwrite = false;
+ ILANG_FRONTEND::flag_lib = false;
+
log_header(design, "Executing ILANG frontend.\n");
- extra_args(f, filename, args, 1);
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ std::string arg = args[argidx];
+ if (arg == "-nooverwrite") {
+ ILANG_FRONTEND::flag_nooverwrite = true;
+ ILANG_FRONTEND::flag_overwrite = false;
+ continue;
+ }
+ if (arg == "-overwrite") {
+ ILANG_FRONTEND::flag_nooverwrite = false;
+ ILANG_FRONTEND::flag_overwrite = true;
+ continue;
+ }
+ if (arg == "-lib") {
+ ILANG_FRONTEND::flag_lib = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
log("Input filename: %s\n", filename.c_str());
ILANG_FRONTEND::lexin = f;
diff --git a/frontends/ilang/ilang_frontend.h b/frontends/ilang/ilang_frontend.h
index ad3ffec9..f8a15284 100644
--- a/frontends/ilang/ilang_frontend.h
+++ b/frontends/ilang/ilang_frontend.h
@@ -32,6 +32,9 @@ YOSYS_NAMESPACE_BEGIN
namespace ILANG_FRONTEND {
extern std::istream *lexin;
extern RTLIL::Design *current_design;
+ extern bool flag_nooverwrite;
+ extern bool flag_overwrite;
+ extern bool flag_lib;
}
YOSYS_NAMESPACE_END
diff --git a/frontends/ilang/ilang_lexer.l b/frontends/ilang/ilang_lexer.l
index d8e01ae4..4fd0ae85 100644
--- a/frontends/ilang/ilang_lexer.l
+++ b/frontends/ilang/ilang_lexer.l
@@ -53,6 +53,7 @@ USING_YOSYS_NAMESPACE
"attribute" { return TOK_ATTRIBUTE; }
"parameter" { return TOK_PARAMETER; }
"signed" { return TOK_SIGNED; }
+"real" { return TOK_REAL; }
"wire" { return TOK_WIRE; }
"memory" { return TOK_MEMORY; }
"width" { return TOK_WIDTH; }
diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y
index bfc062fe..b4b9693d 100644
--- a/frontends/ilang/ilang_parser.y
+++ b/frontends/ilang/ilang_parser.y
@@ -37,13 +37,24 @@ namespace ILANG_FRONTEND {
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
std::vector<RTLIL::CaseRule*> case_stack;
dict<RTLIL::IdString, RTLIL::Const> attrbuf;
+ bool flag_nooverwrite, flag_overwrite, flag_lib;
+ bool delete_current_module;
}
using namespace ILANG_FRONTEND;
YOSYS_NAMESPACE_END
USING_YOSYS_NAMESPACE
%}
-%name-prefix "rtlil_frontend_ilang_yy"
+%define api.prefix {rtlil_frontend_ilang_yy}
+
+/* The union is defined in the header, so we need to provide all the
+ * includes it requires
+ */
+%code requires {
+#include <string>
+#include <vector>
+#include "frontends/ilang/ilang_frontend.h"
+}
%union {
char *string;
@@ -59,7 +70,7 @@ USING_YOSYS_NAMESPACE
%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT
%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
-%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO
+%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO
%type <rsigspec> sigspec_list_reversed
%type <sigspec> sigspec sigspec_list
@@ -93,18 +104,38 @@ design:
module:
TOK_MODULE TOK_ID EOL {
- if (current_design->has($2))
- rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str());
+ delete_current_module = false;
+ if (current_design->has($2)) {
+ RTLIL::Module *existing_mod = current_design->module($2);
+ if (!flag_overwrite && (flag_lib || (attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()))) {
+ log("Ignoring blackbox re-definition of module %s.\n", $2);
+ delete_current_module = true;
+ } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
+ rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str());
+ } else if (flag_nooverwrite) {
+ log("Ignoring re-definition of module %s.\n", $2);
+ delete_current_module = true;
+ } else {
+ log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", $2);
+ current_design->remove(existing_mod);
+ }
+ }
current_module = new RTLIL::Module;
current_module->name = $2;
current_module->attributes = attrbuf;
- current_design->add(current_module);
+ if (!delete_current_module)
+ current_design->add(current_module);
attrbuf.clear();
free($2);
} module_body TOK_END {
if (attrbuf.size() != 0)
rtlil_frontend_ilang_yyerror("dangling attribute");
current_module->fixup_ports();
+ if (delete_current_module)
+ delete current_module;
+ else if (flag_lib)
+ current_module->makeblackbox();
+ current_module = nullptr;
} EOL;
module_body:
@@ -219,6 +250,12 @@ cell_body:
free($4);
delete $5;
} |
+ cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL {
+ current_cell->parameters[$4] = *$5;
+ current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL;
+ free($4);
+ delete $5;
+ } |
cell_body TOK_CONNECT TOK_ID sigspec EOL {
if (current_cell->hasPort($3))
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
@@ -245,14 +282,14 @@ proc_stmt:
} case_body sync_list TOK_END EOL;
switch_stmt:
- attr_list TOK_SWITCH sigspec EOL {
+ TOK_SWITCH sigspec EOL {
RTLIL::SwitchRule *rule = new RTLIL::SwitchRule;
- rule->signal = *$3;
+ rule->signal = *$2;
rule->attributes = attrbuf;
switch_stack.back()->push_back(rule);
attrbuf.clear();
- delete $3;
- } switch_body TOK_END EOL;
+ delete $2;
+ } attr_list switch_body TOK_END EOL;
attr_list:
/* empty */ |
@@ -261,9 +298,11 @@ attr_list:
switch_body:
switch_body TOK_CASE {
RTLIL::CaseRule *rule = new RTLIL::CaseRule;
+ rule->attributes = attrbuf;
switch_stack.back()->back()->cases.push_back(rule);
switch_stack.push_back(&rule->switches);
case_stack.push_back(rule);
+ attrbuf.clear();
} compare_list EOL case_body {
switch_stack.pop_back();
case_stack.pop_back();
@@ -282,12 +321,15 @@ compare_list:
/* empty */;
case_body:
+ case_body attr_stmt |
case_body switch_stmt |
case_body assign_stmt |
/* empty */;
assign_stmt:
TOK_ASSIGN sigspec sigspec EOL {
+ if (attrbuf.size() != 0)
+ rtlil_frontend_ilang_yyerror("dangling attribute");
case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3));
delete $2;
delete $3;
@@ -387,17 +429,13 @@ sigspec:
$$ = new RTLIL::SigSpec(current_module->wires_[$1]);
free($1);
} |
- TOK_ID '[' TOK_INT ']' {
- if (current_module->wires_.count($1) == 0)
- rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
- $$ = new RTLIL::SigSpec(current_module->wires_[$1], $3);
- free($1);
+ sigspec '[' TOK_INT ']' {
+ $$ = new RTLIL::SigSpec($1->extract($3));
+ delete $1;
} |
- TOK_ID '[' TOK_INT ':' TOK_INT ']' {
- if (current_module->wires_.count($1) == 0)
- rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
- $$ = new RTLIL::SigSpec(current_module->wires_[$1], $5, $3 - $5 + 1);
- free($1);
+ sigspec '[' TOK_INT ':' TOK_INT ']' {
+ $$ = new RTLIL::SigSpec($1->extract($5, $3 - $5 + 1));
+ delete $1;
} |
'{' sigspec_list '}' {
$$ = $2;
@@ -427,4 +465,3 @@ conn_stmt:
delete $2;
delete $3;
};
-
diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc
index 82361ea9..f5ae8eb7 100644
--- a/frontends/json/jsonparse.cc
+++ b/frontends/json/jsonparse.cc
@@ -292,6 +292,18 @@ void json_import(Design *design, string &modname, JsonNode *node)
if (port_wire == nullptr)
port_wire = module->addWire(port_name, GetSize(port_bits_node->data_array));
+ if (port_node->data_dict.count("upto") != 0) {
+ JsonNode *val = port_node->data_dict.at("upto");
+ if (val->type == 'N')
+ port_wire->upto = val->data_number != 0;
+ }
+
+ if (port_node->data_dict.count("offset") != 0) {
+ JsonNode *val = port_node->data_dict.at("offset");
+ if (val->type == 'N')
+ port_wire->start_offset = val->data_number;
+ }
+
if (port_direction_node->data_string == "input") {
port_wire->port_input = true;
} else
@@ -372,6 +384,18 @@ void json_import(Design *design, string &modname, JsonNode *node)
if (wire == nullptr)
wire = module->addWire(net_name, GetSize(bits_node->data_array));
+ if (net_node->data_dict.count("upto") != 0) {
+ JsonNode *val = net_node->data_dict.at("upto");
+ if (val->type == 'N')
+ wire->upto = val->data_number != 0;
+ }
+
+ if (net_node->data_dict.count("offset") != 0) {
+ JsonNode *val = net_node->data_dict.at("offset");
+ if (val->type == 'N')
+ wire->start_offset = val->data_number;
+ }
+
for (int i = 0; i < GetSize(bits_node->data_array); i++)
{
JsonNode *bitval_node = bits_node->data_array.at(i);
diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc
index e90c87a2..6e3cffac 100644
--- a/frontends/liberty/liberty.cc
+++ b/frontends/liberty/liberty.cc
@@ -36,7 +36,8 @@ static RTLIL::SigSpec parse_func_identifier(RTLIL::Module *module, const char *&
int id_len = 0;
while (('a' <= expr[id_len] && expr[id_len] <= 'z') || ('A' <= expr[id_len] && expr[id_len] <= 'Z') ||
- ('0' <= expr[id_len] && expr[id_len] <= '9') || expr[id_len] == '.' || expr[id_len] == '_') id_len++;
+ ('0' <= expr[id_len] && expr[id_len] <= '9') || expr[id_len] == '.' ||
+ expr[id_len] == '_' || expr[id_len] == '[' || expr[id_len] == ']') id_len++;
if (id_len == 0)
log_error("Expected identifier at `%s'.\n", expr);
@@ -634,9 +635,12 @@ struct LibertyFrontend : public Frontend {
}
}
- for (auto node : cell->children)
+ if (!flag_lib)
{
- if (!flag_lib) {
+ // some liberty files do not put ff/latch at the beginning of a cell
+ // try to find "ff" or "latch" and create FF/latch _before_ processing all other nodes
+ for (auto node : cell->children)
+ {
if (node->id == "ff" && node->args.size() == 2)
create_ff(module, node);
if (node->id == "latch" && node->args.size() == 2)
@@ -645,7 +649,10 @@ struct LibertyFrontend : public Frontend {
goto skip_cell;
}
}
+ }
+ for (auto node : cell->children)
+ {
if (node->id == "pin" && node->args.size() == 1)
{
LibertyAst *dir = node->find("direction");
diff --git a/frontends/verific/README b/frontends/verific/README
index b4c436a3..89584f2e 100644
--- a/frontends/verific/README
+++ b/frontends/verific/README
@@ -4,35 +4,6 @@ This directory contains Verific bindings for Yosys.
See http://www.verific.com/ for details.
-Building Yosys with the 32 bit Verific eval library on amd64:
-=============================================================
-
-1.) Use a Makefile.conf like the following one:
-
---snip--
-CONFIG := gcc
-ENABLE_TCL := 0
-ENABLE_PLUGINS := 0
-ENABLE_VERIFIC := 1
-CXXFLAGS += -m32
-LDFLAGS += -m32
-VERIFIC_DIR = /usr/local/src/verific_lib_eval
---snap--
-
-
-2.) Install the necessary multilib packages
-
-Hint: On debian/ubuntu the multilib packages have names such as
-libreadline-dev:i386 or lib32readline6-dev, depending on the
-exact version of debian/ubuntu you are working with.
-
-
-3.) Build and test
-
-make -j8
-./yosys -p 'verific -sv frontends/verific/example.sv; verific -import top'
-
-
Verific Features that should be enabled in your Verific library
===============================================================
@@ -50,7 +21,7 @@ Then run in the following command in this directory:
sby -f example.sby
-This will generate approximately one page of text outpout. The last lines
+This will generate approximately one page of text output. The last lines
should be something like this:
SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0)
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index c5fa5831..2bf99e58 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -46,7 +46,15 @@ USING_YOSYS_NAMESPACE
#include "VeriModule.h"
#include "VeriWrite.h"
#include "VhdlUnits.h"
-#include "Message.h"
+#include "VeriLibrary.h"
+
+#ifndef SYMBIOTIC_VERIFIC_API_VERSION
+# error "Only Symbiotic EDA flavored Verific is supported. Please contact office@symbioticeda.com for commercial support for Yosys+Verific."
+#endif
+
+#if SYMBIOTIC_VERIFIC_API_VERSION < 1
+# error "Please update your version of Symbiotic EDA flavored Verific."
+#endif
#ifdef __clang__
#pragma clang diagnostic pop
@@ -118,6 +126,27 @@ RTLIL::SigBit VerificImporter::net_map_at(Net *net)
return net_map.at(net);
}
+bool is_blackbox(Netlist *nl)
+{
+ if (nl->IsBlackBox())
+ return true;
+
+ const char *attr = nl->GetAttValue("blackbox");
+ if (attr != nullptr && strcmp(attr, "0"))
+ return true;
+
+ return false;
+}
+
+RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj)
+{
+ std::string s = stringf("$verific$%s", obj->Name());
+ if (obj->Linefile())
+ s += stringf("$%s:%d", Verific::LineFile::GetFileName(obj->Linefile()), Verific::LineFile::GetLineNo(obj->Linefile()));
+ s += stringf("$%d", autoidx++);
+ return s;
+}
+
void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj)
{
MapIter mi;
@@ -203,7 +232,7 @@ RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool<Net*,
dummy_wire = NULL;
} else {
if (dummy_wire == NULL)
- dummy_wire = module->addWire(NEW_ID);
+ dummy_wire = module->addWire(new_verific_id(inst));
else
dummy_wire->width++;
sig.append(RTLIL::SigSpec(dummy_wire, dummy_wire->width - 1));
@@ -219,8 +248,8 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr
}
if (inst->Type() == PRIM_NAND) {
- RTLIL::SigSpec tmp = module->addWire(NEW_ID);
- module->addAndGate(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
+ RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst));
+ module->addAndGate(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
module->addNotGate(inst_name, tmp, net_map_at(inst->GetOutput()));
return true;
}
@@ -231,8 +260,8 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr
}
if (inst->Type() == PRIM_NOR) {
- RTLIL::SigSpec tmp = module->addWire(NEW_ID);
- module->addOrGate(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
+ RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst));
+ module->addOrGate(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
module->addNotGate(inst_name, tmp, net_map_at(inst->GetOutput()));
return true;
}
@@ -272,16 +301,16 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr
if (inst->Type() == PRIM_FADD)
{
RTLIL::SigSpec a = net_map_at(inst->GetInput1()), b = net_map_at(inst->GetInput2()), c = net_map_at(inst->GetCin());
- RTLIL::SigSpec x = inst->GetCout() ? net_map_at(inst->GetCout()) : module->addWire(NEW_ID);
- RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(NEW_ID);
- RTLIL::SigSpec tmp1 = module->addWire(NEW_ID);
- RTLIL::SigSpec tmp2 = module->addWire(NEW_ID);
- RTLIL::SigSpec tmp3 = module->addWire(NEW_ID);
- module->addXorGate(NEW_ID, a, b, tmp1);
+ RTLIL::SigSpec x = inst->GetCout() ? net_map_at(inst->GetCout()) : module->addWire(new_verific_id(inst));
+ RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(new_verific_id(inst));
+ RTLIL::SigSpec tmp1 = module->addWire(new_verific_id(inst));
+ RTLIL::SigSpec tmp2 = module->addWire(new_verific_id(inst));
+ RTLIL::SigSpec tmp3 = module->addWire(new_verific_id(inst));
+ module->addXorGate(new_verific_id(inst), a, b, tmp1);
module->addXorGate(inst_name, tmp1, c, y);
- module->addAndGate(NEW_ID, tmp1, c, tmp2);
- module->addAndGate(NEW_ID, a, b, tmp3);
- module->addOrGate(NEW_ID, tmp2, tmp3, x);
+ module->addAndGate(new_verific_id(inst), tmp1, c, tmp2);
+ module->addAndGate(new_verific_id(inst), a, b, tmp3);
+ module->addOrGate(new_verific_id(inst), tmp2, tmp3, x);
return true;
}
@@ -308,63 +337,78 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr
bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdString inst_name)
{
+ RTLIL::Cell *cell = nullptr;
+
if (inst->Type() == PRIM_AND) {
- module->addAnd(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ cell = module->addAnd(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_NAND) {
- RTLIL::SigSpec tmp = module->addWire(NEW_ID);
- module->addAnd(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
- module->addNot(inst_name, tmp, net_map_at(inst->GetOutput()));
+ RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst));
+ cell = module->addAnd(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
+ import_attributes(cell->attributes, inst);
+ cell = module->addNot(inst_name, tmp, net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_OR) {
- module->addOr(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ cell = module->addOr(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_NOR) {
- RTLIL::SigSpec tmp = module->addWire(NEW_ID);
- module->addOr(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
- module->addNot(inst_name, tmp, net_map_at(inst->GetOutput()));
+ RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst));
+ cell = module->addOr(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
+ import_attributes(cell->attributes, inst);
+ cell = module->addNot(inst_name, tmp, net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_XOR) {
- module->addXor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ cell = module->addXor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_XNOR) {
- module->addXnor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ cell = module->addXnor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_INV) {
- module->addNot(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ cell = module->addNot(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_MUX) {
- module->addMux(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput()));
+ cell = module->addMux(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_TRI) {
- module->addMux(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput()));
+ cell = module->addMux(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_FADD)
{
- RTLIL::SigSpec a_plus_b = module->addWire(NEW_ID, 2);
- RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(NEW_ID);
+ RTLIL::SigSpec a_plus_b = module->addWire(new_verific_id(inst), 2);
+ RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(new_verific_id(inst));
if (inst->GetCout())
y.append(net_map_at(inst->GetCout()));
- module->addAdd(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), a_plus_b);
- module->addAdd(inst_name, a_plus_b, net_map_at(inst->GetCin()), y);
+ cell = module->addAdd(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), a_plus_b);
+ import_attributes(cell->attributes, inst);
+ cell = module->addAdd(inst_name, a_plus_b, net_map_at(inst->GetCin()), y);
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -375,24 +419,26 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
log_assert(clocking.body_net == nullptr);
if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd())
- clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ cell = clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
else if (inst->GetSet()->IsGnd())
- clocking.addAdff(inst_name, net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S0);
+ cell = clocking.addAdff(inst_name, net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S0);
else if (inst->GetReset()->IsGnd())
- clocking.addAdff(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S1);
+ cell = clocking.addAdff(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S1);
else
- clocking.addDffsr(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetReset()),
+ cell = clocking.addDffsr(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetReset()),
net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_DLATCHRS)
{
if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd())
- module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ cell = module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
else
- module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetSet()), net_map_at(inst->GetReset()),
+ cell = module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetSet()), net_map_at(inst->GetReset()),
net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -408,37 +454,45 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
if (inst->GetCout() != NULL)
out.append(net_map_at(inst->GetCout()));
if (inst->GetCin()->IsGnd()) {
- module->addAdd(inst_name, IN1, IN2, out, SIGNED);
+ cell = module->addAdd(inst_name, IN1, IN2, out, SIGNED);
+ import_attributes(cell->attributes, inst);
} else {
- RTLIL::SigSpec tmp = module->addWire(NEW_ID, GetSize(out));
- module->addAdd(NEW_ID, IN1, IN2, tmp, SIGNED);
- module->addAdd(inst_name, tmp, net_map_at(inst->GetCin()), out, false);
+ RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst), GetSize(out));
+ cell = module->addAdd(new_verific_id(inst), IN1, IN2, tmp, SIGNED);
+ import_attributes(cell->attributes, inst);
+ cell = module->addAdd(inst_name, tmp, net_map_at(inst->GetCin()), out, false);
+ import_attributes(cell->attributes, inst);
}
return true;
}
if (inst->Type() == OPER_MULTIPLIER) {
- module->addMul(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addMul(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_DIVIDER) {
- module->addDiv(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addDiv(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_MODULO) {
- module->addMod(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addMod(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_REMAINDER) {
- module->addMod(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addMod(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_SHIFT_LEFT) {
- module->addShl(inst_name, IN1, IN2, OUT, false);
+ cell = module->addShl(inst_name, IN1, IN2, OUT, false);
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -448,7 +502,8 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
for (unsigned i = 1; i < inst->OutputSize(); i++) {
vec.append(RTLIL::State::S0);
}
- module->addShl(inst_name, vec, IN, OUT, false);
+ cell = module->addShl(inst_name, vec, IN, OUT, false);
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -458,7 +513,8 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
for (unsigned i = 1; i < inst->OutputSize(); i++) {
vec.append(RTLIL::State::S0);
}
- module->addShl(inst_name, vec, IN, OUT, false);
+ cell = module->addShl(inst_name, vec, IN, OUT, false);
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -466,108 +522,127 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
Net *net_cin = inst->GetCin();
Net *net_a_msb = inst->GetInput1Bit(0);
if (net_cin->IsGnd())
- module->addShr(inst_name, IN1, IN2, OUT, false);
+ cell = module->addShr(inst_name, IN1, IN2, OUT, false);
else if (net_cin == net_a_msb)
- module->addSshr(inst_name, IN1, IN2, OUT, true);
+ cell = module->addSshr(inst_name, IN1, IN2, OUT, true);
else
log_error("Can't import Verific OPER_SHIFT_RIGHT instance %s: carry_in is neither 0 nor msb of left input\n", inst->Name());
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_REDUCE_AND) {
- module->addReduceAnd(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addReduceAnd(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_REDUCE_OR) {
- module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_REDUCE_XOR) {
- module->addReduceXor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addReduceXor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_REDUCE_XNOR) {
- module->addReduceXnor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addReduceXnor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_REDUCE_NOR) {
- SigSpec t = module->ReduceOr(NEW_ID, IN, SIGNED);
- module->addNot(inst_name, t, net_map_at(inst->GetOutput()));
+ SigSpec t = module->ReduceOr(new_verific_id(inst), IN, SIGNED);
+ cell = module->addNot(inst_name, t, net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_LESSTHAN) {
Net *net_cin = inst->GetCin();
if (net_cin->IsGnd())
- module->addLt(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addLt(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
else if (net_cin->IsPwr())
- module->addLe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addLe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
else
log_error("Can't import Verific OPER_LESSTHAN instance %s: carry_in is neither 0 nor 1\n", inst->Name());
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_AND) {
- module->addAnd(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addAnd(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_OR) {
- module->addOr(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addOr(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_XOR) {
- module->addXor(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addXor(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_XNOR) {
- module->addXnor(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addXnor(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_BUF) {
- module->addPos(inst_name, IN, FILTERED_OUT, SIGNED);
+ cell = module->addPos(inst_name, IN, FILTERED_OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_INV) {
- module->addNot(inst_name, IN, OUT, SIGNED);
+ cell = module->addNot(inst_name, IN, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_MINUS) {
- module->addSub(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addSub(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_UMINUS) {
- module->addNeg(inst_name, IN, OUT, SIGNED);
+ cell = module->addNeg(inst_name, IN, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_EQUAL) {
- module->addEq(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addEq(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_NEQUAL) {
- module->addNe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addNe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_MUX) {
- module->addMux(inst_name, IN1, IN2, net_map_at(inst->GetControl()), OUT);
+ cell = module->addMux(inst_name, IN1, IN2, net_map_at(inst->GetControl()), OUT);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_NTO1MUX) {
- module->addShr(inst_name, IN2, IN1, net_map_at(inst->GetOutput()));
+ cell = module->addShr(inst_name, IN2, IN1, net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -587,25 +662,29 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
padded_data.append(d);
}
- module->addShr(inst_name, padded_data, sel, out);
+ cell = module->addShr(inst_name, padded_data, sel, out);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_SELECTOR)
{
- module->addPmux(inst_name, State::S0, IN2, IN1, net_map_at(inst->GetOutput()));
+ cell = module->addPmux(inst_name, State::S0, IN2, IN1, net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_SELECTOR)
{
SigSpec out = OUT;
- module->addPmux(inst_name, SigSpec(State::S0, GetSize(out)), IN2, IN1, out);
+ cell = module->addPmux(inst_name, SigSpec(State::S0, GetSize(out)), IN2, IN1, out);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_TRI) {
- module->addMux(inst_name, RTLIL::SigSpec(RTLIL::State::Sz, inst->OutputSize()), IN, net_map_at(inst->GetControl()), OUT);
+ cell = module->addMux(inst_name, RTLIL::SigSpec(RTLIL::State::Sz, inst->OutputSize()), IN, net_map_at(inst->GetControl()), OUT);
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -619,9 +698,10 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
RTLIL::SigSpec sig_reset = operatorInport(inst, "reset");
if (sig_set.is_fully_const() && !sig_set.as_bool() && sig_reset.is_fully_const() && !sig_reset.as_bool())
- clocking.addDff(inst_name, IN, OUT);
+ cell = clocking.addDff(inst_name, IN, OUT);
else
- clocking.addDffsr(inst_name, sig_set, sig_reset, IN, OUT);
+ cell = clocking.addDffsr(inst_name, sig_set, sig_reset, IN, OUT);
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -704,13 +784,14 @@ void VerificImporter::merge_past_ffs(pool<RTLIL::Cell*> &candidates)
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());
+ std::string netlist_name = nl->GetAtt(" \\top") ? nl->CellBaseName() : nl->Owner()->Name();
+ std::string module_name = nl->IsOperator() ? "$verific$" + netlist_name : RTLIL::escape_id(netlist_name);
netlist = nl;
if (design->has(module_name)) {
- if (!nl->IsOperator())
- log_cmd_error("Re-definition of module `%s'.\n", nl->Owner()->Name());
+ if (!nl->IsOperator() && !is_blackbox(nl))
+ log_cmd_error("Re-definition of module `%s'.\n", netlist_name.c_str());
return;
}
@@ -718,7 +799,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
module->name = module_name;
design->add(module);
- if (nl->IsBlackBox()) {
+ if (is_blackbox(nl)) {
log("Importing blackbox module %s.\n", RTLIL::id2cstr(module->name));
module->set_bool_attribute("\\blackbox");
} else {
@@ -850,7 +931,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
ascii_initdata++;
}
if (initval_valid) {
- RTLIL::Cell *cell = module->addCell(NEW_ID, "$meminit");
+ RTLIL::Cell *cell = module->addCell(new_verific_id(net), "$meminit");
cell->parameters["\\WORDS"] = 1;
if (net->GetOrigTypeRange()->LeftRangeBound() < net->GetOrigTypeRange()->RightRangeBound())
cell->setPort("\\ADDR", word_idx);
@@ -913,7 +994,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
if (net->Bus())
continue;
- RTLIL::IdString wire_name = module->uniquify(mode_names || net->IsUserDeclared() ? RTLIL::escape_id(net->Name()) : NEW_ID);
+ RTLIL::IdString wire_name = module->uniquify(mode_names || net->IsUserDeclared() ? RTLIL::escape_id(net->Name()) : new_verific_id(net));
if (verific_verbose)
log(" importing net %s as %s.\n", net->Name(), log_id(wire_name));
@@ -937,7 +1018,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
if (found_new_net)
{
- RTLIL::IdString wire_name = module->uniquify(mode_names || netbus->IsUserDeclared() ? RTLIL::escape_id(netbus->Name()) : NEW_ID);
+ RTLIL::IdString wire_name = module->uniquify(mode_names || netbus->IsUserDeclared() ? RTLIL::escape_id(netbus->Name()) : new_verific_id(netbus));
if (verific_verbose)
log(" importing netbus %s as %s.\n", netbus->Name(), log_id(wire_name));
@@ -1013,16 +1094,16 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
}
if (GetSize(anyconst_sig))
- module->connect(anyconst_sig, module->Anyconst(NEW_ID, GetSize(anyconst_sig)));
+ module->connect(anyconst_sig, module->Anyconst(new_verific_id(netbus), GetSize(anyconst_sig)));
if (GetSize(anyseq_sig))
- module->connect(anyseq_sig, module->Anyseq(NEW_ID, GetSize(anyseq_sig)));
+ module->connect(anyseq_sig, module->Anyseq(new_verific_id(netbus), GetSize(anyseq_sig)));
if (GetSize(allconst_sig))
- module->connect(allconst_sig, module->Allconst(NEW_ID, GetSize(allconst_sig)));
+ module->connect(allconst_sig, module->Allconst(new_verific_id(netbus), GetSize(allconst_sig)));
if (GetSize(allseq_sig))
- module->connect(allseq_sig, module->Allseq(NEW_ID, GetSize(allseq_sig)));
+ module->connect(allseq_sig, module->Allseq(new_verific_id(netbus), GetSize(allseq_sig)));
}
for (auto it : init_nets)
@@ -1046,10 +1127,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
}
for (auto net : anyconst_nets)
- module->connect(net_map_at(net), module->Anyconst(NEW_ID));
+ module->connect(net_map_at(net), module->Anyconst(new_verific_id(net)));
for (auto net : anyseq_nets)
- module->connect(net_map_at(net), module->Anyseq(NEW_ID));
+ module->connect(net_map_at(net), module->Anyseq(new_verific_id(net)));
pool<Instance*, hash_ptr_ops> sva_asserts;
pool<Instance*, hash_ptr_ops> sva_assumes;
@@ -1060,7 +1141,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst)
{
- RTLIL::IdString inst_name = module->uniquify(mode_names || inst->IsUserDeclared() ? RTLIL::escape_id(inst->Name()) : NEW_ID);
+ RTLIL::IdString inst_name = module->uniquify(mode_names || inst->IsUserDeclared() ? RTLIL::escape_id(inst->Name()) : new_verific_id(inst));
if (verific_verbose)
log(" importing cell %s (%s) as %s.\n", inst->Name(), inst->View()->Owner()->Name(), log_id(inst_name));
@@ -1128,27 +1209,34 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
if (inst->Type() == OPER_WRITE_PORT || inst->Type() == OPER_CLOCKED_WRITE_PORT)
{
RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetOutput()->Name()));
- if (memory->width != int(inst->Input2Size()))
- log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
+ int numchunks = int(inst->Input2Size()) / memory->width;
+ int chunksbits = ceil_log2(numchunks);
- RTLIL::SigSpec addr = operatorInput1(inst);
- RTLIL::SigSpec data = operatorInput2(inst);
-
- RTLIL::Cell *cell = module->addCell(inst_name, "$memwr");
- cell->parameters["\\MEMID"] = memory->name.str();
- cell->parameters["\\CLK_ENABLE"] = false;
- cell->parameters["\\CLK_POLARITY"] = true;
- cell->parameters["\\PRIORITY"] = 0;
- cell->parameters["\\ABITS"] = GetSize(addr);
- cell->parameters["\\WIDTH"] = GetSize(data);
- cell->setPort("\\EN", RTLIL::SigSpec(net_map_at(inst->GetControl())).repeat(GetSize(data)));
- cell->setPort("\\CLK", RTLIL::State::S0);
- cell->setPort("\\ADDR", addr);
- cell->setPort("\\DATA", data);
-
- if (inst->Type() == OPER_CLOCKED_WRITE_PORT) {
- cell->parameters["\\CLK_ENABLE"] = true;
- cell->setPort("\\CLK", net_map_at(inst->GetClock()));
+ if ((numchunks * memory->width) != int(inst->Input2Size()) || (numchunks & (numchunks - 1)) != 0)
+ log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetOutput()->Name());
+
+ for (int i = 0; i < numchunks; i++)
+ {
+ RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)};
+ RTLIL::SigSpec data = operatorInput2(inst).extract(i * memory->width, memory->width);
+
+ RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name :
+ RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), "$memwr");
+ cell->parameters["\\MEMID"] = memory->name.str();
+ cell->parameters["\\CLK_ENABLE"] = false;
+ cell->parameters["\\CLK_POLARITY"] = true;
+ cell->parameters["\\PRIORITY"] = 0;
+ cell->parameters["\\ABITS"] = GetSize(addr);
+ cell->parameters["\\WIDTH"] = GetSize(data);
+ cell->setPort("\\EN", RTLIL::SigSpec(net_map_at(inst->GetControl())).repeat(GetSize(data)));
+ cell->setPort("\\CLK", RTLIL::State::S0);
+ cell->setPort("\\ADDR", addr);
+ cell->setPort("\\DATA", data);
+
+ if (inst->Type() == OPER_CLOCKED_WRITE_PORT) {
+ cell->parameters["\\CLK_ENABLE"] = true;
+ cell->setPort("\\CLK", net_map_at(inst->GetClock()));
+ }
}
continue;
}
@@ -1184,7 +1272,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
log_assert(inst->Input1Size() == inst->OutputSize());
SigSpec sig_d, sig_q, sig_o;
- sig_q = module->addWire(NEW_ID, inst->Input1Size());
+ sig_q = module->addWire(new_verific_id(inst), inst->Input1Size());
for (int i = int(inst->Input1Size())-1; i >= 0; i--){
sig_d.append(net_map_at(inst->GetInput1Bit(i)));
@@ -1198,8 +1286,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
log_signal(sig_d), log_signal(sig_q), log_signal(sig_o));
}
- clocking.addDff(NEW_ID, sig_d, sig_q);
- module->addXnor(NEW_ID, sig_d, sig_q, sig_o);
+ clocking.addDff(new_verific_id(inst), sig_d, sig_q);
+ module->addXnor(new_verific_id(inst), sig_d, sig_q, sig_o);
if (!mode_keep)
continue;
@@ -1213,7 +1301,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
SigSpec sig_d = net_map_at(inst->GetInput1());
SigSpec sig_o = net_map_at(inst->GetOutput());
- SigSpec sig_q = module->addWire(NEW_ID);
+ SigSpec sig_q = module->addWire(new_verific_id(inst));
if (verific_verbose) {
log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
@@ -1222,8 +1310,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
log_signal(sig_d), log_signal(sig_q), log_signal(sig_o));
}
- clocking.addDff(NEW_ID, sig_d, sig_q);
- module->addXnor(NEW_ID, sig_d, sig_q, sig_o);
+ clocking.addDff(new_verific_id(inst), sig_d, sig_q);
+ module->addXnor(new_verific_id(inst), sig_d, sig_q, sig_o);
if (!mode_keep)
continue;
@@ -1242,7 +1330,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig));
- past_ffs.insert(clocking.addDff(NEW_ID, sig_d, sig_q));
+ past_ffs.insert(clocking.addDff(new_verific_id(inst), sig_d, sig_q));
if (!mode_keep)
continue;
@@ -1256,14 +1344,14 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
SigBit sig_d = net_map_at(inst->GetInput1());
SigBit sig_o = net_map_at(inst->GetOutput());
- SigBit sig_q = module->addWire(NEW_ID);
+ SigBit sig_q = module->addWire(new_verific_id(inst));
if (verific_verbose)
log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig));
- clocking.addDff(NEW_ID, sig_d, sig_q);
- module->addEq(NEW_ID, {sig_q, sig_d}, Const(inst->Type() == PRIM_SVA_ROSE ? 1 : 2, 2), sig_o);
+ clocking.addDff(new_verific_id(inst), sig_d, sig_q);
+ module->addEq(new_verific_id(inst), {sig_q, sig_d}, Const(inst->Type() == PRIM_SVA_ROSE ? 1 : 2, 2), sig_o);
if (!mode_keep)
continue;
@@ -1286,9 +1374,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
Cell *cell = nullptr;
if (assume_attr != nullptr && !strcmp(assume_attr, "1"))
- cell = module->addAssume(NEW_ID, cond, State::S1);
+ cell = module->addAssume(new_verific_id(inst), cond, State::S1);
else
- cell = module->addAssert(NEW_ID, cond, State::S1);
+ cell = module->addAssert(new_verific_id(inst), cond, State::S1);
import_attributes(cell->attributes, inst);
continue;
@@ -1330,7 +1418,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
IdString port_name_id = RTLIL::escape_id(port_name);
auto &sigvec = cell_port_conns[port_name_id];
if (GetSize(sigvec) <= port_offset) {
- SigSpec zwires = module->addWire(NEW_ID, port_offset+1-GetSize(sigvec));
+ SigSpec zwires = module->addWire(new_verific_id(inst), port_offset+1-GetSize(sigvec));
for (auto bit : zwires)
sigvec.push_back(bit);
}
@@ -1540,30 +1628,35 @@ struct VerificExtNets
int portname_cnt = 0;
// a map from Net to the same Net one level up in the design hierarchy
- std::map<Net*, Net*> net_level_up;
+ std::map<Net*, Net*> net_level_up_drive_up;
+ std::map<Net*, Net*> net_level_up_drive_down;
- Net *get_net_level_up(Net *net)
+ Net *route_up(Net *net, bool drive_up, Net *final_net = nullptr)
{
+ auto &net_level_up = drive_up ? net_level_up_drive_up : net_level_up_drive_down;
+
if (net_level_up.count(net) == 0)
{
Netlist *nl = net->Owner();
// Simply return if Netlist is not unique
- if (nl->NumOfRefs() != 1)
- return net;
+ log_assert(nl->NumOfRefs() == 1);
Instance *up_inst = (Instance*)nl->GetReferences()->GetLast();
Netlist *up_nl = up_inst->Owner();
// create new Port
string name = stringf("___extnets_%d", portname_cnt++);
- Port *new_port = new Port(name.c_str(), DIR_OUT);
+ Port *new_port = new Port(name.c_str(), drive_up ? DIR_OUT : DIR_IN);
nl->Add(new_port);
net->Connect(new_port);
// create new Net in up Netlist
- Net *new_net = new Net(name.c_str());
- up_nl->Add(new_net);
+ Net *new_net = final_net;
+ if (new_net == nullptr || new_net->Owner() != up_nl) {
+ new_net = new Net(name.c_str());
+ up_nl->Add(new_net);
+ }
up_inst->Connect(new_port, new_net);
net_level_up[net] = new_net;
@@ -1572,6 +1665,39 @@ struct VerificExtNets
return net_level_up.at(net);
}
+ Net *route_up(Net *net, bool drive_up, Netlist *dest, Net *final_net = nullptr)
+ {
+ while (net->Owner() != dest)
+ net = route_up(net, drive_up, final_net);
+ if (final_net != nullptr)
+ log_assert(net == final_net);
+ return net;
+ }
+
+ Netlist *find_common_ancestor(Netlist *A, Netlist *B)
+ {
+ std::set<Netlist*> ancestors_of_A;
+
+ Netlist *cursor = A;
+ while (1) {
+ ancestors_of_A.insert(cursor);
+ if (cursor->NumOfRefs() != 1)
+ break;
+ cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
+ }
+
+ cursor = B;
+ while (1) {
+ if (ancestors_of_A.count(cursor))
+ return cursor;
+ if (cursor->NumOfRefs() != 1)
+ break;
+ cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
+ }
+
+ log_error("No common ancestor found between %s and %s.\n", get_full_netlist_name(A).c_str(), get_full_netlist_name(B).c_str());
+ }
+
void run(Netlist *nl)
{
MapIter mi, mi2;
@@ -1595,19 +1721,37 @@ struct VerificExtNets
if (verific_verbose)
log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name());
- while (net->IsExternalTo(nl))
- {
- Net *newnet = get_net_level_up(net);
- if (newnet == net) break;
+ Netlist *ext_nl = net->Owner();
+
+ if (verific_verbose)
+ log(" external net owner: %s\n", get_full_netlist_name(ext_nl).c_str());
+
+ Netlist *ca_nl = find_common_ancestor(nl, ext_nl);
+
+ if (verific_verbose)
+ log(" common ancestor: %s\n", get_full_netlist_name(ca_nl).c_str());
+
+ Net *ca_net = route_up(net, !port->IsOutput(), ca_nl);
+ Net *new_net = ca_net;
+ if (ca_nl != nl)
+ {
if (verific_verbose)
- log(" external net: %s.%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name());
- net = newnet;
+ log(" net in common ancestor: %s\n", ca_net->Name());
+
+ string name = stringf("___extnets_%d", portname_cnt++);
+ new_net = new Net(name.c_str());
+ nl->Add(new_net);
+
+ Net *n = route_up(new_net, port->IsOutput(), ca_nl, ca_net);
+ log_assert(n == ca_net);
}
if (verific_verbose)
- log(" final net: %s.%s%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name(), net->IsExternalTo(nl) ? " (external)" : "");
- todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, net));
+ log(" new local net: %s\n", new_net->Name());
+
+ log_assert(!new_net->IsExternalTo(nl));
+ todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, new_net));
}
for (auto it : todo_connect) {
@@ -1617,32 +1761,64 @@ struct VerificExtNets
}
};
-void verific_import(Design *design, std::string top)
+void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top)
{
verific_sva_fsm_limit = 16;
std::set<Netlist*> nl_todo, nl_done;
- {
- VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
- VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
+ VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
+ VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
+ Array *netlists = NULL;
+ Array veri_libs, vhdl_libs;
+ if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
+ if (veri_lib) veri_libs.InsertLast(veri_lib);
+
+ Map verific_params(STRING_HASH);
+ for (const auto &i : parameters)
+ verific_params.Insert(i.first.c_str(), i.second.c_str());
- Array veri_libs, vhdl_libs;
- if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
- if (veri_lib) veri_libs.InsertLast(veri_lib);
+ if (top.empty()) {
+ netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params);
+ }
+ else {
+ Array veri_modules, vhdl_units;
+
+ if (veri_lib) {
+ VeriModule *veri_module = veri_lib->GetModule(top.c_str(), 1);
+ if (veri_module) {
+ veri_modules.InsertLast(veri_module);
+ }
- Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
- Netlist *nl;
- int i;
+ // Also elaborate all root modules since they may contain bind statements
+ MapIter mi;
+ FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
+ if (!veri_module->IsRootModule()) continue;
+ veri_modules.InsertLast(veri_module);
+ }
+ }
- FOREACH_ARRAY_ITEM(netlists, i, nl) {
- if (top.empty() || nl->Owner()->Name() == top)
- nl_todo.insert(nl);
+ if (vhdl_lib) {
+ VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str());
+ if (vhdl_unit)
+ vhdl_units.InsertLast(vhdl_unit);
}
- delete netlists;
+ netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params);
+ }
+
+ Netlist *nl;
+ int i;
+
+ FOREACH_ARRAY_ITEM(netlists, i, nl) {
+ if (top.empty() && nl->CellBaseName() != top)
+ continue;
+ nl->AddAtt(new Att(" \\top", NULL));
+ nl_todo.insert(nl);
}
+ delete netlists;
+
if (!verific_error_msg.empty())
log_error("%s\n", verific_error_msg.c_str());
@@ -1676,6 +1852,7 @@ YOSYS_NAMESPACE_END
PRIVATE_NAMESPACE_BEGIN
+#ifdef YOSYS_ENABLE_VERIFIC
bool check_noverific_env()
{
const char *e = getenv("YOSYS_NOVERIFIC");
@@ -1685,6 +1862,7 @@ bool check_noverific_env()
return false;
return true;
}
+#endif
struct VerificPass : public Pass {
VerificPass() : Pass("verific", "load Verilog and VHDL designs using Verific") { }
@@ -1774,6 +1952,13 @@ struct VerificPass : public Pass {
log(" -autocover\n");
log(" Generate automatic cover statements for all asserts\n");
log("\n");
+ log(" -chparam name value \n");
+ log(" Elaborate the specified top modules (all modules when -all given) using\n");
+ log(" this parameter value. Modules on which this parameter does not exist will\n");
+ log(" cause Verific to produce a VERI-1928 or VHDL-1676 message. This option\n");
+ log(" can be specified multiple times to override multiple parameters.\n");
+ log(" String values must be passed in double quotes (\").\n");
+ log("\n");
log(" -v, -vv\n");
log(" Verbose log messages. (-vv is even more verbose than -v.)\n");
log("\n");
@@ -1819,12 +2004,19 @@ struct VerificPass : public Pass {
{
Message::SetConsoleOutput(0);
Message::RegisterCallBackMsg(msg_func);
+
RuntimeFlags::SetVar("db_preserve_user_nets", 1);
RuntimeFlags::SetVar("db_allow_external_nets", 1);
- RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0);
+ RuntimeFlags::SetVar("db_infer_wide_operators", 1);
+
RuntimeFlags::SetVar("veri_extract_dualport_rams", 0);
RuntimeFlags::SetVar("veri_extract_multiport_rams", 1);
- RuntimeFlags::SetVar("db_infer_wide_operators", 1);
+
+ RuntimeFlags::SetVar("vhdl_extract_dualport_rams", 0);
+ RuntimeFlags::SetVar("vhdl_extract_multiport_rams", 1);
+
+ RuntimeFlags::SetVar("vhdl_support_variable_slice", 1);
+ RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0);
// Workaround for VIPER #13851
RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1);
@@ -1832,6 +2024,13 @@ struct VerificPass : public Pass {
// WARNING: instantiating unknown module 'XYZ' (VERI-1063)
Message::SetMessageType("VERI-1063", VERIFIC_ERROR);
+ // https://github.com/YosysHQ/yosys/issues/1055
+ RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ;
+
+#ifndef DB_PRESERVE_INITIAL_VALUE
+# warning Verific was built without DB_PRESERVE_INITIAL_VALUE.
+#endif
+
set_verific_global_flags = false;
}
@@ -2017,6 +2216,7 @@ struct VerificPass : public Pass {
bool mode_autocover = false;
bool flatten = false, extnets = false;
string dumpfile;
+ Map parameters(STRING_HASH);
for (argidx++; argidx < GetSize(args); argidx++) {
if (args[argidx] == "-all") {
@@ -2055,6 +2255,15 @@ struct VerificPass : public Pass {
mode_autocover = true;
continue;
}
+ if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) {
+ const std::string &key = args[++argidx];
+ const std::string &value = args[++argidx];
+ unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(),
+ 1 /* force_overwrite */);
+ if (!new_insertion)
+ log_warning_noprefix("-chparam %s already specified: overwriting.\n", key.c_str());
+ continue;
+ }
if (args[argidx] == "-V") {
mode_verific = true;
continue;
@@ -2079,42 +2288,6 @@ struct VerificPass : public Pass {
if (mode_all)
{
-#if 0
- log("Running veri_file::ElaborateAll().\n");
- if (!veri_file::ElaborateAll())
- log_cmd_error("Elaboration of Verilog modules failed.\n");
-
- log("Running vhdl_file::ElaborateAll().\n");
- if (!vhdl_file::ElaborateAll())
- log_cmd_error("Elaboration of VHDL modules failed.\n");
-
- Library *lib = Netlist::PresentDesign()->Owner()->Owner();
-
- if (argidx == GetSize(args))
- {
- MapIter iter;
- char *iter_name;
- Verific::Cell *iter_cell;
-
- FOREACH_MAP_ITEM(lib->GetCells(), iter, &iter_name, &iter_cell) {
- if (*iter_name != '$')
- nl_todo.insert(iter_cell->GetFirstNetlist());
- }
- }
- else
- {
- for (; argidx < GetSize(args); argidx++)
- {
- Verific::Cell *cell = lib->GetCell(args[argidx].c_str());
-
- if (cell == nullptr)
- log_cmd_error("Module not found: %s\n", args[argidx].c_str());
-
- nl_todo.insert(cell->GetFirstNetlist());
- cell->GetFirstNetlist()->SetPresentDesign();
- }
- }
-#else
log("Running hier_tree::ElaborateAll().\n");
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1);
@@ -2124,45 +2297,39 @@ struct VerificPass : public Pass {
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
if (veri_lib) veri_libs.InsertLast(veri_lib);
- Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
+ Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &parameters);
Netlist *nl;
int i;
FOREACH_ARRAY_ITEM(netlists, i, nl)
nl_todo.insert(nl);
delete netlists;
-#endif
}
else
{
if (argidx == GetSize(args))
log_cmd_error("No top module specified.\n");
-#if 0
- for (; argidx < GetSize(args); argidx++) {
- if (veri_file::GetModule(args[argidx].c_str())) {
- log("Running veri_file::Elaborate(\"%s\").\n", args[argidx].c_str());
- if (!veri_file::Elaborate(args[argidx].c_str()))
- log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
- nl_todo.insert(Netlist::PresentDesign());
- } else {
- log("Running vhdl_file::Elaborate(\"%s\").\n", args[argidx].c_str());
- if (!vhdl_file::Elaborate(args[argidx].c_str()))
- log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
- nl_todo.insert(Netlist::PresentDesign());
- }
- }
-#else
Array veri_modules, vhdl_units;
for (; argidx < GetSize(args); argidx++)
{
const char *name = args[argidx].c_str();
+ VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1);
+
+ if (veri_lib) {
+ VeriModule *veri_module = veri_lib->GetModule(name, 1);
+ if (veri_module) {
+ log("Adding Verilog module '%s' to elaboration queue.\n", name);
+ veri_modules.InsertLast(veri_module);
+ continue;
+ }
- 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;
+ // Also elaborate all root modules since they may contain bind statements
+ MapIter mi;
+ FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
+ if (!veri_module->IsRootModule()) continue;
+ veri_modules.InsertLast(veri_module);
+ }
}
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1);
@@ -2177,14 +2344,15 @@ struct VerificPass : public Pass {
}
log("Running hier_tree::Elaborate().\n");
- Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units);
+ Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &parameters);
Netlist *nl;
int i;
- FOREACH_ARRAY_ITEM(netlists, i, nl)
+ FOREACH_ARRAY_ITEM(netlists, i, nl) {
+ nl->AddAtt(new Att(" \\top", NULL));
nl_todo.insert(nl);
+ }
delete netlists;
-#endif
}
if (!verific_error_msg.empty())
@@ -2274,21 +2442,43 @@ struct ReadPass : public Pass {
log("\n");
log("Add directory to global Verilog/SystemVerilog include directories.\n");
log("\n");
+ log("\n");
+ log(" read -verific\n");
+ log(" read -noverific\n");
+ log("\n");
+ log("Subsequent calls to 'read' will either use or not use Verific. Calling 'read'\n");
+ log("with -verific will result in an error on Yosys binaries that are built without\n");
+ log("Verific support. The default is to use Verific if it is available.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- if (args.size() < 2)
+#ifdef YOSYS_ENABLE_VERIFIC
+ static bool verific_available = !check_noverific_env();
+#else
+ static bool verific_available = false;
+#endif
+ static bool use_verific = verific_available;
+
+ if (args.size() < 2 || args[1][0] != '-')
log_cmd_error("Missing mode parameter.\n");
+ if (args[1] == "-verific" || args[1] == "-noverific") {
+ if (args.size() != 2)
+ log_cmd_error("Additional arguments to -verific/-noverific.\n");
+ if (args[1] == "-verific") {
+ if (!verific_available)
+ log_cmd_error("This version of Yosys is built without Verific support.\n");
+ use_verific = true;
+ } else {
+ use_verific = false;
+ }
+ return;
+ }
+
if (args.size() < 3)
log_cmd_error("Missing file name parameter.\n");
-#ifdef YOSYS_ENABLE_VERIFIC
- bool use_verific = !check_noverific_env();
-#else
- bool use_verific = false;
-#endif
-
if (args[1] == "-vlog95" || args[1] == "-vlog2k") {
if (use_verific) {
args[0] = "verific";
diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h
index 334a436a..88a6cc0b 100644
--- a/frontends/verific/verific.h
+++ b/frontends/verific/verific.h
@@ -26,7 +26,7 @@ YOSYS_NAMESPACE_BEGIN
extern int verific_verbose;
extern bool verific_import_pending;
-extern void verific_import(Design *design, std::string top = std::string());
+extern void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top = std::string());
extern pool<int> verific_sva_prims;
@@ -78,6 +78,7 @@ struct VerificImporter
RTLIL::SigBit net_map_at(Verific::Net *net);
+ RTLIL::IdString new_verific_id(Verific::DesignObj *obj);
void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, Verific::DesignObj *obj);
RTLIL::SigSpec operatorInput(Verific::Instance *inst);
diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc
index cdc9ece8..8ea8372d 100644
--- a/frontends/verific/verificsva.cc
+++ b/frontends/verific/verificsva.cc
@@ -827,9 +827,9 @@ struct SvaFsm
for (auto &it : nodes[i].edges) {
if (it.second != State::S1)
- log(" egde %s -> %d\n", log_signal(it.second), it.first);
+ log(" edge %s -> %d\n", log_signal(it.second), it.first);
else
- log(" egde -> %d\n", it.first);
+ log(" edge -> %d\n", it.first);
}
for (auto &it : nodes[i].links) {
@@ -856,9 +856,9 @@ struct SvaFsm
for (auto &it : unodes[i].edges) {
if (!it.second.empty())
- log(" egde %s -> %d\n", log_signal(it.second), it.first);
+ log(" edge %s -> %d\n", log_signal(it.second), it.first);
else
- log(" egde -> %d\n", it.first);
+ log(" edge -> %d\n", it.first);
}
for (auto &ctrl : unodes[i].accept) {
@@ -1666,7 +1666,20 @@ struct VerificSvaImporter
log(" importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(),
LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile()));
- RTLIL::IdString root_name = module->uniquify(importer->mode_names || root->IsUserDeclared() ? RTLIL::escape_id(root->Name()) : NEW_ID);
+ bool is_user_declared = root->IsUserDeclared();
+
+ // FIXME
+ if (!is_user_declared) {
+ const char *name = root->Name();
+ for (int i = 0; name[i]; i++) {
+ if (i ? (name[i] < '0' || name[i] > '9') : (name[i] != 'i')) {
+ is_user_declared = true;
+ break;
+ }
+ }
+ }
+
+ RTLIL::IdString root_name = module->uniquify(importer->mode_names || is_user_declared ? RTLIL::escape_id(root->Name()) : NEW_ID);
// parse SVA sequence into trigger signal
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc
index dbaace58..6a8462b4 100644
--- a/frontends/verilog/Makefile.inc
+++ b/frontends/verilog/Makefile.inc
@@ -14,6 +14,8 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
$(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/verilog/verilog_lexer.cc $<
+frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=10000000
+
OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o
OBJS += frontends/verilog/preproc.o
diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
index 7848c626..f6a17b24 100644
--- a/frontends/verilog/const2ast.cc
+++ b/frontends/verilog/const2ast.cc
@@ -71,7 +71,7 @@ static int my_ilog2(int x)
}
// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
-static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type)
+static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized)
{
// all digits in string (MSB at index 0)
std::vector<uint8_t> digits;
@@ -129,6 +129,9 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
return;
}
+ if (is_unsized && (len > len_in_bits))
+ log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len);
+
for (len = len - 1; len >= 0; len--)
if (data[len] == RTLIL::S1)
break;
@@ -150,7 +153,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
if (warn_z) {
AstNode *ret = const2ast(code, case_type);
- if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
+ if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n",
current_filename.c_str(), get_line_num());
return ret;
@@ -186,7 +189,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
// Simple base-10 integer
if (*endptr == 0) {
std::vector<RTLIL::State> data;
- my_strtobin(data, str, -1, 10, case_type);
+ my_strtobin(data, str, -1, 10, case_type, false);
if (data.back() == RTLIL::S1)
data.push_back(RTLIL::S0);
return AstNode::mkconst_bits(data, true);
@@ -201,6 +204,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
std::vector<RTLIL::State> data;
bool is_signed = false;
+ bool is_unsized = len_in_bits < 0;
if (*(endptr+1) == 's') {
is_signed = true;
endptr++;
@@ -209,28 +213,34 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
case 'b':
case 'B':
- my_strtobin(data, endptr+2, len_in_bits, 2, case_type);
+ my_strtobin(data, endptr+2, len_in_bits, 2, case_type, is_unsized);
break;
case 'o':
case 'O':
- my_strtobin(data, endptr+2, len_in_bits, 8, case_type);
+ my_strtobin(data, endptr+2, len_in_bits, 8, case_type, is_unsized);
break;
case 'd':
case 'D':
- my_strtobin(data, endptr+2, len_in_bits, 10, case_type);
+ my_strtobin(data, endptr+2, len_in_bits, 10, case_type, is_unsized);
break;
case 'h':
case 'H':
- my_strtobin(data, endptr+2, len_in_bits, 16, case_type);
+ my_strtobin(data, endptr+2, len_in_bits, 16, case_type, is_unsized);
break;
default:
- return NULL;
+ char next_char = char(tolower(*(endptr+1)));
+ if (next_char == '0' || next_char == '1' || next_char == 'x' || next_char == 'z') {
+ is_unsized = true;
+ my_strtobin(data, endptr+1, 1, 2, case_type, is_unsized);
+ } else {
+ return NULL;
+ }
}
if (len_in_bits < 0) {
if (is_signed && data.back() == RTLIL::S1)
data.push_back(RTLIL::S0);
}
- return AstNode::mkconst_bits(data, is_signed);
+ return AstNode::mkconst_bits(data, is_signed, is_unsized);
}
return NULL;
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
index 8dcc7c5a..0e2bead6 100644
--- a/frontends/verilog/verilog_frontend.cc
+++ b/frontends/verilog/verilog_frontend.cc
@@ -66,12 +66,24 @@ struct VerilogFrontend : public Frontend {
log(" enable support for SystemVerilog assertions and some Yosys extensions\n");
log(" replace the implicit -D SYNTHESIS with -D FORMAL\n");
log("\n");
+ log(" -noassert\n");
+ log(" ignore assert() statements\n");
+ log("\n");
+ log(" -noassume\n");
+ log(" ignore assume() statements\n");
+ log("\n");
log(" -norestrict\n");
- log(" ignore restrict() assertions\n");
+ log(" ignore restrict() statements\n");
log("\n");
log(" -assume-asserts\n");
log(" treat all assert() statements like assume() statements\n");
log("\n");
+ log(" -assert-assumes\n");
+ log(" treat all assume() statements like assert() statements\n");
+ log("\n");
+ log(" -debug\n");
+ log(" alias for -dump_ast1 -dump_ast2 -dump_vlog1 -dump_vlog2 -yydebug\n");
+ log("\n");
log(" -dump_ast1\n");
log(" dump abstract syntax tree (before simplification)\n");
log("\n");
@@ -81,7 +93,10 @@ struct VerilogFrontend : public Frontend {
log(" -no_dump_ptr\n");
log(" do not include hex memory addresses in dump (easier to diff dumps)\n");
log("\n");
- log(" -dump_vlog\n");
+ log(" -dump_vlog1\n");
+ log(" dump ast as Verilog code (before simplification)\n");
+ log("\n");
+ log(" -dump_vlog2\n");
log(" dump ast as Verilog code (after simplification)\n");
log("\n");
log(" -dump_rtlil\n");
@@ -130,8 +145,21 @@ struct VerilogFrontend : public Frontend {
log(" -nodpi\n");
log(" disable DPI-C support\n");
log("\n");
+ log(" -noblackbox\n");
+ log(" do not automatically add a (* blackbox *) attribute to an\n");
+ log(" empty module.\n");
+ log("\n");
log(" -lib\n");
log(" only create empty blackbox modules. This implies -DBLACKBOX.\n");
+ log(" modules with the (* whitebox *) attribute will be preserved.\n");
+ log(" (* lib_whitebox *) will be treated like (* whitebox *).\n");
+ log("\n");
+ log(" -nowb\n");
+ log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n");
+ log(" all modules.\n");
+ log("\n");
+ log(" -specify\n");
+ log(" parse and import specify blocks\n");
log("\n");
log(" -noopt\n");
log(" don't perform basic optimizations (such as const folding) in the\n");
@@ -140,6 +168,9 @@ struct VerilogFrontend : public Frontend {
log(" -icells\n");
log(" interpret cell types starting with '$' as internal cell types\n");
log("\n");
+ log(" -pwires\n");
+ log(" add a wire for each module parameter\n");
+ log("\n");
log(" -nooverwrite\n");
log(" ignore re-definitions of modules. (the default behavior is to\n");
log(" create an error message if the existing module is not a black box\n");
@@ -188,7 +219,8 @@ struct VerilogFrontend : public Frontend {
bool flag_dump_ast1 = false;
bool flag_dump_ast2 = false;
bool flag_no_dump_ptr = false;
- bool flag_dump_vlog = false;
+ bool flag_dump_vlog1 = false;
+ bool flag_dump_vlog2 = false;
bool flag_dump_rtlil = false;
bool flag_nolatches = false;
bool flag_nomeminit = false;
@@ -199,9 +231,12 @@ struct VerilogFrontend : public Frontend {
bool flag_nodpi = false;
bool flag_noopt = false;
bool flag_icells = false;
+ bool flag_pwires = false;
bool flag_nooverwrite = false;
bool flag_overwrite = false;
bool flag_defer = false;
+ bool flag_noblackbox = false;
+ bool flag_nowb = false;
std::map<std::string, std::string> defines_map;
std::list<std::string> include_dirs;
std::list<std::string> attributes;
@@ -212,10 +247,9 @@ struct VerilogFrontend : public Frontend {
norestrict_mode = false;
assume_asserts_mode = false;
lib_mode = false;
+ specify_mode = false;
default_nettype_wire = true;
- log_header(design, "Executing Verilog-2005 frontend.\n");
-
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
size_t argidx;
@@ -229,6 +263,14 @@ struct VerilogFrontend : public Frontend {
formal_mode = true;
continue;
}
+ if (arg == "-noassert") {
+ noassert_mode = true;
+ continue;
+ }
+ if (arg == "-noassume") {
+ noassume_mode = true;
+ continue;
+ }
if (arg == "-norestrict") {
norestrict_mode = true;
continue;
@@ -237,6 +279,18 @@ struct VerilogFrontend : public Frontend {
assume_asserts_mode = true;
continue;
}
+ if (arg == "-assert-assumes") {
+ assert_assumes_mode = true;
+ continue;
+ }
+ if (arg == "-debug") {
+ flag_dump_ast1 = true;
+ flag_dump_ast2 = true;
+ flag_dump_vlog1 = true;
+ flag_dump_vlog2 = true;
+ frontend_verilog_yydebug = true;
+ continue;
+ }
if (arg == "-dump_ast1") {
flag_dump_ast1 = true;
continue;
@@ -249,8 +303,12 @@ struct VerilogFrontend : public Frontend {
flag_no_dump_ptr = true;
continue;
}
- if (arg == "-dump_vlog") {
- flag_dump_vlog = true;
+ if (arg == "-dump_vlog1") {
+ flag_dump_vlog1 = true;
+ continue;
+ }
+ if (arg == "-dump_vlog2") {
+ flag_dump_vlog2 = true;
continue;
}
if (arg == "-dump_rtlil") {
@@ -289,11 +347,23 @@ struct VerilogFrontend : public Frontend {
flag_nodpi = true;
continue;
}
+ if (arg == "-noblackbox") {
+ flag_noblackbox = true;
+ continue;
+ }
if (arg == "-lib") {
lib_mode = true;
defines_map["BLACKBOX"] = string();
continue;
}
+ if (arg == "-nowb") {
+ flag_nowb = true;
+ continue;
+ }
+ if (arg == "-specify") {
+ specify_mode = true;
+ continue;
+ }
if (arg == "-noopt") {
flag_noopt = true;
continue;
@@ -302,6 +372,10 @@ struct VerilogFrontend : public Frontend {
flag_icells = true;
continue;
}
+ if (arg == "-pwires") {
+ flag_pwires = true;
+ continue;
+ }
if (arg == "-ignore_redef" || arg == "-nooverwrite") {
flag_nooverwrite = true;
flag_overwrite = false;
@@ -355,6 +429,8 @@ struct VerilogFrontend : public Frontend {
}
extra_args(f, filename, args, argidx);
+ log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str());
+
log("Parsing %s%s input from `%s' to AST representation.\n",
formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
@@ -389,7 +465,8 @@ struct VerilogFrontend : public Frontend {
if (flag_nodpi)
error_on_dpi_function(current_ast);
- AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
+ AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
+ flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
if (!flag_nopp)
delete lexin;
diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h
index 16edc798..a7c9b2fe 100644
--- a/frontends/verilog/verilog_frontend.h
+++ b/frontends/verilog/verilog_frontend.h
@@ -54,15 +54,27 @@ namespace VERILOG_FRONTEND
// running in -formal mode
extern bool formal_mode;
+ // running in -noassert mode
+ extern bool noassert_mode;
+
+ // running in -noassume mode
+ extern bool noassume_mode;
+
// running in -norestrict mode
extern bool norestrict_mode;
// running in -assume-asserts mode
extern bool assume_asserts_mode;
+ // running in -assert-assumes mode
+ extern bool assert_assumes_mode;
+
// running in -lib mode
extern bool lib_mode;
+ // running in -specify mode
+ extern bool specify_mode;
+
// lexer input stream
extern std::istream *lexin;
}
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 83921bf0..951d9c66 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -135,6 +135,9 @@ YOSYS_NAMESPACE_END
frontend_verilog_yyerror("Unsupported default nettype: %s", p);
}
+"`protect"[^\n]* /* ignore `protect*/
+"`endprotect"[^\n]* /* ignore `endprotect*/
+
"`"[a-zA-Z_$][a-zA-Z0-9_$]* {
frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext);
}
@@ -145,11 +148,14 @@ YOSYS_NAMESPACE_END
"endfunction" { return TOK_ENDFUNCTION; }
"task" { return TOK_TASK; }
"endtask" { return TOK_ENDTASK; }
-"specify" { return TOK_SPECIFY; }
+"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; }
"endspecify" { return TOK_ENDSPECIFY; }
"specparam" { return TOK_SPECPARAM; }
"package" { SV_KEYWORD(TOK_PACKAGE); }
"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); }
+"interface" { SV_KEYWORD(TOK_INTERFACE); }
+"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); }
+"modport" { SV_KEYWORD(TOK_MODPORT); }
"parameter" { return TOK_PARAMETER; }
"localparam" { return TOK_LOCALPARAM; }
"defparam" { return TOK_DEFPARAM; }
@@ -183,6 +189,16 @@ YOSYS_NAMESPACE_END
"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
+ /* use special token for labels on assert, assume, cover, and restrict because it's insanley complex
+ to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some
+ global state.. its a mess) */
+[a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] {
+ if (!strcmp(yytext, "default"))
+ return TOK_DEFAULT;
+ frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
+ return TOK_SVA_LABEL;
+}
+
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
@@ -192,7 +208,9 @@ YOSYS_NAMESPACE_END
"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); }
+"final" { SV_KEYWORD(TOK_FINAL); }
"logic" { SV_KEYWORD(TOK_LOGIC); }
+"var" { SV_KEYWORD(TOK_VAR); }
"bit" { SV_KEYWORD(TOK_REG); }
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
@@ -202,6 +220,8 @@ YOSYS_NAMESPACE_END
"output" { return TOK_OUTPUT; }
"inout" { return TOK_INOUT; }
"wire" { return TOK_WIRE; }
+"wor" { return TOK_WOR; }
+"wand" { return TOK_WAND; }
"reg" { return TOK_REG; }
"integer" { return TOK_INTEGER; }
"signed" { return TOK_SIGNED; }
@@ -216,7 +236,7 @@ YOSYS_NAMESPACE_END
return TOK_CONSTVAL;
}
-[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
+[0-9]*[ \t]*\'s?[bodhBODH]*[ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_CONSTVAL;
}
@@ -268,7 +288,7 @@ YOSYS_NAMESPACE_END
yystr[j++] = yystr[i++];
}
yystr[j] = 0;
- frontend_verilog_yylval.string = new std::string(yystr);
+ frontend_verilog_yylval.string = new std::string(yystr, j);
free(yystr);
return TOK_STRING;
}
@@ -287,6 +307,17 @@ supply1 { return TOK_SUPPLY1; }
return TOK_ID;
}
+"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) {
+ if (!specify_mode) REJECT;
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_ID;
+}
+
+"$"(info|warning|error|fatal) {
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_MSG_TASKS;
+}
+
"$signed" { return TOK_TO_SIGNED; }
"$unsigned" { return TOK_TO_UNSIGNED; }
@@ -295,6 +326,11 @@ supply1 { return TOK_SUPPLY1; }
return TOK_ID;
}
+[a-zA-Z_$][a-zA-Z0-9_$\.]* {
+ frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
+ return TOK_ID;
+}
+
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
static bool printed_warning = false;
if (!printed_warning) {
@@ -392,6 +428,17 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
"+:" { return TOK_POS_INDEXED; }
"-:" { return TOK_NEG_INDEXED; }
+[-+]?[=*]> {
+ if (!specify_mode) REJECT;
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_SPECIFY_OPER;
+}
+
+"&&&" {
+ if (!specify_mode) REJECT;
+ return TOK_SPECIFY_AND;
+}
+
"/*" { BEGIN(COMMENT); }
<COMMENT>. /* ignore comment body */
<COMMENT>\n /* ignore comment body */
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 2389d7d3..0fec445f 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -35,6 +35,7 @@
%{
#include <list>
+#include <stack>
#include <string.h>
#include "frontends/verilog/verilog_frontend.h"
#include "kernel/log.h"
@@ -47,7 +48,8 @@ YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND {
int port_counter;
std::map<std::string, int> port_stubs;
- std::map<std::string, AstNode*> attr_list, default_attr_list;
+ std::map<std::string, AstNode*> *attr_list, default_attr_list;
+ std::stack<std::map<std::string, AstNode*> *> attr_list_stack;
std::map<std::string, AstNode*> *albuf;
std::vector<AstNode*> ast_stack;
struct AstNode *astbuf1, *astbuf2, *astbuf3;
@@ -57,9 +59,11 @@ namespace VERILOG_FRONTEND {
std::vector<char> case_type_stack;
bool do_not_require_port_stubs;
bool default_nettype_wire;
- bool sv_mode, formal_mode, lib_mode;
- bool norestrict_mode, assume_asserts_mode;
+ bool sv_mode, formal_mode, lib_mode, specify_mode;
+ bool noassert_mode, noassume_mode, norestrict_mode;
+ bool assume_asserts_mode, assert_assumes_mode;
bool current_wire_rand, current_wire_const;
+ bool current_modport_input, current_modport_output;
std::istream *lexin;
}
YOSYS_NAMESPACE_END
@@ -90,41 +94,77 @@ static void free_attr(std::map<std::string, AstNode*> *al)
delete al;
}
+struct specify_target {
+ char polarity_op;
+ AstNode *dst, *dat;
+};
+
+struct specify_triple {
+ AstNode *t_min, *t_avg, *t_max;
+};
+
+struct specify_rise_fall {
+ specify_triple rise;
+ specify_triple fall;
+};
+
%}
-%name-prefix "frontend_verilog_yy"
+%define api.prefix {frontend_verilog_yy}
+
+/* The union is defined in the header, so we need to provide all the
+ * includes it requires
+ */
+%code requires {
+#include <map>
+#include <string>
+#include "frontends/verilog/verilog_frontend.h"
+}
%union {
std::string *string;
struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al;
+ struct specify_target *specify_target_ptr;
+ struct specify_triple *specify_triple_ptr;
+ struct specify_rise_fall *specify_rise_fall_ptr;
bool boolean;
+ char ch;
}
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
+%token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS
+%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL
%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 TOK_LOGIC
+%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR
+%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR 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 TOK_AUTOMATIC
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
-%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM
+%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY
+%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
-%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
-%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
+%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
-%type <string> opt_label tok_prim_wrapper hierarchical_id
-%type <boolean> opt_signed unique_case_attr
+%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id
+%type <boolean> opt_signed opt_property unique_case_attr
%type <al> attr case_attr
+%type <specify_target_ptr> specify_target
+%type <specify_triple_ptr> specify_triple
+%type <specify_rise_fall_ptr> specify_rise_fall
+%type <ast> specify_if specify_condition specify_opt_arg
+%type <ch> specify_edge
+
// operator precedence from low to high
%left OP_LOR
%left OP_LAND
@@ -167,19 +207,23 @@ design:
param_decl design |
localparam_decl design |
package design |
+ interface design |
/* empty */;
attr:
{
- for (auto &it : attr_list)
- delete it.second;
- attr_list.clear();
+ if (attr_list != nullptr)
+ attr_list_stack.push(attr_list);
+ attr_list = new std::map<std::string, AstNode*>;
for (auto &it : default_attr_list)
- attr_list[it.first] = it.second->clone();
+ (*attr_list)[it.first] = it.second->clone();
} attr_opt {
- std::map<std::string, AstNode*> *al = new std::map<std::string, AstNode*>;
- al->swap(attr_list);
- $$ = al;
+ $$ = attr_list;
+ if (!attr_list_stack.empty()) {
+ attr_list = attr_list_stack.top();
+ attr_list_stack.pop();
+ } else
+ attr_list = nullptr;
};
attr_opt:
@@ -188,15 +232,20 @@ attr_opt:
defattr:
DEFATTR_BEGIN {
+ if (attr_list != nullptr)
+ attr_list_stack.push(attr_list);
+ attr_list = new std::map<std::string, AstNode*>;
for (auto &it : default_attr_list)
delete it.second;
default_attr_list.clear();
- for (auto &it : attr_list)
- delete it.second;
- attr_list.clear();
} opt_attr_list {
- default_attr_list = attr_list;
- attr_list.clear();
+ attr_list->swap(default_attr_list);
+ delete attr_list;
+ if (!attr_list_stack.empty()) {
+ attr_list = attr_list_stack.top();
+ attr_list_stack.pop();
+ } else
+ attr_list = nullptr;
} DEFATTR_END;
opt_attr_list:
@@ -208,15 +257,15 @@ attr_list:
attr_assign:
hierarchical_id {
- if (attr_list.count(*$1) != 0)
- delete attr_list[*$1];
- attr_list[*$1] = AstNode::mkconst_int(1, false);
+ if (attr_list->count(*$1) != 0)
+ delete (*attr_list)[*$1];
+ (*attr_list)[*$1] = AstNode::mkconst_int(1, false);
delete $1;
} |
hierarchical_id '=' expr {
- if (attr_list.count(*$1) != 0)
- delete attr_list[*$1];
- attr_list[*$1] = $3;
+ if (attr_list->count(*$1) != 0)
+ delete (*attr_list)[*$1];
+ (*attr_list)[*$1] = $3;
delete $1;
};
@@ -270,15 +319,17 @@ module_para_list:
single_module_para:
/* empty */ |
- TOK_PARAMETER {
+ attr TOK_PARAMETER {
if (astbuf1) delete astbuf1;
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
+ append_attr(astbuf1, $1);
} param_signed param_integer param_range single_param_decl |
- TOK_LOCALPARAM {
+ attr TOK_LOCALPARAM {
if (astbuf1) delete astbuf1;
astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
+ append_attr(astbuf1, $1);
} param_signed param_integer param_range single_param_decl |
single_param_decl;
@@ -296,12 +347,18 @@ module_arg_opt_assignment:
if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) {
AstNode *wire = new AstNode(AST_IDENTIFIER);
wire->str = ast_stack.back()->children.back()->str;
- if (ast_stack.back()->children.back()->is_reg)
+ if (ast_stack.back()->children.back()->is_input) {
+ AstNode *n = ast_stack.back()->children.back();
+ if (n->attributes.count("\\defaultvalue"))
+ delete n->attributes.at("\\defaultvalue");
+ n->attributes["\\defaultvalue"] = $2;
+ } else
+ if (ast_stack.back()->children.back()->is_reg || ast_stack.back()->children.back()->is_logic)
ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2))));
else
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2));
} else
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("SystemVerilog interface in module port list cannot have a default value.");
} |
/* empty */;
@@ -319,6 +376,21 @@ module_arg:
}
delete $1;
} module_arg_opt_assignment |
+ TOK_ID {
+ astbuf1 = new AstNode(AST_INTERFACEPORT);
+ astbuf1->children.push_back(new AstNode(AST_INTERFACEPORTTYPE));
+ astbuf1->children[0]->str = *$1;
+ delete $1;
+ } TOK_ID { /* SV interfaces */
+ if (!sv_mode)
+ frontend_verilog_yyerror("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str());
+ astbuf2 = astbuf1->clone(); // really only needed if multiple instances of same type.
+ astbuf2->str = *$3;
+ delete $3;
+ astbuf2->port_id = ++port_counter;
+ ast_stack.back()->children.push_back(astbuf2);
+ delete astbuf1; // really only needed if multiple instances of same type.
+ } module_arg_opt_assignment |
attr wire_type range TOK_ID {
AstNode *node = $2;
node->str = *$4;
@@ -356,6 +428,33 @@ package_body:
package_body_stmt:
localparam_decl;
+interface:
+ TOK_INTERFACE TOK_ID {
+ do_not_require_port_stubs = false;
+ AstNode *intf = new AstNode(AST_INTERFACE);
+ ast_stack.back()->children.push_back(intf);
+ ast_stack.push_back(intf);
+ current_ast_mod = intf;
+ port_stubs.clear();
+ port_counter = 0;
+ intf->str = *$2;
+ delete $2;
+ } module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE {
+ if (port_stubs.size() != 0)
+ frontend_verilog_yyerror("Missing details for module port `%s'.",
+ port_stubs.begin()->first.c_str());
+ ast_stack.pop_back();
+ log_assert(ast_stack.size() == 1);
+ current_ast_mod = NULL;
+ };
+
+interface_body:
+ interface_body interface_body_stmt |;
+
+interface_body_stmt:
+ param_decl | localparam_decl | defparam_decl | wire_decl | always_stmt | assign_stmt |
+ modport_stmt;
+
non_opt_delay:
'#' TOK_ID { delete $2; } |
'#' TOK_CONSTVAL { delete $2; } |
@@ -394,12 +493,21 @@ wire_type_token_io:
wire_type_token:
TOK_WIRE {
} |
+ TOK_WOR {
+ astbuf3->is_wor = true;
+ } |
+ TOK_WAND {
+ astbuf3->is_wand = true;
+ } |
TOK_REG {
astbuf3->is_reg = true;
} |
TOK_LOGIC {
astbuf3->is_logic = true;
} |
+ TOK_VAR {
+ astbuf3->is_logic = true;
+ } |
TOK_INTEGER {
astbuf3->is_reg = true;
astbuf3->range_left = 31;
@@ -409,6 +517,7 @@ wire_type_token:
TOK_GENVAR {
astbuf3->type = AST_GENVAR;
astbuf3->is_reg = true;
+ astbuf3->is_signed = true;
astbuf3->range_left = 31;
astbuf3->range_right = 0;
} |
@@ -483,7 +592,7 @@ module_body:
module_body_stmt:
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;
+ always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
checker_decl:
TOK_CHECKER TOK_ID ';' {
@@ -626,7 +735,7 @@ task_func_port:
astbuf2 = $3;
if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
if (astbuf2) {
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions (task/function arguments)");
} else {
astbuf2 = new AstNode(AST_RANGE);
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
@@ -634,22 +743,261 @@ task_func_port:
}
}
if (astbuf2 && astbuf2->children.size() != 2)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("task/function argument range must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]");
} wire_name | wire_name;
task_func_body:
task_func_body behavioral_stmt |
/* empty */;
+/*************************** specify parser ***************************/
+
specify_block:
- TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY |
- TOK_SPECIFY TOK_ENDSPECIFY ;
+ TOK_SPECIFY specify_item_list TOK_ENDSPECIFY;
-specify_item_opt:
- specify_item_opt specify_item |
- specify_item ;
+specify_item_list:
+ specify_item specify_item_list |
+ /* empty */;
specify_item:
+ specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' {
+ AstNode *en_expr = $1;
+ char specify_edge = $3;
+ AstNode *src_expr = $4;
+ string *oper = $5;
+ specify_target *target = $6;
+ specify_rise_fall *timing = $9;
+
+ if (specify_edge != 0 && target->dat == nullptr)
+ frontend_verilog_yyerror("Found specify edge but no data spec.\n");
+
+ AstNode *cell = new AstNode(AST_CELL);
+ ast_stack.back()->children.push_back(cell);
+ cell->str = stringf("$specify$%d", autoidx++);
+ cell->children.push_back(new AstNode(AST_CELLTYPE));
+ cell->children.back()->str = target->dat ? "$specify3" : "$specify2";
+
+ char oper_polarity = 0;
+ char oper_type = oper->at(0);
+
+ if (oper->size() == 3) {
+ oper_polarity = oper->at(0);
+ oper_type = oper->at(1);
+ }
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1)));
+ cell->children.back()->str = "\\FULL";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1)));
+ cell->children.back()->str = "\\SRC_DST_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1)));
+ cell->children.back()->str = "\\SRC_DST_POL";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min));
+ cell->children.back()->str = "\\T_RISE_MIN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg));
+ cell->children.back()->str = "\\T_RISE_TYP";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max));
+ cell->children.back()->str = "\\T_RISE_MAX";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min));
+ cell->children.back()->str = "\\T_FALL_MIN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg));
+ cell->children.back()->str = "\\T_FALL_TYP";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max));
+ cell->children.back()->str = "\\T_FALL_MAX";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1)));
+ cell->children.back()->str = "\\EN";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
+ cell->children.back()->str = "\\SRC";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst));
+ cell->children.back()->str = "\\DST";
+
+ if (target->dat)
+ {
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1)));
+ cell->children.back()->str = "\\EDGE_EN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1)));
+ cell->children.back()->str = "\\EDGE_POL";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1)));
+ cell->children.back()->str = "\\DAT_DST_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1)));
+ cell->children.back()->str = "\\DAT_DST_POL";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat));
+ cell->children.back()->str = "\\DAT";
+ }
+
+ delete oper;
+ delete target;
+ delete timing;
+ } |
+ TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' {
+ if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" &&
+ *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange")
+ frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str());
+
+ AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1);
+ AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1);
+ AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1);
+
+ AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1);
+ AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1);
+ AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1);
+
+ AstNode *limit = $11;
+ AstNode *limit2 = $12;
+
+ AstNode *cell = new AstNode(AST_CELL);
+ ast_stack.back()->children.push_back(cell);
+ cell->str = stringf("$specify$%d", autoidx++);
+ cell->children.push_back(new AstNode(AST_CELLTYPE));
+ cell->children.back()->str = "$specrule";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1)));
+ cell->children.back()->str = "\\TYPE";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit));
+ cell->children.back()->str = "\\T_LIMIT";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true)));
+ cell->children.back()->str = "\\T_LIMIT2";
+
+ cell->children.push_back(new AstNode(AST_PARASET, src_pen));
+ cell->children.back()->str = "\\SRC_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, src_pol));
+ cell->children.back()->str = "\\SRC_POL";
+
+ cell->children.push_back(new AstNode(AST_PARASET, dst_pen));
+ cell->children.back()->str = "\\DST_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, dst_pol));
+ cell->children.back()->str = "\\DST_POL";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, src_en));
+ cell->children.back()->str = "\\SRC_EN";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
+ cell->children.back()->str = "\\SRC";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en));
+ cell->children.back()->str = "\\DST_EN";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr));
+ cell->children.back()->str = "\\DST";
+
+ delete $1;
+ };
+
+specify_opt_arg:
+ ',' expr {
+ $$ = $2;
+ } |
+ /* empty */ {
+ $$ = nullptr;
+ };
+
+specify_if:
+ TOK_IF '(' expr ')' {
+ $$ = $3;
+ } |
+ /* empty */ {
+ $$ = nullptr;
+ };
+
+specify_condition:
+ TOK_SPECIFY_AND expr {
+ $$ = $2;
+ } |
+ /* empty */ {
+ $$ = nullptr;
+ };
+
+specify_target:
+ expr {
+ $$ = new specify_target;
+ $$->polarity_op = 0;
+ $$->dst = $1;
+ $$->dat = nullptr;
+ } |
+ '(' expr ':' expr ')'{
+ $$ = new specify_target;
+ $$->polarity_op = 0;
+ $$->dst = $2;
+ $$->dat = $4;
+ } |
+ '(' expr TOK_NEG_INDEXED expr ')'{
+ $$ = new specify_target;
+ $$->polarity_op = '-';
+ $$->dst = $2;
+ $$->dat = $4;
+ } |
+ '(' expr TOK_POS_INDEXED expr ')'{
+ $$ = new specify_target;
+ $$->polarity_op = '+';
+ $$->dst = $2;
+ $$->dat = $4;
+ };
+
+specify_edge:
+ TOK_POSEDGE { $$ = 'p'; } |
+ TOK_NEGEDGE { $$ = 'n'; } |
+ { $$ = 0; };
+
+specify_rise_fall:
+ specify_triple {
+ $$ = new specify_rise_fall;
+ $$->rise = *$1;
+ $$->fall.t_min = $1->t_min->clone();
+ $$->fall.t_avg = $1->t_avg->clone();
+ $$->fall.t_max = $1->t_max->clone();
+ delete $1;
+ } |
+ '(' specify_triple ',' specify_triple ')' {
+ $$ = new specify_rise_fall;
+ $$->rise = *$2;
+ $$->fall = *$4;
+ delete $2;
+ delete $4;
+ };
+
+specify_triple:
+ expr {
+ $$ = new specify_triple;
+ $$->t_min = $1;
+ $$->t_avg = $1->clone();
+ $$->t_max = $1->clone();
+ } |
+ expr ':' expr ':' expr {
+ $$ = new specify_triple;
+ $$->t_min = $1;
+ $$->t_avg = $3;
+ $$->t_max = $5;
+ };
+
+/******************** ignored specify parser **************************/
+
+ignored_specify_block:
+ TOK_IGNORED_SPECIFY ignored_specify_item_opt TOK_ENDSPECIFY |
+ TOK_IGNORED_SPECIFY TOK_ENDSPECIFY ;
+
+ignored_specify_item_opt:
+ ignored_specify_item_opt ignored_specify_item |
+ ignored_specify_item ;
+
+ignored_specify_item:
specparam_declaration
// | pulsestyle_declaration
// | showcancelled_declaration
@@ -665,21 +1013,16 @@ specparam_declaration:
// 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 ']' ;
+ '[' ignspec_constant_expression ':' ignspec_constant_expression ']' ;
list_of_specparam_assignments:
specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
specparam_assignment:
- TOK_ID '=' constant_mintypmax_expression ;
+ ignspec_id '=' constant_mintypmax_expression ;
-/*
-pulsestyle_declaration :
- ;
-
-showcancelled_declaration :
- ;
-*/
+ignspec_opt_cond:
+ TOK_IF '(' ignspec_expr ')' | /* empty */;
path_declaration :
simple_path_declaration ';'
@@ -688,8 +1031,8 @@ path_declaration :
;
simple_path_declaration :
- parallel_path_description '=' path_delay_value |
- full_path_description '=' path_delay_value
+ ignspec_opt_cond parallel_path_description '=' path_delay_value |
+ ignspec_opt_cond full_path_description '=' path_delay_value
;
path_delay_value :
@@ -699,32 +1042,20 @@ path_delay_value :
;
list_of_path_delay_extra_expressions :
-/*
- t_path_delay_expression
- | trise_path_delay_expression ',' tfall_path_delay_expression
- | trise_path_delay_expression ',' tfall_path_delay_expression ',' tz_path_delay_expression
- | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ','
- tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression
- | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ','
- tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression ','
- t0x_path_delay_expression ',' tx1_path_delay_expression ',' t1x_path_delay_expression ','
- tx0_path_delay_expression ',' txz_path_delay_expression ',' tzx_path_delay_expression
-*/
- ',' path_delay_expression
- | ',' path_delay_expression ',' path_delay_expression
- | ',' path_delay_expression ',' path_delay_expression ','
- path_delay_expression ',' path_delay_expression ',' path_delay_expression
- | ',' path_delay_expression ',' path_delay_expression ','
- path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
- path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
- path_delay_expression ',' path_delay_expression ',' path_delay_expression
- ;
+ ',' path_delay_expression | ',' path_delay_expression list_of_path_delay_extra_expressions;
+
+specify_edge_identifier :
+ TOK_POSEDGE | TOK_NEGEDGE ;
parallel_path_description :
- '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' ;
+ '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' |
+ '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor opt_polarity_operator ':' ignspec_expr ')' ')' |
+ '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor TOK_POS_INDEXED ignspec_expr ')' ')' ;
full_path_description :
- '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' ;
+ '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' |
+ '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs opt_polarity_operator ':' ignspec_expr ')' ')' |
+ '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs TOK_POS_INDEXED ignspec_expr ')' ')' ;
// This was broken into 2 rules to solve shift/reduce conflicts
list_of_path_inputs :
@@ -738,7 +1069,7 @@ more_path_inputs :
list_of_path_outputs :
specify_output_terminal_descriptor |
list_of_path_outputs ',' specify_output_terminal_descriptor ;
-
+
opt_polarity_operator :
'+'
| '-'
@@ -746,88 +1077,46 @@ opt_polarity_operator :
// Good enough for the time being
specify_input_terminal_descriptor :
- TOK_ID ;
+ ignspec_id ;
// Good enough for the time being
specify_output_terminal_descriptor :
- TOK_ID ;
+ ignspec_id ;
system_timing_declaration :
- TOK_ID '(' system_timing_args ')' ';' ;
+ ignspec_id '(' system_timing_args ')' ';' ;
system_timing_arg :
- TOK_POSEDGE TOK_ID |
- TOK_NEGEDGE TOK_ID |
- expr ;
+ TOK_POSEDGE ignspec_id |
+ TOK_NEGEDGE ignspec_id |
+ ignspec_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;
+ ignspec_constant_expression;
constant_mintypmax_expression :
- constant_expression
- | constant_expression ':' constant_expression ':' constant_expression
+ ignspec_constant_expression
+ | ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_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 ;
+// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness
+ignspec_constant_expression:
+ expr { delete $1; };
+
+ignspec_expr:
+ expr { delete $1; };
+
+ignspec_id:
+ TOK_ID { delete $1; };
+
+/**********************************************************************/
param_signed:
TOK_SIGNED {
@@ -837,7 +1126,7 @@ param_signed:
param_integer:
TOK_INTEGER {
if (astbuf1->children.size() != 1)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Internal error in param_integer - should not happen?");
astbuf1->children.push_back(new AstNode(AST_RANGE));
astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true));
astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true));
@@ -847,7 +1136,7 @@ param_integer:
param_real:
TOK_REAL {
if (astbuf1->children.size() != 1)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Parameter already declared as integer, cannot set to real.");
astbuf1->children.push_back(new AstNode(AST_REALVALUE));
} | /* empty */;
@@ -855,23 +1144,25 @@ param_range:
range {
if ($1 != NULL) {
if (astbuf1->children.size() != 1)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("integer/real parameters should not have a range.");
astbuf1->children.push_back($1);
}
};
param_decl:
- TOK_PARAMETER {
+ attr TOK_PARAMETER {
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
+ append_attr(astbuf1, $1);
} param_signed param_integer param_real param_range param_decl_list ';' {
delete astbuf1;
};
localparam_decl:
- TOK_LOCALPARAM {
+ attr TOK_LOCALPARAM {
astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
+ append_attr(astbuf1, $1);
} param_signed param_integer param_real param_range param_decl_list ';' {
delete astbuf1;
};
@@ -881,9 +1172,15 @@ param_decl_list:
single_param_decl:
TOK_ID '=' expr {
- if (astbuf1 == nullptr)
- frontend_verilog_yyerror("syntax error");
- AstNode *node = astbuf1->clone();
+ AstNode *node;
+ if (astbuf1 == nullptr) {
+ if (!sv_mode)
+ frontend_verilog_yyerror("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword");
+ node = new AstNode(AST_PARAMETER);
+ node->children.push_back(AstNode::mkconst_int(0, true));
+ } else {
+ node = astbuf1->clone();
+ }
node->str = *$1;
delete node->children[0];
node->children[0] = $3;
@@ -914,7 +1211,7 @@ wire_decl:
astbuf2 = $3;
if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
if (astbuf2) {
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions.");
} else {
astbuf2 = new AstNode(AST_RANGE);
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
@@ -922,7 +1219,7 @@ wire_decl:
}
}
if (astbuf2 && astbuf2->children.size() != 2)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]");
} wire_name_list {
delete astbuf1;
if (astbuf2 != NULL)
@@ -1007,7 +1304,12 @@ wire_name_and_opt_assign:
wire_name '=' expr {
AstNode *wire = new AstNode(AST_IDENTIFIER);
wire->str = ast_stack.back()->children.back()->str;
- if (astbuf1->is_reg)
+ if (astbuf1->is_input) {
+ if (astbuf1->attributes.count("\\defaultvalue"))
+ delete astbuf1->attributes.at("\\defaultvalue");
+ astbuf1->attributes["\\defaultvalue"] = $3;
+ } else
+ if (astbuf1->is_reg || astbuf1->is_logic)
ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $3))));
else
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $3));
@@ -1016,7 +1318,7 @@ wire_name_and_opt_assign:
wire_name:
TOK_ID range_or_multirange {
if (astbuf1 == nullptr)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Internal error - should not happen - no AST_WIRE node.");
AstNode *node = astbuf1->clone();
node->str = *$1;
append_attr_clone(node, albuf);
@@ -1024,7 +1326,7 @@ wire_name:
node->children.push_back(astbuf2->clone());
if ($2 != NULL) {
if (node->is_input || node->is_output)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("input/output/inout ports cannot have unpacked dimensions.");
if (!astbuf2) {
AstNode *rng = new AstNode(AST_RANGE);
rng->children.push_back(AstNode::mkconst_int(0, true));
@@ -1032,7 +1334,13 @@ wire_name:
node->children.push_back(rng);
}
node->type = AST_MEMORY;
- node->children.push_back($2);
+ auto *rangeNode = $2;
+ if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) {
+ // SV array size [n], rewrite as [n-1:0]
+ rangeNode->children[0] = new AstNode(AST_SUB, rangeNode->children[0], AstNode::mkconst_int(1, true));
+ rangeNode->children.push_back(AstNode::mkconst_int(0, false));
+ }
+ node->children.push_back(rangeNode);
}
if (current_function_or_task == NULL) {
if (do_not_require_port_stubs && (node->is_input || node->is_output) && port_stubs.count(*$1) == 0) {
@@ -1179,27 +1487,40 @@ cell_port_list_rules:
cell_port | cell_port_list_rules ',' cell_port;
cell_port:
- /* empty */ {
+ attr {
AstNode *node = new AstNode(AST_ARGUMENT);
astbuf2->children.push_back(node);
+ free_attr($1);
} |
- expr {
+ attr expr {
AstNode *node = new AstNode(AST_ARGUMENT);
astbuf2->children.push_back(node);
- node->children.push_back($1);
+ node->children.push_back($2);
+ free_attr($1);
} |
- '.' TOK_ID '(' expr ')' {
+ attr '.' TOK_ID '(' expr ')' {
AstNode *node = new AstNode(AST_ARGUMENT);
- node->str = *$2;
+ node->str = *$3;
astbuf2->children.push_back(node);
- node->children.push_back($4);
- delete $2;
+ node->children.push_back($5);
+ delete $3;
+ free_attr($1);
} |
- '.' TOK_ID '(' ')' {
+ attr '.' TOK_ID '(' ')' {
AstNode *node = new AstNode(AST_ARGUMENT);
- node->str = *$2;
+ node->str = *$3;
astbuf2->children.push_back(node);
- delete $2;
+ delete $3;
+ free_attr($1);
+ } |
+ attr '.' TOK_ID {
+ AstNode *node = new AstNode(AST_ARGUMENT);
+ node->str = *$3;
+ astbuf2->children.push_back(node);
+ node->children.push_back(new AstNode(AST_IDENTIFIER));
+ node->children.back()->str = *$3;
+ delete $3;
+ free_attr($1);
};
always_stmt:
@@ -1267,74 +1588,219 @@ opt_label:
$$ = NULL;
};
+opt_sva_label:
+ TOK_SVA_LABEL ':' {
+ $$ = $1;
+ } |
+ /* empty */ {
+ $$ = NULL;
+ };
+
opt_property:
- TOK_PROPERTY | /* empty */;
+ TOK_PROPERTY {
+ $$ = true;
+ } |
+ TOK_FINAL {
+ $$ = false;
+ } |
+ /* empty */ {
+ $$ = false;
+ };
-opt_stmt_label:
- TOK_ID ':' | /* empty */;
+modport_stmt:
+ TOK_MODPORT TOK_ID {
+ AstNode *modport = new AstNode(AST_MODPORT);
+ ast_stack.back()->children.push_back(modport);
+ ast_stack.push_back(modport);
+ modport->str = *$2;
+ delete $2;
+ } modport_args_opt {
+ ast_stack.pop_back();
+ log_assert(ast_stack.size() == 2);
+ } ';'
+
+modport_args_opt:
+ '(' ')' | '(' modport_args optional_comma ')';
+
+modport_args:
+ modport_arg | modport_args ',' modport_arg;
+
+modport_arg:
+ modport_type_token modport_member |
+ modport_member
+
+modport_member:
+ TOK_ID {
+ AstNode *modport_member = new AstNode(AST_MODPORTMEMBER);
+ ast_stack.back()->children.push_back(modport_member);
+ modport_member->str = *$1;
+ modport_member->is_input = current_modport_input;
+ modport_member->is_output = current_modport_output;
+ delete $1;
+ }
+
+modport_type_token:
+ TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}
assert:
- opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
+ opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' {
+ if (noassert_mode) {
+ delete $5;
+ } else {
+ AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5);
+ if ($1 != nullptr)
+ node->str = *$1;
+ ast_stack.back()->children.push_back(node);
+ }
+ if ($1 != nullptr)
+ delete $1;
} |
- opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
+ opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' {
+ if (noassume_mode) {
+ delete $5;
+ } else {
+ AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5);
+ if ($1 != nullptr)
+ node->str = *$1;
+ ast_stack.back()->children.push_back(node);
+ }
+ if ($1 != nullptr)
+ delete $1;
} |
- opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
+ opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+ if (noassert_mode) {
+ delete $6;
+ } else {
+ AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6);
+ if ($1 != nullptr)
+ node->str = *$1;
+ ast_stack.back()->children.push_back(node);
+ }
+ if ($1 != nullptr)
+ delete $1;
} |
- opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
+ opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+ if (noassume_mode) {
+ delete $6;
+ } else {
+ AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6);
+ if ($1 != nullptr)
+ node->str = *$1;
+ ast_stack.back()->children.push_back(node);
+ }
+ if ($1 != nullptr)
+ delete $1;
} |
- opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
+ opt_sva_label TOK_COVER opt_property '(' expr ')' ';' {
+ AstNode *node = new AstNode(AST_COVER, $5);
+ if ($1 != nullptr) {
+ node->str = *$1;
+ delete $1;
+ }
+ ast_stack.back()->children.push_back(node);
} |
- opt_stmt_label TOK_COVER opt_property '(' ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
+ opt_sva_label TOK_COVER opt_property '(' ')' ';' {
+ AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
+ if ($1 != nullptr) {
+ node->str = *$1;
+ delete $1;
+ }
+ ast_stack.back()->children.push_back(node);
} |
- opt_stmt_label TOK_COVER ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
+ opt_sva_label TOK_COVER ';' {
+ AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
+ if ($1 != nullptr) {
+ node->str = *$1;
+ delete $1;
+ }
+ ast_stack.back()->children.push_back(node);
} |
- opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' {
- if (norestrict_mode)
+ opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' {
+ if (norestrict_mode) {
delete $5;
- else
- ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
+ } else {
+ AstNode *node = new AstNode(AST_ASSUME, $5);
+ if ($1 != nullptr)
+ node->str = *$1;
+ ast_stack.back()->children.push_back(node);
+ }
+ if (!$3)
+ log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
+ if ($1 != nullptr)
+ delete $1;
} |
- opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
- if (norestrict_mode)
+ opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+ if (norestrict_mode) {
delete $6;
- else
- ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
+ } else {
+ AstNode *node = new AstNode(AST_FAIR, $6);
+ if ($1 != nullptr)
+ node->str = *$1;
+ ast_stack.back()->children.push_back(node);
+ }
+ if (!$3)
+ log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
+ if ($1 != nullptr)
+ delete $1;
};
assert_property:
- TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4));
- } |
- TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
+ opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
} |
- TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5));
+ opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
} |
- TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
+ opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
} |
- TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4));
+ opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
} |
- TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
- if (norestrict_mode)
- delete $4;
- else
- ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
+ opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
} |
- TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
- if (norestrict_mode)
+ opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
+ if (norestrict_mode) {
delete $5;
- else
- ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
+ } else {
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
+ }
+ } |
+ opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
+ if (norestrict_mode) {
+ delete $6;
+ } else {
+ ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
+ }
};
simple_behavioral_stmt:
@@ -1370,6 +1836,16 @@ behavioral_stmt:
} opt_arg_list ';'{
ast_stack.pop_back();
} |
+ TOK_MSG_TASKS attr {
+ AstNode *node = new AstNode(AST_TCALL);
+ node->str = *$1;
+ delete $1;
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ append_attr(node, $2);
+ } opt_arg_list ';'{
+ ast_stack.pop_back();
+ } |
attr TOK_BEGIN opt_label {
AstNode *node = new AstNode(AST_BLOCK);
ast_stack.back()->children.push_back(node);
@@ -1379,7 +1855,7 @@ behavioral_stmt:
node->str = *$3;
} behavioral_stmt_list TOK_END opt_label {
if ($3 != NULL && $7 != NULL && *$3 != *$7)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1);
if ($3 != NULL)
delete $3;
if ($7 != NULL)
@@ -1552,6 +2028,11 @@ case_expr_list:
TOK_DEFAULT {
ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT));
} |
+ TOK_SVA_LABEL {
+ ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER));
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ } |
expr {
ast_stack.back()->children.push_back($1);
} |
@@ -1660,6 +2141,15 @@ gen_stmt:
if ($6 != NULL)
delete $6;
ast_stack.pop_back();
+ } |
+ TOK_MSG_TASKS {
+ AstNode *node = new AstNode(AST_TECALL);
+ node->str = *$1;
+ delete $1;
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ } opt_arg_list ';'{
+ ast_stack.pop_back();
};
gen_stmt_block:
@@ -1695,7 +2185,7 @@ basic_expr:
} |
'(' expr ')' TOK_CONSTVAL {
if ($4->substr(0, 1) != "'")
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. (<expr>)<constval> , while %s is not a sized constant.", $4->c_str());
AstNode *bits = $2;
AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
if (val == NULL)
@@ -1705,7 +2195,7 @@ basic_expr:
} |
hierarchical_id TOK_CONSTVAL {
if ($2->substr(0, 1) != "'")
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. <ID>\'d0, while %s is not a sized constant.", $2->c_str());
AstNode *bits = new AstNode(AST_IDENTIFIER);
bits->str = *$1;
AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
@@ -1930,4 +2420,3 @@ concat_list:
$$ = $3;
$$->children.push_back($1);
};
-
diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc
index 5fd76afe..26c625f8 100644
--- a/kernel/cellaigs.cc
+++ b/kernel/cellaigs.cc
@@ -453,7 +453,7 @@ Aig::Aig(Cell *cell)
int B = mk.inport("\\B");
int C = mk.inport("\\C");
int D = mk.inport("\\D");
- int Y = mk.nand_gate(mk.nor_gate(A, B), mk.nor_gate(C, D));
+ int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D));
mk.outport(Y, "\\Y");
goto optimize;
}
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index fcc4fcc4..4e91eddd 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -82,6 +82,32 @@ struct CellTypes
void setup_internals()
{
+ setup_internals_eval();
+
+ IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
+ IdString SRC = "\\SRC", DST = "\\DST", DAT = "\\DAT";
+ IdString EN_SRC = "\\EN_SRC", EN_DST = "\\EN_DST";
+
+ setup_type("$tribuf", {A, EN}, {Y}, true);
+
+ setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
+ setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
+ setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
+ setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
+ setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
+ setup_type("$equiv", {A, B}, {Y}, true);
+ setup_type("$specify2", {EN, SRC, DST}, pool<RTLIL::IdString>(), true);
+ setup_type("$specify3", {EN, SRC, DST, DAT}, pool<RTLIL::IdString>(), true);
+ setup_type("$specrule", {EN_SRC, EN_DST, SRC, DST}, pool<RTLIL::IdString>(), true);
+ }
+
+ void setup_internals_eval()
+ {
std::vector<RTLIL::IdString> unary_ops = {
"$not", "$pos", "$neg",
"$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
@@ -111,20 +137,6 @@ struct CellTypes
setup_type("$lcu", {P, G, CI}, {CO}, true);
setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true);
setup_type("$fa", {A, B, C}, {X, Y}, true);
-
- setup_type("$tribuf", {A, EN}, {Y}, true);
-
- setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
- setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
- setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
- setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
- setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
- setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
- setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
- setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
- setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
- setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
- setup_type("$equiv", {A, B}, {Y}, true);
}
void setup_internals_mem()
@@ -154,10 +166,19 @@ struct CellTypes
void setup_stdcells()
{
+ setup_stdcells_eval();
+
+ IdString A = "\\A", E = "\\E", Y = "\\Y";
+
+ setup_type("$_TBUF_", {A, E}, {Y}, true);
+ }
+
+ void setup_stdcells_eval()
+ {
IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D";
IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H";
IdString I = "\\I", J = "\\J", K = "\\K", L = "\\L";
- IdString M = "\\I", N = "\\N", O = "\\O", P = "\\P";
+ IdString M = "\\M", N = "\\N", O = "\\O", P = "\\P";
IdString S = "\\S", T = "\\T", U = "\\U", V = "\\V";
IdString Y = "\\Y";
@@ -179,7 +200,6 @@ struct CellTypes
setup_type("$_OAI3_", {A, B, C}, {Y}, true);
setup_type("$_AOI4_", {A, B, C, D}, {Y}, true);
setup_type("$_OAI4_", {A, B, C, D}, {Y}, true);
- setup_type("$_TBUF_", {A, E}, {Y}, true);
}
void setup_stdcells_mem()
@@ -257,7 +277,7 @@ struct CellTypes
return v;
}
- static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+ static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len, bool *errp = nullptr)
{
if (type == "$sshr" && !signed1)
type = "$shr";
@@ -329,10 +349,15 @@ struct CellTypes
if (type == "$_ORNOT_")
return const_or(arg1, eval_not(arg2), false, false, 1);
+ if (errp != nullptr) {
+ *errp = true;
+ return State::Sm;
+ }
+
log_abort();
}
- static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2)
+ static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool *errp = nullptr)
{
if (cell->type == "$slice") {
RTLIL::Const ret;
@@ -415,10 +440,10 @@ struct CellTypes
bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool();
bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool();
int result_len = cell->parameters.count("\\Y_WIDTH") > 0 ? cell->parameters["\\Y_WIDTH"].as_int() : -1;
- return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len);
+ return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len, errp);
}
- static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3)
+ static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr)
{
if (cell->type.in("$mux", "$pmux", "$_MUX_")) {
RTLIL::Const ret = arg1;
@@ -436,18 +461,18 @@ struct CellTypes
return eval_not(const_and(const_or(arg1, arg2, false, false, 1), arg3, false, false, 1));
log_assert(arg3.bits.size() == 0);
- return eval(cell, arg1, arg2);
+ return eval(cell, arg1, arg2, errp);
}
- static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4)
+ static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4, bool *errp = nullptr)
{
if (cell->type == "$_AOI4_")
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
if (cell->type == "$_OAI4_")
- return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
+ return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_or(arg3, arg4, false, false, 1), false, false, 1));
log_assert(arg4.bits.size() == 0);
- return eval(cell, arg1, arg2, arg3);
+ return eval(cell, arg1, arg2, arg3, errp);
}
};
diff --git a/kernel/consteval.h b/kernel/consteval.h
index 0229f504..154373a8 100644
--- a/kernel/consteval.h
+++ b/kernel/consteval.h
@@ -321,8 +321,13 @@ struct ConstEval
if (sig_d.size() > 0 && !eval(sig_d, undef, cell))
return false;
- set(sig_y, CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(),
- sig_c.as_const(), sig_d.as_const()));
+ bool eval_err = false;
+ RTLIL::Const eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_c.as_const(), sig_d.as_const(), &eval_err);
+
+ if (eval_err)
+ return false;
+
+ set(sig_y, eval_ret);
}
return true;
diff --git a/kernel/cost.h b/kernel/cost.h
index e795b571..41a09eb6 100644
--- a/kernel/cost.h
+++ b/kernel/cost.h
@@ -26,7 +26,7 @@ YOSYS_NAMESPACE_BEGIN
int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr);
-int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> &parameters = dict<RTLIL::IdString, RTLIL::Const>(),
+inline int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> &parameters = dict<RTLIL::IdString, RTLIL::Const>(),
RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr)
{
static dict<RTLIL::IdString, int> gate_cost = {
@@ -76,7 +76,7 @@ int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const
return 1;
}
-int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache)
+inline int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache)
{
return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache);
}
diff --git a/kernel/driver.cc b/kernel/driver.cc
index 8b328e5b..edec7760 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -110,6 +110,10 @@ int main(int argc, char **argv)
log_error_stderr = true;
yosys_banner();
yosys_setup();
+#ifdef WITH_PYTHON
+ PyRun_SimpleString(("sys.path.append(\""+proc_self_dirname()+"\")").c_str());
+ PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str());
+#endif
if (argc == 2)
{
@@ -179,6 +183,7 @@ int main(int argc, char **argv)
{
std::string frontend_command = "auto";
std::string backend_command = "auto";
+ std::vector<std::string> vlog_defines;
std::vector<std::string> passes_commands;
std::vector<std::string> plugin_filenames;
std::string output_filename = "";
@@ -268,7 +273,10 @@ int main(int argc, char **argv)
printf(" -A\n");
printf(" will call abort() at the end of the script. for debugging\n");
printf("\n");
- printf(" -D <header_id>[:<filename>]\n");
+ printf(" -D <macro>[=<value>]\n");
+ printf(" set the specified Verilog define (via \"read -define\")\n");
+ printf("\n");
+ printf(" -P <header_id>[:<filename>]\n");
printf(" dump the design when printing the specified log header to a file.\n");
printf(" yosys_dump_<header_id>.il is used as filename if none is specified.\n");
printf(" Use 'ALL' as <header_id> to dump at every header.\n");
@@ -287,6 +295,9 @@ int main(int argc, char **argv)
printf(" -E <depsfile>\n");
printf(" write a Makefile dependencies file with in- and output file names\n");
printf("\n");
+ printf(" -g\n");
+ printf(" globally enable debug log messages\n");
+ printf("\n");
printf(" -V\n");
printf(" print version information and exit\n");
printf("\n");
@@ -307,7 +318,7 @@ int main(int argc, char **argv)
}
int opt;
- while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:E:")) != -1)
+ while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1)
{
switch (opt)
{
@@ -332,6 +343,9 @@ int main(int argc, char **argv)
case 'S':
passes_commands.push_back("synth");
break;
+ case 'g':
+ log_force_debug++;
+ break;
case 'm':
plugin_filenames.push_back(optarg);
break;
@@ -408,6 +422,9 @@ int main(int argc, char **argv)
std::regex_constants::egrep));
break;
case 'D':
+ vlog_defines.push_back(optarg);
+ break;
+ case 'P':
{
auto args = split_tokens(optarg, ":");
if (!args.empty() && args[0] == "ALL") {
@@ -462,6 +479,10 @@ int main(int argc, char **argv)
#endif
yosys_setup();
+#ifdef WITH_PYTHON
+ PyRun_SimpleString(("sys.path.append(\""+proc_self_dirname()+"\")").c_str());
+ PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str());
+#endif
log_error_atexit = yosys_atexit;
for (auto &fn : plugin_filenames)
@@ -473,6 +494,13 @@ int main(int argc, char **argv)
shell(yosys_design);
}
+ if (!vlog_defines.empty()) {
+ std::string vdef_cmd = "read -define";
+ for (auto vdef : vlog_defines)
+ vdef_cmd += " " + vdef;
+ run_pass(vdef_cmd);
+ }
+
while (optind < argc)
run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL);
@@ -501,13 +529,13 @@ int main(int argc, char **argv)
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());
+ fprintf(f, "%s%s", first ? "" : " ", escape_filename_spaces(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, " %s", escape_filename_spaces(fn).c_str());
}
fprintf(f, "\n");
}
diff --git a/kernel/hashlib.h b/kernel/hashlib.h
index df534ec1..e7cb312e 100644
--- a/kernel/hashlib.h
+++ b/kernel/hashlib.h
@@ -557,9 +557,11 @@ public:
void clear() { hashtable.clear(); entries.clear(); }
iterator begin() { return iterator(this, int(entries.size())-1); }
+ iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
iterator end() { return iterator(nullptr, -1); }
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
+ const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
const_iterator end() const { return const_iterator(nullptr, -1); }
};
@@ -881,9 +883,11 @@ public:
void clear() { hashtable.clear(); entries.clear(); }
iterator begin() { return iterator(this, int(entries.size())-1); }
+ iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
iterator end() { return iterator(nullptr, -1); }
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
+ const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
const_iterator end() const { return const_iterator(nullptr, -1); }
};
@@ -952,6 +956,7 @@ public:
void clear() { database.clear(); }
const_iterator begin() const { return database.begin(); }
+ const_iterator element(int n) const { return database.element(n); }
const_iterator end() const { return database.end(); }
};
@@ -1051,6 +1056,7 @@ public:
void clear() { database.clear(); parents.clear(); }
const_iterator begin() const { return database.begin(); }
+ const_iterator element(int n) const { return database.element(n); }
const_iterator end() const { return database.end(); }
};
diff --git a/kernel/log.cc b/kernel/log.cc
index 1dfa89a4..311bc384 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -56,6 +56,10 @@ int log_verbose_level;
string log_last_error;
void (*log_error_atexit)() = NULL;
+int log_make_debug = 0;
+int log_force_debug = 0;
+int log_debug_suppressed = 0;
+
vector<int> header_count;
pool<RTLIL::IdString> log_id_cache;
vector<shared_str> string_buf;
@@ -92,6 +96,9 @@ void logv(const char *format, va_list ap)
format++;
}
+ if (log_make_debug && !ys_debug(1))
+ return;
+
std::string str = vstringf(format, ap);
if (str.empty())
@@ -196,7 +203,11 @@ void logv_header(RTLIL::Design *design, const char *format, va_list ap)
if (log_hdump.count(header_id) && design != nullptr)
for (auto &filename : log_hdump.at(header_id)) {
log("Dumping current design to '%s'.\n", filename.c_str());
+ if (yosys_xtrace)
+ IdString::xtrace_db_dump();
Pass::call(design, {"dump", "-o", filename});
+ if (yosys_xtrace)
+ log("#X# -- end of dump --\n");
}
if (pop_errfile)
@@ -219,6 +230,9 @@ static void logv_warning_with_prefix(const char *prefix,
}
else
{
+ int bak_log_make_debug = log_make_debug;
+ log_make_debug = 0;
+
for (auto &re : log_werror_regexes)
if (std::regex_search(message, re))
log_error("%s", message.c_str());
@@ -243,6 +257,7 @@ static void logv_warning_with_prefix(const char *prefix,
}
log_warnings_count++;
+ log_make_debug = bak_log_make_debug;
}
}
@@ -262,11 +277,22 @@ void log_file_warning(const std::string &filename, int lineno,
va_list ap;
va_start(ap, format);
std::string prefix = stringf("%s:%d: Warning: ",
- filename.c_str(), lineno);
+ filename.c_str(), lineno);
logv_warning_with_prefix(prefix.c_str(), format, ap);
va_end(ap);
}
+void log_file_info(const std::string &filename, int lineno,
+ const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ std::string fmt = stringf("%s:%d: Info: %s",
+ filename.c_str(), lineno, format);
+ logv(fmt.c_str(), ap);
+ va_end(ap);
+}
+
YS_ATTRIBUTE(noreturn)
static void logv_error_with_prefix(const char *prefix,
const char *format, va_list ap)
@@ -274,6 +300,9 @@ static void logv_error_with_prefix(const char *prefix,
#ifdef EMSCRIPTEN
auto backup_log_files = log_files;
#endif
+ int bak_log_make_debug = log_make_debug;
+ log_make_debug = 0;
+ log_suppressed();
if (log_errfile != NULL)
log_files.push_back(log_errfile);
@@ -287,6 +316,8 @@ static void logv_error_with_prefix(const char *prefix,
log("%s%s", prefix, log_last_error.c_str());
log_flush();
+ log_make_debug = bak_log_make_debug;
+
if (log_error_atexit)
log_error_atexit();
diff --git a/kernel/log.h b/kernel/log.h
index 0f068a16..82e27d06 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -64,6 +64,10 @@ extern int log_verbose_level;
extern string log_last_error;
extern void (*log_error_atexit)();
+extern int log_make_debug;
+extern int log_force_debug;
+extern int log_debug_suppressed;
+
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);
@@ -76,12 +80,52 @@ 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_file_info(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);
+#ifndef NDEBUG
+static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; }
+# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0)
+#else
+static inline bool ys_debug(int n = 0) { return false; }
+# define log_debug(_fmt, ...) do { } while (0)
+#endif
+
+static inline void log_suppressed() {
+ if (log_debug_suppressed && !log_make_debug) {
+ log("<suppressed ~%d debug messages>\n", log_debug_suppressed);
+ log_debug_suppressed = 0;
+ }
+}
+
+struct LogMakeDebugHdl {
+ bool status = false;
+ LogMakeDebugHdl(bool start_on = false) {
+ if (start_on)
+ on();
+ }
+ ~LogMakeDebugHdl() {
+ off();
+ }
+ void on() {
+ if (status) return;
+ status=true;
+ log_make_debug++;
+ }
+ void off_silent() {
+ if (!status) return;
+ status=false;
+ log_make_debug--;
+ }
+ void off() {
+ off_silent();
+ }
+};
+
void log_spacer();
void log_push();
void log_pop();
@@ -94,7 +138,9 @@ const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
const char *log_const(const RTLIL::Const &value, bool autoint = true);
const char *log_id(RTLIL::IdString id);
-template<typename T> static inline const char *log_id(T *obj) {
+template<typename T> static inline const char *log_id(T *obj, const char *nullstr = nullptr) {
+ if (nullstr && obj == nullptr)
+ return nullstr;
return log_id(obj->name);
}
@@ -195,7 +241,7 @@ struct PerformanceTimer
t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL;
return t;
# else
-# error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?).
+# error "Don't know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?)."
# endif
}
diff --git a/kernel/register.cc b/kernel/register.cc
index 402a5b3e..26da96b9 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -86,6 +86,9 @@ Pass::pre_post_exec_state_t Pass::pre_execute()
void Pass::post_execute(Pass::pre_post_exec_state_t state)
{
+ IdString::checkpoint();
+ log_suppressed();
+
int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
runtime_ns += time_ns;
current_pass = state.parent_pass;
@@ -542,6 +545,7 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st
}
filename = arg;
+ rewrite_filename(filename);
std::ofstream *ff = new std::ofstream;
ff->open(filename.c_str(), std::ofstream::trunc);
yosys_output_files.insert(filename);
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index a4fa2cf0..a09f4a0d 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -33,6 +33,8 @@ std::vector<int> RTLIL::IdString::global_refcount_storage_;
std::vector<char*> RTLIL::IdString::global_id_storage_;
dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
std::vector<int> RTLIL::IdString::global_free_idx_list_;
+int RTLIL::IdString::last_created_idx_[8];
+int RTLIL::IdString::last_created_idx_ptr_;
RTLIL::Const::Const()
{
@@ -74,6 +76,13 @@ RTLIL::Const::Const(const std::vector<bool> &bits)
this->bits.push_back(b ? RTLIL::S1 : RTLIL::S0);
}
+RTLIL::Const::Const(const RTLIL::Const &c)
+{
+ flags = c.flags;
+ for (auto b : c.bits)
+ this->bits.push_back(b);
+}
+
bool RTLIL::Const::operator <(const RTLIL::Const &other) const
{
if (bits.size() != other.bits.size())
@@ -205,16 +214,23 @@ bool RTLIL::Const::is_fully_undef() const
return true;
}
-void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id)
+void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
{
- attributes[id] = RTLIL::Const(1);
+ if (value)
+ attributes[id] = RTLIL::Const(1);
+ else {
+ const auto it = attributes.find(id);
+ if (it != attributes.end())
+ attributes.erase(it);
+ }
}
bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
{
- if (attributes.count(id) == 0)
+ const auto it = attributes.find(id);
+ if (it == attributes.end())
return false;
- return attributes.at(id).as_bool();
+ return it->second.as_bool();
}
void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
@@ -358,6 +374,10 @@ RTLIL::Design::Design()
refcount_modules_ = 0;
selection_stack.push_back(RTLIL::Selection());
+
+#ifdef WITH_PYTHON
+ RTLIL::Design::get_all_designs()->insert(std::pair<unsigned int, RTLIL::Design*>(hashidx_, this));
+#endif
}
RTLIL::Design::~Design()
@@ -368,8 +388,19 @@ RTLIL::Design::~Design()
delete n;
for (auto n : verilog_globals)
delete n;
+#ifdef WITH_PYTHON
+ RTLIL::Design::get_all_designs()->erase(hashidx_);
+#endif
}
+#ifdef WITH_PYTHON
+static std::map<unsigned int, RTLIL::Design*> all_designs;
+std::map<unsigned int, RTLIL::Design*> *RTLIL::Design::get_all_designs(void)
+{
+ return &all_designs;
+}
+#endif
+
RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules()
{
return RTLIL::ObjRange<RTLIL::Module*>(&modules_, &refcount_modules_);
@@ -587,7 +618,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_modules() const
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
- if (selected_module(it.first) && !it.second->get_bool_attribute("\\blackbox"))
+ if (selected_module(it.first) && !it.second->get_blackbox_attribute())
result.push_back(it.second);
return result;
}
@@ -597,7 +628,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
- if (selected_whole_module(it.first) && !it.second->get_bool_attribute("\\blackbox"))
+ if (selected_whole_module(it.first) && !it.second->get_blackbox_attribute())
result.push_back(it.second);
return result;
}
@@ -607,7 +638,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
- if (it.second->get_bool_attribute("\\blackbox"))
+ if (it.second->get_blackbox_attribute())
continue;
else if (selected_whole_module(it.first))
result.push_back(it.second);
@@ -625,6 +656,10 @@ RTLIL::Module::Module()
design = nullptr;
refcount_wires_ = 0;
refcount_cells_ = 0;
+
+#ifdef WITH_PYTHON
+ RTLIL::Module::get_all_modules()->insert(std::pair<unsigned int, RTLIL::Module*>(hashidx_, this));
+#endif
}
RTLIL::Module::~Module()
@@ -637,6 +672,46 @@ RTLIL::Module::~Module()
delete it->second;
for (auto it = processes.begin(); it != processes.end(); ++it)
delete it->second;
+#ifdef WITH_PYTHON
+ RTLIL::Module::get_all_modules()->erase(hashidx_);
+#endif
+}
+
+#ifdef WITH_PYTHON
+static std::map<unsigned int, RTLIL::Module*> all_modules;
+std::map<unsigned int, RTLIL::Module*> *RTLIL::Module::get_all_modules(void)
+{
+ return &all_modules;
+}
+#endif
+
+void RTLIL::Module::makeblackbox()
+{
+ pool<RTLIL::Wire*> delwires;
+
+ for (auto it = wires_.begin(); it != wires_.end(); ++it)
+ if (!it->second->port_input && !it->second->port_output)
+ delwires.insert(it->second);
+
+ for (auto it = memories.begin(); it != memories.end(); ++it)
+ delete it->second;
+ memories.clear();
+
+ for (auto it = cells_.begin(); it != cells_.end(); ++it)
+ delete it->second;
+ cells_.clear();
+
+ for (auto it = processes.begin(); it != processes.end(); ++it)
+ delete it->second;
+ processes.clear();
+
+ remove(delwires);
+ set_bool_attribute("\\blackbox");
+}
+
+void RTLIL::Module::reprocess_module(RTLIL::Design *, dict<RTLIL::IdString, RTLIL::Module *>)
+{
+ log_error("Cannot reprocess_module module `%s' !\n", id2cstr(name));
}
RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, bool mayfail)
@@ -646,6 +721,14 @@ RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLI
log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
}
+
+RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, dict<RTLIL::IdString, RTLIL::Module*>, dict<RTLIL::IdString, RTLIL::IdString>, bool mayfail)
+{
+ if (mayfail)
+ return RTLIL::IdString();
+ log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
+}
+
size_t RTLIL::Module::count_id(RTLIL::IdString id)
{
return wires_.count(id) + memories.count(id) + cells_.count(id) + processes.count(id);
@@ -745,7 +828,7 @@ namespace {
void check()
{
- if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" ||
+ if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" || cell->type.substr(0,10) == "$fmcombine" ||
cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:")
return;
@@ -1115,6 +1198,46 @@ namespace {
return;
}
+ if (cell->type.in("$specify2", "$specify3")) {
+ param_bool("\\FULL");
+ param_bool("\\SRC_DST_PEN");
+ param_bool("\\SRC_DST_POL");
+ param("\\T_RISE_MIN");
+ param("\\T_RISE_TYP");
+ param("\\T_RISE_MAX");
+ param("\\T_FALL_MIN");
+ param("\\T_FALL_TYP");
+ param("\\T_FALL_MAX");
+ port("\\EN", 1);
+ port("\\SRC", param("\\SRC_WIDTH"));
+ port("\\DST", param("\\DST_WIDTH"));
+ if (cell->type == "$specify3") {
+ param_bool("\\EDGE_EN");
+ param_bool("\\EDGE_POL");
+ param_bool("\\DAT_DST_PEN");
+ param_bool("\\DAT_DST_POL");
+ port("\\DAT", param("\\DST_WIDTH"));
+ }
+ check_expected();
+ return;
+ }
+
+ if (cell->type == "$specrule") {
+ param("\\TYPE");
+ param_bool("\\SRC_PEN");
+ param_bool("\\SRC_POL");
+ param_bool("\\DST_PEN");
+ param_bool("\\DST_POL");
+ param("\\T_LIMIT");
+ param("\\T_LIMIT2");
+ port("\\SRC_EN", 1);
+ port("\\DST_EN", 1);
+ port("\\SRC", param("\\SRC_WIDTH"));
+ port("\\DST", param("\\DST_WIDTH"));
+ check_expected();
+ return;
+ }
+
if (cell->type == "$_BUF_") { check_gate("AY"); return; }
if (cell->type == "$_NOT_") { check_gate("AY"); return; }
if (cell->type == "$_AND_") { check_gate("ABY"); return; }
@@ -1258,7 +1381,34 @@ void RTLIL::Module::check()
for (auto &it : processes) {
log_assert(it.first == it.second->name);
log_assert(!it.first.empty());
- // FIXME: More checks here..
+ log_assert(it.second->root_case.compare.empty());
+ std::vector<CaseRule*> all_cases = {&it.second->root_case};
+ for (size_t i = 0; i < all_cases.size(); i++) {
+ for (auto &switch_it : all_cases[i]->switches) {
+ for (auto &case_it : switch_it->cases) {
+ for (auto &compare_it : case_it->compare) {
+ log_assert(switch_it->signal.size() == compare_it.size());
+ }
+ all_cases.push_back(case_it);
+ }
+ }
+ }
+ for (auto &sync_it : it.second->syncs) {
+ switch (sync_it->type) {
+ case SyncType::ST0:
+ case SyncType::ST1:
+ case SyncType::STp:
+ case SyncType::STn:
+ case SyncType::STe:
+ log_assert(!sync_it->signal.empty());
+ break;
+ case SyncType::STa:
+ case SyncType::STg:
+ case SyncType::STi:
+ log_assert(sync_it->signal.empty());
+ break;
+ }
+ }
}
for (auto &it : connections_) {
@@ -1391,7 +1541,10 @@ void RTLIL::Module::add(RTLIL::Cell *cell)
cell->module = this;
}
-namespace {
+void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
+{
+ log_assert(refcount_wires_ == 0);
+
struct DeleteWireWorker
{
RTLIL::Module *module;
@@ -1406,17 +1559,29 @@ namespace {
}
sig = chunks;
}
- };
-}
-void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
-{
- log_assert(refcount_wires_ == 0);
+ void operator()(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) {
+ log_assert(GetSize(lhs) == GetSize(rhs));
+ RTLIL::SigSpec new_lhs, new_rhs;
+ for (int i = 0; i < GetSize(lhs); i++) {
+ RTLIL::SigBit lhs_bit = lhs[i];
+ if (lhs_bit.wire != nullptr && wires_p->count(lhs_bit.wire))
+ continue;
+ RTLIL::SigBit rhs_bit = rhs[i];
+ if (rhs_bit.wire != nullptr && wires_p->count(rhs_bit.wire))
+ continue;
+ new_lhs.append(lhs_bit);
+ new_rhs.append(rhs_bit);
+ }
+ lhs = new_lhs;
+ rhs = new_rhs;
+ }
+ };
DeleteWireWorker delete_wire_worker;
delete_wire_worker.module = this;
delete_wire_worker.wires_p = &wires;
- rewrite_sigspecs(delete_wire_worker);
+ rewrite_sigspecs2(delete_wire_worker);
for (auto &it : wires) {
log_assert(wires_.count(it->name) != 0);
@@ -2187,8 +2352,27 @@ RTLIL::Wire::Wire()
port_input = false;
port_output = false;
upto = false;
+
+#ifdef WITH_PYTHON
+ RTLIL::Wire::get_all_wires()->insert(std::pair<unsigned int, RTLIL::Wire*>(hashidx_, this));
+#endif
+}
+
+RTLIL::Wire::~Wire()
+{
+#ifdef WITH_PYTHON
+ RTLIL::Wire::get_all_wires()->erase(hashidx_);
+#endif
}
+#ifdef WITH_PYTHON
+static std::map<unsigned int, RTLIL::Wire*> all_wires;
+std::map<unsigned int, RTLIL::Wire*> *RTLIL::Wire::get_all_wires(void)
+{
+ return &all_wires;
+}
+#endif
+
RTLIL::Memory::Memory()
{
static unsigned int hashidx_count = 123456789;
@@ -2198,6 +2382,9 @@ RTLIL::Memory::Memory()
width = 1;
start_offset = 0;
size = 0;
+#ifdef WITH_PYTHON
+ RTLIL::Memory::get_all_memorys()->insert(std::pair<unsigned int, RTLIL::Memory*>(hashidx_, this));
+#endif
}
RTLIL::Cell::Cell() : module(nullptr)
@@ -2208,7 +2395,26 @@ RTLIL::Cell::Cell() : module(nullptr)
// log("#memtrace# %p\n", this);
memhasher();
+
+#ifdef WITH_PYTHON
+ RTLIL::Cell::get_all_cells()->insert(std::pair<unsigned int, RTLIL::Cell*>(hashidx_, this));
+#endif
+}
+
+RTLIL::Cell::~Cell()
+{
+#ifdef WITH_PYTHON
+ RTLIL::Cell::get_all_cells()->erase(hashidx_);
+#endif
+}
+
+#ifdef WITH_PYTHON
+static std::map<unsigned int, RTLIL::Cell*> all_cells;
+std::map<unsigned int, RTLIL::Cell*> *RTLIL::Cell::get_all_cells(void)
+{
+ return &all_cells;
}
+#endif
bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const
{
@@ -2345,7 +2551,7 @@ void RTLIL::Cell::check()
void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
{
- if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" ||
+ if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" || type.substr(0,10) == "$fmcombine" ||
type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:")
return;
@@ -2397,6 +2603,9 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
if (connections_.count("\\Y"))
parameters["\\Y_WIDTH"] = GetSize(connections_["\\Y"]);
+ if (connections_.count("\\Q"))
+ parameters["\\WIDTH"] = GetSize(connections_["\\Q"]);
+
check();
}
@@ -2466,6 +2675,14 @@ RTLIL::SigChunk::SigChunk(RTLIL::SigBit bit)
width = 1;
}
+RTLIL::SigChunk::SigChunk(const RTLIL::SigChunk &sigchunk) : data(sigchunk.data)
+{
+ wire = sigchunk.wire;
+ data = sigchunk.data;
+ width = sigchunk.width;
+ offset = sigchunk.offset;
+}
+
RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const
{
RTLIL::SigChunk ret;
@@ -3219,7 +3436,7 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed)
remove(width, width_ - width);
if (width_ < width) {
- RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::S0;
+ RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::Sx;
if (!is_signed)
padding = RTLIL::State::S0;
while (width_ < width)
@@ -3325,7 +3542,7 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const
pack();
other.pack();
- if (chunks_.size() != chunks_.size())
+ if (chunks_.size() != other.chunks_.size())
return false;
updhash();
@@ -3780,6 +3997,11 @@ RTLIL::CaseRule::~CaseRule()
delete *it;
}
+bool RTLIL::CaseRule::empty() const
+{
+ return actions.empty() && switches.empty();
+}
+
RTLIL::CaseRule *RTLIL::CaseRule::clone() const
{
RTLIL::CaseRule *new_caserule = new RTLIL::CaseRule;
@@ -3796,6 +4018,11 @@ RTLIL::SwitchRule::~SwitchRule()
delete *it;
}
+bool RTLIL::SwitchRule::empty() const
+{
+ return cases.empty();
+}
+
RTLIL::SwitchRule *RTLIL::SwitchRule::clone() const
{
RTLIL::SwitchRule *new_switchrule = new RTLIL::SwitchRule;
@@ -3840,5 +4067,15 @@ RTLIL::Process *RTLIL::Process::clone() const
return new_proc;
}
+#ifdef WITH_PYTHON
+RTLIL::Memory::~Memory()
+{
+ RTLIL::Memory::get_all_memorys()->erase(hashidx_);
+}
+static std::map<unsigned int, RTLIL::Memory*> all_memorys;
+std::map<unsigned int, RTLIL::Memory*> *RTLIL::Memory::get_all_memorys(void)
+{
+ return &all_memorys;
+}
+#endif
YOSYS_NAMESPACE_END
-
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 027faf41..7b7367fb 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -50,7 +50,7 @@ namespace RTLIL
CONST_FLAG_NONE = 0,
CONST_FLAG_STRING = 1,
CONST_FLAG_SIGNED = 2, // only used for parameters
- CONST_FLAG_REAL = 4 // unused -- to be used for parameters
+ CONST_FLAG_REAL = 4 // only used for parameters
};
struct Const;
@@ -76,6 +76,9 @@ namespace RTLIL
struct IdString
{
+ #undef YOSYS_XTRACE_GET_PUT
+ #undef YOSYS_SORT_ID_FREE_LIST
+
// the global id string cache
static struct destruct_guard_t {
@@ -89,9 +92,43 @@ namespace RTLIL
static dict<char*, int, hash_cstr_ops> global_id_index_;
static std::vector<int> global_free_idx_list_;
+ static int last_created_idx_ptr_;
+ static int last_created_idx_[8];
+
+ static inline void xtrace_db_dump()
+ {
+ #ifdef YOSYS_XTRACE_GET_PUT
+ for (int idx = 0; idx < GetSize(global_id_storage_); idx++)
+ {
+ if (global_id_storage_.at(idx) == nullptr)
+ log("#X# DB-DUMP index %d: FREE\n", idx);
+ else
+ log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));
+ }
+ #endif
+ }
+
+ static inline void checkpoint()
+ {
+ last_created_idx_ptr_ = 0;
+ for (int i = 0; i < 8; i++) {
+ if (last_created_idx_[i])
+ put_reference(last_created_idx_[i]);
+ last_created_idx_[i] = 0;
+ }
+ #ifdef YOSYS_SORT_ID_FREE_LIST
+ std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());
+ #endif
+ }
+
static inline int get_reference(int idx)
{
global_refcount_storage_.at(idx)++;
+ #ifdef YOSYS_XTRACE_GET_PUT
+ if (yosys_xtrace) {
+ log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
+ }
+ #endif
return idx;
}
@@ -107,6 +144,11 @@ namespace RTLIL
auto it = global_id_index_.find((char*)p);
if (it != global_id_index_.end()) {
global_refcount_storage_.at(it->second)++;
+ #ifdef YOSYS_XTRACE_GET_PUT
+ if (yosys_xtrace) {
+ log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second));
+ }
+ #endif
return it->second;
}
@@ -124,16 +166,22 @@ namespace RTLIL
global_refcount_storage_.at(idx)++;
// Avoid Create->Delete->Create pattern
- static IdString last_created_id;
- put_reference(last_created_id.index_);
- last_created_id.index_ = idx;
- get_reference(last_created_id.index_);
+ if (last_created_idx_[last_created_idx_ptr_])
+ put_reference(last_created_idx_[last_created_idx_ptr_]);
+ last_created_idx_[last_created_idx_ptr_] = idx;
+ get_reference(last_created_idx_[last_created_idx_ptr_]);
+ last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7;
if (yosys_xtrace) {
log("#X# New IdString '%s' with index %d.\n", p, idx);
log_backtrace("-X- ", yosys_xtrace-1);
}
+ #ifdef YOSYS_XTRACE_GET_PUT
+ if (yosys_xtrace) {
+ log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
+ }
+ #endif
return idx;
}
@@ -144,6 +192,12 @@ namespace RTLIL
if (!destruct_guard.ok)
return;
+ #ifdef YOSYS_XTRACE_GET_PUT
+ if (yosys_xtrace) {
+ log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
+ }
+ #endif
+
log_assert(global_refcount_storage_.at(idx) > 0);
if (--global_refcount_storage_.at(idx) != 0)
@@ -463,6 +517,8 @@ struct RTLIL::Const
Const(RTLIL::State bit, int width = 1);
Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; }
Const(const std::vector<bool> &bits);
+ Const(const RTLIL::Const &c);
+ RTLIL::Const &operator =(const RTLIL::Const &other) = default;
bool operator <(const RTLIL::Const &other) const;
bool operator ==(const RTLIL::Const &other) const;
@@ -492,6 +548,14 @@ struct RTLIL::Const
return ret;
}
+ void extu(int width) {
+ bits.resize(width, RTLIL::State::S0);
+ }
+
+ void exts(int width) {
+ bits.resize(width, bits.empty() ? RTLIL::State::Sx : bits.back());
+ }
+
inline unsigned int hash() const {
unsigned int h = mkhash_init;
for (auto b : bits)
@@ -504,9 +568,13 @@ struct RTLIL::AttrObject
{
dict<RTLIL::IdString, RTLIL::Const> attributes;
- void set_bool_attribute(RTLIL::IdString id);
+ void set_bool_attribute(RTLIL::IdString id, bool value=true);
bool get_bool_attribute(RTLIL::IdString id) const;
+ bool get_blackbox_attribute(bool ignore_wb=false) const {
+ return get_bool_attribute("\\blackbox") || (!ignore_wb && get_bool_attribute("\\whitebox"));
+ }
+
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;
@@ -529,8 +597,11 @@ struct RTLIL::SigChunk
SigChunk(int val, int width = 32);
SigChunk(RTLIL::State bit, int width = 1);
SigChunk(RTLIL::SigBit bit);
+ SigChunk(const RTLIL::SigChunk &sigchunk);
+ RTLIL::SigChunk &operator =(const RTLIL::SigChunk &other) = default;
RTLIL::SigChunk extract(int offset, int length) const;
+ inline int size() const { return width; }
bool operator <(const RTLIL::SigChunk &other) const;
bool operator ==(const RTLIL::SigChunk &other) const;
@@ -553,6 +624,8 @@ struct RTLIL::SigBit
SigBit(const RTLIL::SigChunk &chunk);
SigBit(const RTLIL::SigChunk &chunk, int index);
SigBit(const RTLIL::SigSpec &sig);
+ SigBit(const RTLIL::SigBit &sigbit);
+ RTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default;
bool operator <(const RTLIL::SigBit &other) const;
bool operator ==(const RTLIL::SigBit &other) const;
@@ -874,9 +947,13 @@ struct RTLIL::Design
}
}
+
std::vector<RTLIL::Module*> selected_modules() const;
std::vector<RTLIL::Module*> selected_whole_modules() const;
std::vector<RTLIL::Module*> selected_whole_modules_warn() const;
+#ifdef WITH_PYTHON
+ static std::map<unsigned int, RTLIL::Design*> *get_all_designs(void);
+#endif
};
struct RTLIL::Module : public RTLIL::AttrObject
@@ -907,11 +984,14 @@ public:
Module();
virtual ~Module();
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail = false);
+ virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail = false);
virtual size_t count_id(RTLIL::IdString id);
+ virtual void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces);
virtual void sort();
virtual void check();
virtual void optimize();
+ virtual void makeblackbox();
void connect(const RTLIL::SigSig &conn);
void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs);
@@ -922,6 +1002,7 @@ public:
void fixup_ports();
template<typename T> void rewrite_sigspecs(T &functor);
+ template<typename T> void rewrite_sigspecs2(T &functor);
void cloneInto(RTLIL::Module *new_mod) const;
virtual RTLIL::Module *clone() const;
@@ -1130,6 +1211,10 @@ public:
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 = "");
+
+#ifdef WITH_PYTHON
+ static std::map<unsigned int, RTLIL::Module*> *get_all_modules(void);
+#endif
};
struct RTLIL::Wire : public RTLIL::AttrObject
@@ -1141,7 +1226,7 @@ protected:
// use module->addWire() and module->remove() to create or destroy wires
friend struct RTLIL::Module;
Wire();
- ~Wire() { };
+ ~Wire();
public:
// do not simply copy wires
@@ -1152,6 +1237,10 @@ public:
RTLIL::IdString name;
int width, start_offset, port_id;
bool port_input, port_output, upto;
+
+#ifdef WITH_PYTHON
+ static std::map<unsigned int, RTLIL::Wire*> *get_all_wires(void);
+#endif
};
struct RTLIL::Memory : public RTLIL::AttrObject
@@ -1163,6 +1252,10 @@ struct RTLIL::Memory : public RTLIL::AttrObject
RTLIL::IdString name;
int width, start_offset, size;
+#ifdef WITH_PYTHON
+ ~Memory();
+ static std::map<unsigned int, RTLIL::Memory*> *get_all_memorys(void);
+#endif
};
struct RTLIL::Cell : public RTLIL::AttrObject
@@ -1174,6 +1267,7 @@ protected:
// use module->addCell() and module->remove() to create or destroy cells
friend struct RTLIL::Module;
Cell();
+ ~Cell();
public:
// do not simply copy cells
@@ -1214,9 +1308,14 @@ public:
}
template<typename T> void rewrite_sigspecs(T &functor);
+ template<typename T> void rewrite_sigspecs2(T &functor);
+
+#ifdef WITH_PYTHON
+ static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void);
+#endif
};
-struct RTLIL::CaseRule
+struct RTLIL::CaseRule : public RTLIL::AttrObject
{
std::vector<RTLIL::SigSpec> compare;
std::vector<RTLIL::SigSig> actions;
@@ -1225,7 +1324,10 @@ struct RTLIL::CaseRule
~CaseRule();
void optimize();
+ bool empty() const;
+
template<typename T> void rewrite_sigspecs(T &functor);
+ template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::CaseRule *clone() const;
};
@@ -1236,7 +1338,10 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject
~SwitchRule();
+ bool empty() const;
+
template<typename T> void rewrite_sigspecs(T &functor);
+ template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::SwitchRule *clone() const;
};
@@ -1247,6 +1352,7 @@ struct RTLIL::SyncRule
std::vector<RTLIL::SigSig> actions;
template<typename T> void rewrite_sigspecs(T &functor);
+ template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::SyncRule *clone() const;
};
@@ -1259,6 +1365,7 @@ struct RTLIL::Process : public RTLIL::AttrObject
~Process();
template<typename T> void rewrite_sigspecs(T &functor);
+ template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::Process *clone() const;
};
@@ -1270,13 +1377,14 @@ inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_as
inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); }
inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; }
inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; }
+inline RTLIL::SigBit::SigBit(const RTLIL::SigBit &sigbit) : wire(sigbit.wire), data(sigbit.data){if(wire) offset = sigbit.offset;}
inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {
if (wire == other.wire)
return wire ? (offset < other.offset) : (data < other.data);
if (wire != nullptr && other.wire != nullptr)
return wire->name < other.wire->name;
- return wire < other.wire;
+ return (wire != nullptr) < (other.wire != nullptr);
}
inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {
@@ -1320,12 +1428,30 @@ void RTLIL::Module::rewrite_sigspecs(T &functor)
}
template<typename T>
+void RTLIL::Module::rewrite_sigspecs2(T &functor)
+{
+ for (auto &it : cells_)
+ it.second->rewrite_sigspecs2(functor);
+ for (auto &it : processes)
+ it.second->rewrite_sigspecs2(functor);
+ for (auto &it : connections_) {
+ functor(it.first, it.second);
+ }
+}
+
+template<typename T>
void RTLIL::Cell::rewrite_sigspecs(T &functor) {
for (auto &it : connections_)
functor(it.second);
}
template<typename T>
+void RTLIL::Cell::rewrite_sigspecs2(T &functor) {
+ for (auto &it : connections_)
+ functor(it.second);
+}
+
+template<typename T>
void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
for (auto &it : compare)
functor(it);
@@ -1338,6 +1464,17 @@ void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
}
template<typename T>
+void RTLIL::CaseRule::rewrite_sigspecs2(T &functor) {
+ for (auto &it : compare)
+ functor(it);
+ for (auto &it : actions) {
+ functor(it.first, it.second);
+ }
+ for (auto it : switches)
+ it->rewrite_sigspecs2(functor);
+}
+
+template<typename T>
void RTLIL::SwitchRule::rewrite_sigspecs(T &functor)
{
functor(signal);
@@ -1346,6 +1483,14 @@ void RTLIL::SwitchRule::rewrite_sigspecs(T &functor)
}
template<typename T>
+void RTLIL::SwitchRule::rewrite_sigspecs2(T &functor)
+{
+ functor(signal);
+ for (auto it : cases)
+ it->rewrite_sigspecs2(functor);
+}
+
+template<typename T>
void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
{
functor(signal);
@@ -1356,6 +1501,15 @@ void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
}
template<typename T>
+void RTLIL::SyncRule::rewrite_sigspecs2(T &functor)
+{
+ functor(signal);
+ for (auto &it : actions) {
+ functor(it.first, it.second);
+ }
+}
+
+template<typename T>
void RTLIL::Process::rewrite_sigspecs(T &functor)
{
root_case.rewrite_sigspecs(functor);
@@ -1363,6 +1517,14 @@ void RTLIL::Process::rewrite_sigspecs(T &functor)
it->rewrite_sigspecs(functor);
}
+template<typename T>
+void RTLIL::Process::rewrite_sigspecs2(T &functor)
+{
+ root_case.rewrite_sigspecs2(functor);
+ for (auto it : syncs)
+ it->rewrite_sigspecs2(functor);
+}
+
YOSYS_NAMESPACE_END
#endif
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 822cab93..791d40ec 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -33,7 +33,7 @@
# include <dlfcn.h>
#endif
-#ifdef _WIN32
+#if defined(_WIN32)
# include <windows.h>
# include <io.h>
#elif defined(__APPLE__)
@@ -41,13 +41,15 @@
# include <unistd.h>
# include <dirent.h>
# include <sys/stat.h>
-# include <glob.h>
#else
# include <unistd.h>
# include <dirent.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <sys/stat.h>
+#endif
+
+#if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB)
# include <glob.h>
#endif
@@ -55,6 +57,16 @@
# include <sys/sysctl.h>
#endif
+#ifdef WITH_PYTHON
+#if PY_MAJOR_VERSION >= 3
+# define INIT_MODULE PyInit_libyosys
+ extern "C" PyObject* INIT_MODULE();
+#else
+# define INIT_MODULE initlibyosys
+ extern "C" void INIT_MODULE();
+#endif
+#endif
+
#include <limits.h>
#include <errno.h>
@@ -117,7 +129,7 @@ void yosys_banner()
log(" | |\n");
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
log(" | |\n");
- log(" | Copyright (C) 2012 - 2018 Clifford Wolf <clifford@clifford.at> |\n");
+ log(" | Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at> |\n");
log(" | |\n");
log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
log(" | purpose with or without fee is hereby granted, provided that the above |\n");
@@ -139,14 +151,16 @@ void yosys_banner()
int ceil_log2(int x)
{
+#if defined(__GNUC__)
+ return x > 1 ? (8*sizeof(int)) - __builtin_clz(x-1) : 0;
+#else
if (x <= 0)
return 0;
-
for (int i = 0; i < 32; i++)
if (((x-1) >> i) == 0)
return i;
-
log_abort();
+#endif
}
std::string stringf(const char *fmt, ...)
@@ -166,7 +180,7 @@ std::string vstringf(const char *fmt, va_list ap)
std::string string;
char *str = NULL;
-#if defined(_WIN32 )|| defined(__CYGWIN__)
+#if defined(_WIN32 )|| defined(__CYGWIN__)
int sz = 64, rc;
while (1) {
va_list apc;
@@ -216,12 +230,18 @@ std::string next_token(std::string &text, const char *sep, bool long_strings)
if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') {
string sep_string = sep;
- for (size_t i = pos_begin+1; i < text.size(); i++)
+ for (size_t i = pos_begin+1; i < text.size(); i++) {
if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) {
std::string token = text.substr(pos_begin, i-pos_begin+1);
text = text.substr(i+1);
return token;
}
+ if (i+1 < text.size() && text[i] == '"' && text[i+1] == ';' && (i+2 == text.size() || sep_string.find(text[i+2]) != std::string::npos)) {
+ std::string token = text.substr(pos_begin, i-pos_begin+1);
+ text = text.substr(i+2);
+ return token + ";";
+ }
+ }
}
size_t pos_end = text.find_first_of(sep, pos_begin);
@@ -464,26 +484,61 @@ void remove_directory(std::string dirname)
#endif
}
+std::string escape_filename_spaces(const std::string& filename)
+{
+ std::string out;
+ out.reserve(filename.size());
+ for (auto c : filename)
+ {
+ if (c == ' ')
+ out += "\\ ";
+ else
+ out.push_back(c);
+ }
+ return out;
+}
+
int GetSize(RTLIL::Wire *wire)
{
return wire->width;
}
+bool already_setup = false;
+
void yosys_setup()
{
+ if(already_setup)
+ return;
+ already_setup = true;
// if there are already IdString objects then we have a global initialization order bug
IdString empty_id;
log_assert(empty_id.index_ == 0);
IdString::get_reference(empty_id.index_);
+ #ifdef WITH_PYTHON
+ PyImport_AppendInittab((char*)"libyosys", INIT_MODULE);
+ Py_Initialize();
+ PyRun_SimpleString("import sys");
+ #endif
+
Pass::init_register();
yosys_design = new RTLIL::Design;
yosys_celltypes.setup();
log_push();
}
+bool yosys_already_setup()
+{
+ return already_setup;
+}
+
+bool already_shutdown = false;
+
void yosys_shutdown()
{
+ if(already_shutdown)
+ return;
+ already_shutdown = true;
log_pop();
delete yosys_design;
@@ -511,9 +566,16 @@ void yosys_shutdown()
dlclose(it.second);
loaded_plugins.clear();
+#ifdef WITH_PYTHON
+ loaded_python_plugins.clear();
+#endif
loaded_plugin_aliases.clear();
#endif
+#ifdef WITH_PYTHON
+ Py_Finalize();
+#endif
+
IdString empty_id;
IdString::put_reference(empty_id.index_);
}
@@ -564,7 +626,7 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern)
{
std::vector<std::string> results;
-#ifdef _WIN32
+#if defined(_WIN32) || !defined(YOSYS_ENABLE_GLOB)
results.push_back(filename_pattern);
#else
glob_t globbuf;
@@ -589,6 +651,10 @@ void rewrite_filename(std::string &filename)
filename = filename.substr(1, GetSize(filename)-2);
if (filename.substr(0, 2) == "+/")
filename = proc_share_dirname() + filename.substr(2);
+#ifndef _WIN32
+ if (filename.substr(0, 2) == "~/")
+ filename = filename.replace(0, 1, getenv("HOME"));
+#endif
}
#ifdef YOSYS_ENABLE_TCL
@@ -637,8 +703,9 @@ extern Tcl_Interp *yosys_get_tcl_interp()
struct TclPass : public Pass {
TclPass() : Pass("tcl", "execute a TCL script file") { }
void help() YS_OVERRIDE {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" tcl <filename>\n");
+ log(" tcl <filename> [args]\n");
log("\n");
log("This command executes the tcl commands in the specified file.\n");
log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n");
@@ -648,14 +715,24 @@ struct TclPass : public Pass {
log("'proc' and 'rename' are wrapped to tcl commands 'procs' and 'renames'\n");
log("in order to avoid a name collision with the built in commands.\n");
log("\n");
+ log("If any arguments are specified, these arguments are provided to the script via\n");
+ log("the standard $argc and $argv variables.\n");
+ log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
+ void execute(std::vector<std::string> args, RTLIL::Design *) YS_OVERRIDE {
if (args.size() < 2)
log_cmd_error("Missing script file.\n");
- if (args.size() > 2)
- extra_args(args, 1, design, false);
- if (Tcl_EvalFile(yosys_get_tcl_interp(), args[1].c_str()) != TCL_OK)
- log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp()));
+
+ std::vector<Tcl_Obj*> script_args;
+ for (auto it = args.begin() + 2; it != args.end(); ++it)
+ script_args.push_back(Tcl_NewStringObj((*it).c_str(), (*it).size()));
+
+ Tcl_Interp *interp = yosys_get_tcl_interp();
+ Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argc", 4), NULL, Tcl_NewIntObj(script_args.size()), 0);
+ Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv", 4), NULL, Tcl_NewListObj(script_args.size(), script_args.data()), 0);
+ Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv0", 5), NULL, Tcl_NewStringObj(args[1].c_str(), args[1].size()), 0);
+ if (Tcl_EvalFile(interp, args[1].c_str()) != TCL_OK)
+ log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(interp));
}
} TclPass;
#endif
@@ -733,7 +810,7 @@ std::string proc_self_dirname()
return "/";
}
#else
- #error Dont know how to determine process executable base path!
+ #error "Don't know how to determine process executable base path!"
#endif
#ifdef EMSCRIPTEN
@@ -799,7 +876,7 @@ static void handle_label(std::string &command, bool &from_to_active, const std::
while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
label += command[pos++];
- if (label.back() == ':' && GetSize(label) > 1)
+ if (GetSize(label) > 1 && label.back() == ':')
{
label = label.substr(0, GetSize(label)-1);
command = command.substr(pos);
@@ -821,7 +898,7 @@ void run_frontend(std::string filename, std::string command, std::string *backen
command = "verilog";
else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv")
command = "verilog -sv";
- else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".vhd")
+ else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".vhd")
command = "vhdl";
else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif")
command = "blif";
@@ -833,7 +910,7 @@ void run_frontend(std::string filename, std::string command, std::string *backen
command = "ilang";
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
command = "script";
- else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".tcl")
+ else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".tcl")
command = "tcl";
else if (filename == "-")
command = "script";
diff --git a/kernel/yosys.h b/kernel/yosys.h
index c9f97331..730efe82 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -66,6 +66,10 @@
#include <stdio.h>
#include <limits.h>
+#ifdef WITH_PYTHON
+#include <Python.h>
+#endif
+
#ifndef _YOSYS_
# error It looks like you are trying to build Yosys without the config defines set. \
When building Yosys with a custom make system, make sure you set all the \
@@ -83,6 +87,10 @@ extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName);
extern void Tcl_Finalize(void);
extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr);
extern const char *Tcl_GetStringResult(Tcl_Interp *interp);
+extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length);
+extern Tcl_Obj *Tcl_NewIntObj(int intValue);
+extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]);
+extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags);
# endif
#endif
@@ -115,6 +123,7 @@ extern const char *Tcl_GetStringResult(Tcl_Interp *interp);
# define PATH_MAX 4096
#endif
+#define YOSYS_NAMESPACE Yosys
#define PRIVATE_NAMESPACE_BEGIN namespace {
#define PRIVATE_NAMESPACE_END }
#define YOSYS_NAMESPACE_BEGIN namespace Yosys {
@@ -239,7 +248,7 @@ extern bool memhasher_active;
inline void memhasher() { if (memhasher_active) memhasher_do(); }
void yosys_banner();
-int ceil_log2(int x);
+int ceil_log2(int x) YS_ATTRIBUTE(const);
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
std::string vstringf(const char *fmt, va_list ap);
int readsome(std::istream &f, char *s, int n);
@@ -252,6 +261,7 @@ std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX");
bool check_file_exists(std::string filename, bool is_exec = false);
bool is_absolute_path(std::string filename);
void remove_directory(std::string dirname);
+std::string escape_filename_spaces(const std::string& filename);
template<typename T> int GetSize(const T &obj) { return obj.size(); }
int GetSize(RTLIL::Wire *wire);
@@ -276,6 +286,11 @@ namespace hashlib {
}
void yosys_setup();
+
+#ifdef WITH_PYTHON
+bool yosys_already_setup();
+#endif
+
void yosys_shutdown();
#ifdef YOSYS_ENABLE_TCL
@@ -317,6 +332,9 @@ extern std::vector<RTLIL::Design*> pushed_designs;
// from passes/cmds/pluginc.cc
extern std::map<std::string, void*> loaded_plugins;
+#ifdef WITH_PYTHON
+extern std::map<std::string, void*> loaded_python_plugins;
+#endif
extern std::map<std::string, std::string> loaded_plugin_aliases;
void load_plugin(std::string filename, std::vector<std::string> aliases);
diff --git a/libs/ezsat/ezminisat.h b/libs/ezsat/ezminisat.h
index 983e6fd0..3a34c13c 100644
--- a/libs/ezsat/ezminisat.h
+++ b/libs/ezsat/ezminisat.h
@@ -28,7 +28,7 @@
#include <time.h>
// minisat is using limit macros and format macros in their headers that
-// can be the source of some troubles when used from c++11. thefore we
+// can be the source of some troubles when used from c++11. therefore we
// don't force ezSAT users to use minisat headers..
namespace Minisat {
class Solver;
diff --git a/libs/subcircuit/README b/libs/subcircuit/README
index b1335681..ecaa987d 100644
--- a/libs/subcircuit/README
+++ b/libs/subcircuit/README
@@ -109,7 +109,7 @@ look at the demo.cc example program in this directory.
Setting up graphs
-----------------
-Instanciate the SubCircuit::Graph class and use the methods of this class to
+Instantiate the SubCircuit::Graph class and use the methods of this class to
set up the circuit.
SubCircuit::Graph myGraph;
@@ -152,7 +152,7 @@ rotate shift,
The method createConstant() can be used to add a constant driver to a signal.
The signal value is encoded as one char by bit, allowing for multi-valued
-logic matching. The follwoing command sets the lowest bit of cell6.A to a
+logic matching. The following command sets the lowest bit of cell6.A to a
logic 1:
myGraph.createConnection("cell6", "A", 0, '1');
@@ -314,7 +314,7 @@ bool userCompareEdge(needleGraphId, needleFromNodeId, needleFromUserData, needle
Perform additional checks on a pair of a pair of adjacent nodes (one
adjacent pair from the needle and one adjacent pair from the haystack)
- to determine wheter this edge from the needle is compatible with
+ to determine whether this edge from the needle is compatible with
that edge from the haystack. The default implementation always
returns true.
diff --git a/libs/subcircuit/subcircuit.cc b/libs/subcircuit/subcircuit.cc
index 7c723683..e8361a67 100644
--- a/libs/subcircuit/subcircuit.cc
+++ b/libs/subcircuit/subcircuit.cc
@@ -320,12 +320,10 @@ class SubCircuit::SolverWorker
static int numberOfPermutations(const std::vector<std::string> &list)
{
- int numPermutations = 1;
- for (int i = 0; i < int(list.size()); i++) {
- assert(numPermutations < maxPermutationsLimit);
- numPermutations *= i+1;
- }
- return numPermutations;
+ constexpr size_t mappedPermutationsSize = 10;
+ constexpr int mappedPermutations[mappedPermutationsSize] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
+ assert(list.size() < mappedPermutationsSize);
+ return mappedPermutations[list.size()];
}
static void permutateVectorToMap(std::map<std::string, std::string> &map, const std::vector<std::string> &list, int idx)
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index 277e8932..cb1bcf1b 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -119,6 +119,12 @@ than one bit from \B{S} is set the output is undefined. Cells of this type are u
``parallel cases'' (defined by using the {\tt parallel\_case} attribute or detected by
an optimization).
+The {\tt \$tribuf} cell is used to implement tristate logic. Cells of this type have a \B{WIDTH}
+parameter and inputs \B{A} and \B{EN} and an output \B{Y}. The \B{A} input and \B{Y} output are
+\B{WIDTH} bits wide, and the \B{EN} input is one bit wide. When \B{EN} is 0, the output \B{Y}
+is not driven. When \B{EN} is 1, the value from \B{A} input is sent to the \B{Y} output. Therefore,
+the {\tt \$tribuf} cell implements the function \lstinline[language=Verilog]; Y = EN ? A : 'bz;.
+
Behavioural code with cascaded {\tt if-then-else}- and {\tt case}-statements
usually results in trees of multiplexer cells. Many passes (from various
optimizations to FSM extraction) heavily depend on these multiplexer trees to
@@ -211,14 +217,15 @@ Add information about {\tt \$sr} cells (set-reset flip-flops) and d-type latches
\subsection{Memories}
\label{sec:memcells}
-Memories are either represented using RTLIL::Memory objects and {\tt \$memrd} and {\tt \$memwr} cells
-or simply by using {\tt \$mem} cells.
+Memories are either represented using RTLIL::Memory objects, {\tt \$memrd}, {\tt \$memwr}, and {\tt \$meminit}
+cells, or by {\tt \$mem} cells alone.
In the first alternative the RTLIL::Memory objects hold the general metadata for the memory (bit width,
size in number of words, etc.) and for each port a {\tt \$memrd} (read port) or {\tt \$memwr} (write port)
cell is created. Having individual cells for read and write ports has the advantage that they can be
consolidated using resource sharing passes. In some cases this drastically reduces the number of required
-ports on the memory cell.
+ports on the memory cell. In this alternative, memory initialization data is represented by {\tt \$meminit} cells,
+which allow delaying constant folding for initialization addresses and data until after the frontend finishes.
The {\tt \$memrd} cells have a clock input \B{CLK}, an enable input \B{EN}, an
address input \B{ADDR}, and a data output \B{DATA}. They also have the
@@ -253,7 +260,7 @@ enable bit for each data bit), an address input \B{ADDR} and a data input
\begin{itemize}
\item \B{MEMID} \\
-The name of the RTLIL::Memory object that is associated with this read port.
+The name of the RTLIL::Memory object that is associated with this write port.
\item \B{ABITS} \\
The number of address bits (width of the \B{ADDR} input port).
@@ -262,7 +269,7 @@ The number of address bits (width of the \B{ADDR} input port).
The number of data bits (width of the \B{DATA} output port).
\item \B{CLK\_ENABLE} \\
-When this parameter is non-zero, the clock is used. Otherwise this read port is asynchronous and
+When this parameter is non-zero, the clock is used. Otherwise this write port is asynchronous and
the \B{CLK} input is not used.
\item \B{CLK\_POLARITY} \\
@@ -273,6 +280,27 @@ edge if this parameter is {\tt 1'b0}.
The cell with the higher integer value in this parameter wins a write conflict.
\end{itemize}
+The {\tt \$meminit} cells have an address input \B{ADDR} and a data input \B{DATA}, with the width
+of the \B{DATA} port equal to \B{WIDTH} parameter times \B{WORDS} parameter. Both of the inputs
+must resolve to a constant for synthesis to succeed.
+
+\begin{itemize}
+\item \B{MEMID} \\
+The name of the RTLIL::Memory object that is associated with this initialization cell.
+
+\item \B{ABITS} \\
+The number of address bits (width of the \B{ADDR} input port).
+
+\item \B{WIDTH} \\
+The number of data bits per memory location.
+
+\item \B{WORDS} \\
+The number of consecutive memory locations initialized by this cell.
+
+\item \B{PRIORITY} \\
+The cell with the higher integer value in this parameter wins an initialization conflict.
+\end{itemize}
+
The HDL frontend models a memory using RTLIL::Memory objects and asynchronous
{\tt \$memrd} and {\tt \$memwr} cells. The {\tt memory} pass (i.e.~its various sub-passes) migrates
{\tt \$dff} cells into the {\tt \$memrd} and {\tt \$memwr} cells making them synchronous, then
@@ -295,6 +323,9 @@ The number of address bits.
\item \B{WIDTH} \\
The number of data bits per word.
+\item \B{INIT} \\
+The initial memory contents.
+
\item \B{RD\_PORTS} \\
The number of read ports on this memory cell.
@@ -345,9 +376,11 @@ This input is \B{WR\_PORTS}*\B{ABITS} bits wide, containing all address signals
This input is \B{WR\_PORTS}*\B{WIDTH} bits wide, containing all data signals for the write ports.
\end{itemize}
-The {\tt techmap} pass can be used to manually map {\tt \$mem} cells to
-specialized memory cells on the target architecture, such as block ram resources
-on an FPGA.
+The {\tt memory\_collect} pass can be used to convert discrete {\tt \$memrd}, {\tt \$memwr}, and {\tt \$meminit} cells
+belonging to the same memory to a single {\tt \$mem} cell, whereas the {\tt memory\_unpack} pass performs the inverse operation.
+The {\tt memory\_dff} pass can combine asynchronous memory ports that are fed by or feeding registers into synchronous memory ports.
+The {\tt memory\_bram} pass can be used to recognize {\tt \$mem} cells that can be implemented with a block RAM resource on an FPGA.
+The {\tt memory\_map} pass can be used to implement {\tt \$mem} cells as basic logic: word-wide DFFs and address decoders.
\subsection{Finite State Machines}
@@ -371,9 +404,15 @@ Verilog & Cell Type \\
\hline
\lstinline[language=Verilog]; Y = ~A; & {\tt \$\_NOT\_} \\
\lstinline[language=Verilog]; Y = A & B; & {\tt \$\_AND\_} \\
+\lstinline[language=Verilog]; Y = ~(A & B); & {\tt \$\_NAND\_} \\
+\lstinline[language=Verilog]; Y = A & ~B; & {\tt \$\_ANDNOT\_} \\
\lstinline[language=Verilog]; Y = A | B; & {\tt \$\_OR\_} \\
+\lstinline[language=Verilog]; Y = ~(A | B); & {\tt \$\_NOR\_} \\
+\lstinline[language=Verilog]; Y = A | ~B; & {\tt \$\_ORNOT\_} \\
\lstinline[language=Verilog]; Y = A ^ B; & {\tt \$\_XOR\_} \\
+\lstinline[language=Verilog]; Y = ~(A ^ B); & {\tt \$\_XNOR\_} \\
\lstinline[language=Verilog]; Y = S ? B : A; & {\tt \$\_MUX\_} \\
+\lstinline[language=Verilog]; Y = EN ? A : 'bz; & {\tt \$\_TBUF\_} \\
\hline
\lstinline[language=Verilog]; always @(negedge C) Q <= D; & {\tt \$\_DFF\_N\_} \\
\lstinline[language=Verilog]; always @(posedge C) Q <= D; & {\tt \$\_DFF\_P\_} \\
@@ -396,9 +435,10 @@ $ClkEdge$ & $RstLvl$ & $RstVal$ & Cell Type \\
\end{table}
Table~\ref{tab:CellLib_gates} lists all cell types used for gate level logic. The cell types
-{\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_OR\_}, {\tt \$\_XOR\_} and {\tt \$\_MUX\_}
-are used to model combinatorial logic. The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_}
-represent d-type flip-flops.
+{\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_NAND\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_OR\_}, {\tt \$\_NOR\_},
+{\tt \$\_ORNOT\_}, {\tt \$\_XOR\_}, {\tt \$\_XNOR\_} and {\tt \$\_MUX\_} are used to model combinatorial logic.
+The cell type {\tt \$\_TBUF\_} is used to model tristate logic.
+The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_} represent d-type flip-flops.
The cell types {\tt \$\_DFF\_NN0\_}, {\tt \$\_DFF\_NN1\_}, {\tt \$\_DFF\_NP0\_}, {\tt \$\_DFF\_NP1\_},
{\tt \$\_DFF\_PN0\_}, {\tt \$\_DFF\_PN1\_}, {\tt \$\_DFF\_PP0\_} and {\tt \$\_DFF\_PP1\_} implement
@@ -410,7 +450,7 @@ otherwise.
\begin{lstlisting}[mathescape,language=Verilog]
always @($ClkEdge$ C, $RstEdge$ R)
if (R == $RstLvl$)
- Q <= $RstVa$l;
+ Q <= $RstVal$;
else
Q <= D;
\end{lstlisting}
@@ -426,6 +466,10 @@ Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}
\end{fixme}
\begin{fixme}
+Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells.
+\end{fixme}
+
+\begin{fixme}
Add information about {\tt \$slice} and {\tt \$concat} cells.
\end{fixme}
@@ -450,7 +494,6 @@ Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLA
\end{fixme}
\begin{fixme}
-Add information about {\tt \$\_NAND\_}, {\tt \$\_NOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_ORNOT\_},
-{\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
+Add information about {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
\end{fixme}
diff --git a/manual/CHAPTER_Overview.tex b/manual/CHAPTER_Overview.tex
index ae5cf094..4136efed 100644
--- a/manual/CHAPTER_Overview.tex
+++ b/manual/CHAPTER_Overview.tex
@@ -331,8 +331,9 @@ to update {\tt \textbackslash{}q}.
An RTLIL::Process is a container for zero or more RTLIL::SyncRule objects and
exactly one RTLIL::CaseRule object, which is called the {\it root case}.
-An RTLIL::SyncRule object contains an (optional) synchronization condition
-(signal and edge-type) and zero or more assignments (RTLIL::SigSig).
+An RTLIL::SyncRule object contains an (optional) synchronization condition (signal and edge-type) and zero or
+more assignments (RTLIL::SigSig). The {\tt always} synchronization condition is used to break combinatorial
+loops when a latch should be inferred instead.
An RTLIL::CaseRule is a container for zero or more assignments (RTLIL::SigSig)
and zero or more RTLIL::SwitchRule objects. An RTLIL::SwitchRule objects is a
@@ -350,6 +351,18 @@ and this bit is a one (the second ``1'').} for {\tt \textbackslash{}reset == 1}
sets {\tt \$0\textbackslash{}q[0:0]} to the value of {\tt \textbackslash{}d} if {\tt
\textbackslash{}enable} is active (lines $6 \dots 11$).
+A case can specify zero or more compare values that will determine whether it matches. Each of the compare values
+must be the exact same width as the control signal. When more than one compare value is specified, the case matches
+if any of them matches the control signal; when zero compare values are specified, the case always matches (i.e.
+it is the default case).
+
+A switch prioritizes cases from first to last: multiple cases can match, but only the first matched case becomes
+active. This normally synthesizes to a priority encoder. The {\tt parallel\_case} attribute allows passes to assume
+that no more than one case will match, and {\tt full\_case} attribute allows passes to assume that exactly one
+case will match; if these invariants are ever dynamically violated, the behavior is undefined. These attributes
+are useful when an invariant invisible to the synthesizer causes the control signal to never take certain
+bit patterns.
+
The lines $13 \dots 16$ then cause {\tt \textbackslash{}q} to be updated whenever there is
a positive clock edge on {\tt \textbackslash{}clock} or {\tt \textbackslash{}reset}.
@@ -428,8 +441,8 @@ memory object has the following properties:
All read accesses to the memory are transformed to {\tt \$memrd} cells and all write accesses to
{\tt \$memwr} cells by the language frontend. These cells consist of independent read- and write-ports
-to the memory. The \B{MEMID} parameter on these cells is used to link them together and to the
-RTLIL::Memory object they belong to.
+to the memory. Memory initialization is transformed to {\tt \$meminit} cells by the language frontend.
+The \B{MEMID} parameter on these cells is used to link them together and to the RTLIL::Memory object they belong to.
The rationale behind using separate cells for the individual ports versus
creating a large multiport memory cell right in the language frontend is that
diff --git a/misc/__init__.py b/misc/__init__.py
new file mode 100644
index 00000000..330fd6d8
--- /dev/null
+++ b/misc/__init__.py
@@ -0,0 +1,5 @@
+import os
+import sys
+sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL)
+
+__all__ = ["libyosys"]
diff --git a/misc/launcher.c b/misc/launcher.c
new file mode 100644
index 00000000..e0d8208f
--- /dev/null
+++ b/misc/launcher.c
@@ -0,0 +1,359 @@
+/* This file comes from the PyPA Setuptools repository, commit 16e452a:
+https://github.com/pypa/setuptools
+Modifications include this comment and inline inclusion of the LICENSE text. */
+
+/* Copyright (C) 2016 Jason R Coombs <jaraco@jaraco.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE. */
+
+/* Setuptools Script Launcher for Windows
+
+ This is a stub executable for Windows that functions somewhat like
+ Effbot's "exemaker", in that it runs a script with the same name but
+ a .py extension, using information from a #! line. It differs in that
+ it spawns the actual Python executable, rather than attempting to
+ hook into the Python DLL. This means that the script will run with
+ sys.executable set to the Python executable, where exemaker ends up with
+ sys.executable pointing to itself. (Which means it won't work if you try
+ to run another Python process using sys.executable.)
+
+ To build/rebuild with mingw32, do this in the setuptools project directory:
+
+ gcc -DGUI=0 -mno-cygwin -O -s -o setuptools/cli.exe launcher.c
+ gcc -DGUI=1 -mwindows -mno-cygwin -O -s -o setuptools/gui.exe launcher.c
+
+ To build for Windows RT, install both Visual Studio Express for Windows 8
+ and for Windows Desktop (both freeware), create "win32" application using
+ "Windows Desktop" version, create new "ARM" target via
+ "Configuration Manager" menu and modify ".vcxproj" file by adding
+ "<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>" tag
+ as child of "PropertyGroup" tags that has "Debug|ARM" and "Release|ARM"
+ properties.
+
+ It links to msvcrt.dll, but this shouldn't be a problem since it doesn't
+ actually run Python in the same process. Note that using 'exec' instead
+ of 'spawn' doesn't work, because on Windows this leads to the Python
+ executable running in the *background*, attached to the same console
+ window, meaning you get a command prompt back *before* Python even finishes
+ starting. So, we have to use spawnv() and wait for Python to exit before
+ continuing. :(
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <windows.h>
+#include <tchar.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int child_pid=0;
+
+int fail(char *format, char *data) {
+ /* Print error message to stderr and return 2 */
+ fprintf(stderr, format, data);
+ return 2;
+}
+
+char *quoted(char *data) {
+ int i, ln = strlen(data), nb;
+
+ /* We allocate twice as much space as needed to deal with worse-case
+ of having to escape everything. */
+ char *result = calloc(ln*2+3, sizeof(char));
+ char *presult = result;
+
+ *presult++ = '"';
+ for (nb=0, i=0; i < ln; i++)
+ {
+ if (data[i] == '\\')
+ nb += 1;
+ else if (data[i] == '"')
+ {
+ for (; nb > 0; nb--)
+ *presult++ = '\\';
+ *presult++ = '\\';
+ }
+ else
+ nb = 0;
+ *presult++ = data[i];
+ }
+
+ for (; nb > 0; nb--) /* Deal w trailing slashes */
+ *presult++ = '\\';
+
+ *presult++ = '"';
+ *presult++ = 0;
+ return result;
+}
+
+
+
+
+
+
+
+
+
+
+char *loadable_exe(char *exename) {
+ /* HINSTANCE hPython; DLL handle for python executable */
+ char *result;
+
+ /* hPython = LoadLibraryEx(exename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!hPython) return NULL; */
+
+ /* Return the absolute filename for spawnv */
+ result = calloc(MAX_PATH, sizeof(char));
+ strncpy(result, exename, MAX_PATH);
+ /*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
+
+ FreeLibrary(hPython); */
+ return result;
+}
+
+
+char *find_exe(char *exename, char *script) {
+ char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
+ char path[_MAX_PATH], c, *result;
+
+ /* convert slashes to backslashes for uniform search below */
+ result = exename;
+ while (c = *result++) if (c=='/') result[-1] = '\\';
+
+ _splitpath(exename, drive, dir, fname, ext);
+ if (drive[0] || dir[0]=='\\') {
+ return loadable_exe(exename); /* absolute path, use directly */
+ }
+ /* Use the script's parent directory, which should be the Python home
+ (This should only be used for bdist_wininst-installed scripts, because
+ easy_install-ed scripts use the absolute path to python[w].exe
+ */
+ _splitpath(script, drive, dir, fname, ext);
+ result = dir + strlen(dir) -1;
+ if (*result == '\\') result--;
+ while (*result != '\\' && result>=dir) *result-- = 0;
+ _makepath(path, drive, dir, exename, NULL);
+ return loadable_exe(path);
+}
+
+
+char **parse_argv(char *cmdline, int *argc)
+{
+ /* Parse a command line in-place using MS C rules */
+
+ char **result = calloc(strlen(cmdline), sizeof(char *));
+ char *output = cmdline;
+ char c;
+ int nb = 0;
+ int iq = 0;
+ *argc = 0;
+
+ result[0] = output;
+ while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
+
+ do {
+ c = *cmdline++;
+ if (!c || (isspace(c) && !iq)) {
+ while (nb) {*output++ = '\\'; nb--; }
+ *output++ = 0;
+ result[++*argc] = output;
+ if (!c) return result;
+ while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
+ if (!*cmdline) return result; /* avoid empty arg if trailing ws */
+ continue;
+ }
+ if (c == '\\')
+ ++nb; /* count \'s */
+ else {
+ if (c == '"') {
+ if (!(nb & 1)) { iq = !iq; c = 0; } /* skip " unless odd # of \ */
+ nb = nb >> 1; /* cut \'s in half */
+ }
+ while (nb) {*output++ = '\\'; nb--; }
+ if (c) *output++ = c;
+ }