summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--CHANGELOG149
-rw-r--r--CodingReadme194
-rw-r--r--Makefile261
-rw-r--r--README182
-rw-r--r--backends/autotest/Makefile.inc3
-rw-r--r--backends/autotest/autotest.cc336
-rw-r--r--backends/blif/blif.cc221
-rw-r--r--backends/btor/btor.cc394
-rwxr-xr-xbackends/btor/verilog2btor.sh4
-rw-r--r--backends/edif/edif.cc216
-rw-r--r--backends/ilang/ilang_backend.cc329
-rw-r--r--backends/ilang/ilang_backend.h32
-rw-r--r--backends/intersynth/intersynth.cc61
-rw-r--r--backends/spice/spice.cc93
-rw-r--r--backends/verilog/verilog_backend.cc729
-rw-r--r--backends/verilog/verilog_backend.h5
-rw-r--r--frontends/ast/Makefile.inc1
-rw-r--r--frontends/ast/ast.cc323
-rw-r--r--frontends/ast/ast.h52
-rw-r--r--frontends/ast/dpicall.cc140
-rw-r--r--frontends/ast/genrtlil.cc618
-rw-r--r--frontends/ast/simplify.cc1123
-rw-r--r--frontends/ilang/Makefile.inc10
-rw-r--r--frontends/ilang/ilang_frontend.cc9
-rw-r--r--frontends/ilang/ilang_frontend.h11
-rw-r--r--frontends/ilang/lexer.l40
-rw-r--r--frontends/ilang/parser.y116
-rw-r--r--frontends/liberty/Makefile.inc3
-rw-r--r--frontends/liberty/liberty.cc578
-rw-r--r--frontends/verific/Makefile.inc16
-rw-r--r--frontends/verific/build_amd64.txt31
-rw-r--r--frontends/verific/test_navre.ys18
-rw-r--r--frontends/verific/verific.cc949
-rw-r--r--frontends/verilog/Makefile.inc6
-rw-r--r--frontends/verilog/const2ast.cc46
-rw-r--r--frontends/verilog/lexer.l90
-rw-r--r--frontends/verilog/parser.y262
-rw-r--r--frontends/verilog/preproc.cc65
-rw-r--r--frontends/verilog/verilog_frontend.cc58
-rw-r--r--frontends/verilog/verilog_frontend.h17
-rw-r--r--frontends/vhdl2verilog/Makefile.inc1
-rw-r--r--frontends/vhdl2verilog/vhdl2verilog.cc196
-rw-r--r--kernel/bitpattern.h19
-rw-r--r--kernel/calc.cc79
-rw-r--r--kernel/celltypes.h335
-rw-r--r--kernel/consteval.h213
-rw-r--r--kernel/driver.cc655
-rw-r--r--kernel/log.cc199
-rw-r--r--kernel/log.h120
-rw-r--r--kernel/macc.h231
-rw-r--r--kernel/modtools.h455
-rw-r--r--kernel/register.cc263
-rw-r--r--kernel/register.h81
-rw-r--r--kernel/rtlil.cc2351
-rw-r--r--kernel/rtlil.h922
-rw-r--r--kernel/satgen.h641
-rw-r--r--kernel/sigtools.h319
-rw-r--r--kernel/utils.h210
-rw-r--r--kernel/yosys.cc646
-rw-r--r--kernel/yosys.h149
-rw-r--r--libs/ezsat/Makefile8
-rw-r--r--libs/ezsat/ezminisat.cc88
-rw-r--r--libs/ezsat/ezminisat.h20
-rw-r--r--libs/ezsat/ezsat.cc322
-rw-r--r--libs/ezsat/ezsat.h38
-rw-r--r--libs/ezsat/puzzle3d.cc4
-rw-r--r--libs/ezsat/testbench.cc131
-rw-r--r--libs/minisat/00_PATCH_mkLit_default_arg.patch20
-rw-r--r--libs/minisat/00_PATCH_remove_zlib.patch38
-rw-r--r--libs/minisat/00_UPDATE.sh17
-rw-r--r--libs/minisat/Alg.h84
-rw-r--r--libs/minisat/Alloc.h131
-rw-r--r--libs/minisat/Dimacs.h87
-rw-r--r--libs/minisat/Heap.h168
-rw-r--r--libs/minisat/IntMap.h106
-rw-r--r--libs/minisat/IntTypes.h42
-rw-r--r--libs/minisat/LICENSE21
-rw-r--r--libs/minisat/Map.h193
-rw-r--r--libs/minisat/Options.cc94
-rw-r--r--libs/minisat/Options.h386
-rw-r--r--libs/minisat/ParseUtils.h119
-rw-r--r--libs/minisat/Queue.h69
-rw-r--r--libs/minisat/Rnd.h67
-rw-r--r--libs/minisat/SimpSolver.cc727
-rw-r--r--libs/minisat/SimpSolver.h222
-rw-r--r--libs/minisat/Solver.cc1068
-rw-r--r--libs/minisat/Solver.h409
-rw-r--r--libs/minisat/SolverTypes.h478
-rw-r--r--libs/minisat/Sort.h98
-rw-r--r--libs/minisat/System.cc171
-rw-r--r--libs/minisat/System.h72
-rw-r--r--libs/minisat/Vec.h134
-rw-r--r--libs/minisat/XAlloc.h45
-rw-r--r--libs/sha1/sha1.cpp455
-rw-r--r--libs/sha1/sha1.h106
-rw-r--r--libs/subcircuit/subcircuit.cc4
-rw-r--r--libs/svgviewer/.gitignore5
-rw-r--r--libs/svgviewer/files/bubbles.svg215
-rw-r--r--libs/svgviewer/files/cubic.svg77
-rw-r--r--libs/svgviewer/files/spheres.svg72
-rw-r--r--libs/svgviewer/main.cpp66
-rw-r--r--libs/svgviewer/mainwindow.cpp205
-rw-r--r--libs/svgviewer/mainwindow.h86
-rw-r--r--libs/svgviewer/svgview.cpp227
-rw-r--r--libs/svgviewer/svgview.h87
-rw-r--r--libs/svgviewer/svgviewer.desktop11
-rw-r--r--libs/svgviewer/svgviewer.pro33
-rw-r--r--libs/svgviewer/svgviewer.qrc6
-rw-r--r--manual/APPNOTE_011_Design_Investigation.tex24
-rw-r--r--manual/CHAPTER_Approach.tex14
-rw-r--r--manual/CHAPTER_Auxlibs.tex6
-rw-r--r--manual/CHAPTER_Auxprogs.tex7
-rw-r--r--manual/CHAPTER_Basics.tex30
-rw-r--r--manual/CHAPTER_CellLib.tex29
-rw-r--r--manual/CHAPTER_Intro.tex8
-rw-r--r--manual/CHAPTER_Optimize.tex2
-rw-r--r--manual/CHAPTER_Overview.tex50
-rw-r--r--manual/CHAPTER_Prog/stubnets.cc31
-rw-r--r--manual/CHAPTER_StateOfTheArt/simlib_yosys.v4
-rw-r--r--manual/CHAPTER_Techmap.tex4
-rw-r--r--manual/CHAPTER_Verilog.tex6
-rw-r--r--manual/PRESENTATION_ExAdv.tex634
-rw-r--r--manual/PRESENTATION_ExAdv/Makefile28
-rw-r--r--manual/PRESENTATION_ExAdv/addshift_map.v20
-rw-r--r--manual/PRESENTATION_ExAdv/addshift_test.v5
-rw-r--r--manual/PRESENTATION_ExAdv/addshift_test.ys6
-rw-r--r--manual/PRESENTATION_ExAdv/macc_simple_test.v6
-rw-r--r--manual/PRESENTATION_ExAdv/macc_simple_test.ys37
-rw-r--r--manual/PRESENTATION_ExAdv/macc_simple_test_01.v6
-rw-r--r--manual/PRESENTATION_ExAdv/macc_simple_test_02.v6
-rw-r--r--manual/PRESENTATION_ExAdv/macc_simple_xmap.v6
-rw-r--r--manual/PRESENTATION_ExAdv/macc_xilinx_swap_map.v28
-rw-r--r--manual/PRESENTATION_ExAdv/macc_xilinx_test.v13
-rw-r--r--manual/PRESENTATION_ExAdv/macc_xilinx_test.ys43
-rw-r--r--manual/PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v61
-rw-r--r--manual/PRESENTATION_ExAdv/macc_xilinx_wrap_map.v89
-rw-r--r--manual/PRESENTATION_ExAdv/macc_xilinx_xmap.v10
-rw-r--r--manual/PRESENTATION_ExAdv/mulshift_map.v26
-rw-r--r--manual/PRESENTATION_ExAdv/mulshift_test.v5
-rw-r--r--manual/PRESENTATION_ExAdv/mulshift_test.ys7
-rw-r--r--manual/PRESENTATION_ExAdv/mymul_map.v15
-rw-r--r--manual/PRESENTATION_ExAdv/mymul_test.v4
-rw-r--r--manual/PRESENTATION_ExAdv/mymul_test.ys15
-rw-r--r--manual/PRESENTATION_ExAdv/red_or3x1_cells.v5
-rw-r--r--manual/PRESENTATION_ExAdv/red_or3x1_map.v48
-rw-r--r--manual/PRESENTATION_ExAdv/red_or3x1_test.v5
-rw-r--r--manual/PRESENTATION_ExAdv/red_or3x1_test.ys7
-rw-r--r--manual/PRESENTATION_ExAdv/select.v (renamed from manual/PRESENTATION_ExAdv/select_01.v)0
-rw-r--r--manual/PRESENTATION_ExAdv/select.ys (renamed from manual/PRESENTATION_ExAdv/select_01.ys)4
-rw-r--r--manual/PRESENTATION_ExAdv/sym_mul_cells.v6
-rw-r--r--manual/PRESENTATION_ExAdv/sym_mul_map.v15
-rw-r--r--manual/PRESENTATION_ExAdv/sym_mul_test.v5
-rw-r--r--manual/PRESENTATION_ExAdv/sym_mul_test.ys6
-rw-r--r--manual/PRESENTATION_ExOth.tex181
-rw-r--r--manual/PRESENTATION_ExOth/.gitignore1
-rw-r--r--manual/PRESENTATION_ExOth/Makefile16
-rw-r--r--manual/PRESENTATION_ExOth/axis_master.v27
-rw-r--r--manual/PRESENTATION_ExOth/axis_test.v27
-rw-r--r--manual/PRESENTATION_ExOth/axis_test.ys5
-rw-r--r--manual/PRESENTATION_ExOth/equiv.ys17
-rw-r--r--manual/PRESENTATION_ExOth/scrambler.v14
-rw-r--r--manual/PRESENTATION_ExOth/scrambler.ys23
-rw-r--r--manual/PRESENTATION_ExSyn.tex26
-rw-r--r--manual/PRESENTATION_ExSyn/Makefile2
-rw-r--r--manual/PRESENTATION_ExSyn/techmap_01_map.v6
-rw-r--r--manual/PRESENTATION_Intro.tex197
-rw-r--r--manual/PRESENTATION_Intro/counter.ys11
-rw-r--r--manual/PRESENTATION_Prog.tex452
-rw-r--r--manual/PRESENTATION_Prog/.gitignore1
-rw-r--r--manual/PRESENTATION_Prog/Makefile18
-rw-r--r--manual/PRESENTATION_Prog/absval_ref.v3
-rw-r--r--manual/PRESENTATION_Prog/my_cmd.cc71
-rw-r--r--manual/PRESENTATION_Prog/sigmap_test.v3
-rwxr-xr-xmanual/clean.sh2
-rw-r--r--manual/command-reference-manual.tex16
-rw-r--r--manual/manual.tex6
-rwxr-xr-xmanual/presentation.sh2
-rw-r--r--manual/presentation.tex22
-rw-r--r--manual/weblinks.bib6
-rw-r--r--passes/abc/abc.cc655
-rw-r--r--passes/abc/blifparse.cc82
-rw-r--r--passes/cmds/Makefile.inc6
-rw-r--r--passes/cmds/add.cc23
-rw-r--r--passes/cmds/connect.cc18
-rw-r--r--passes/cmds/connwrappers.cc205
-rw-r--r--passes/cmds/copy.cc9
-rw-r--r--passes/cmds/cover.cc144
-rw-r--r--passes/cmds/delete.cc61
-rw-r--r--passes/cmds/design.cc82
-rw-r--r--passes/cmds/plugin.cc124
-rw-r--r--passes/cmds/rename.cc65
-rw-r--r--passes/cmds/scatter.cc15
-rw-r--r--passes/cmds/scc.cc18
-rw-r--r--passes/cmds/select.cc198
-rw-r--r--passes/cmds/setattr.cc10
-rw-r--r--passes/cmds/setundef.cc70
-rw-r--r--passes/cmds/show.cc139
-rw-r--r--passes/cmds/splice.cc78
-rw-r--r--passes/cmds/splitnets.cc59
-rw-r--r--passes/cmds/stat.cc49
-rw-r--r--passes/cmds/tee.cc88
-rw-r--r--passes/cmds/trace.cc97
-rw-r--r--passes/cmds/write_file.cc76
-rw-r--r--passes/fsm/fsm.cc6
-rw-r--r--passes/fsm/fsm_detect.cc34
-rw-r--r--passes/fsm/fsm_expand.cc104
-rw-r--r--passes/fsm/fsm_export.cc14
-rw-r--r--passes/fsm/fsm_extract.cc249
-rw-r--r--passes/fsm/fsm_info.cc4
-rw-r--r--passes/fsm/fsm_map.cc304
-rw-r--r--passes/fsm/fsm_opt.cc94
-rw-r--r--passes/fsm/fsm_recode.cc36
-rw-r--r--passes/fsm/fsmdata.h22
-rw-r--r--passes/hierarchy/hierarchy.cc166
-rw-r--r--passes/hierarchy/submod.cc105
-rw-r--r--passes/memory/Makefile.inc1
-rw-r--r--passes/memory/memory.cc6
-rw-r--r--passes/memory/memory_collect.cc102
-rw-r--r--passes/memory/memory_dff.cc125
-rw-r--r--passes/memory/memory_map.cc513
-rw-r--r--passes/memory/memory_share.cc744
-rw-r--r--passes/memory/memory_unpack.cc40
-rw-r--r--passes/opt/Makefile.inc2
-rw-r--r--passes/opt/opt.cc88
-rw-r--r--passes/opt/opt_clean.cc127
-rw-r--r--passes/opt/opt_const.cc753
-rw-r--r--passes/opt/opt_muxtree.cc93
-rw-r--r--passes/opt/opt_reduce.cc258
-rw-r--r--passes/opt/opt_rmdff.cc84
-rw-r--r--passes/opt/opt_share.cc52
-rw-r--r--passes/opt/opt_status.h26
-rw-r--r--passes/opt/share.cc1171
-rw-r--r--passes/opt/wreduce.cc350
-rw-r--r--passes/proc/proc_arst.cc97
-rw-r--r--passes/proc/proc_clean.cc27
-rw-r--r--passes/proc/proc_dff.cc263
-rw-r--r--passes/proc/proc_init.cc33
-rw-r--r--passes/proc/proc_mux.cc132
-rw-r--r--passes/proc/proc_rmdead.cc13
-rw-r--r--passes/sat/eval.cc115
-rw-r--r--passes/sat/example.ys7
-rw-r--r--passes/sat/expose.cc238
-rw-r--r--passes/sat/freduce.cc133
-rw-r--r--passes/sat/miter.cc200
-rw-r--r--passes/sat/sat.cc313
-rw-r--r--passes/techmap/.gitignore2
-rw-r--r--passes/techmap/Makefile.inc24
-rw-r--r--passes/techmap/alumacc.cc563
-rw-r--r--passes/techmap/dfflibmap.cc60
-rw-r--r--passes/techmap/extract.cc285
-rw-r--r--passes/techmap/hilomap.cc42
-rw-r--r--passes/techmap/iopadmap.cc67
-rw-r--r--passes/techmap/libparse.cc45
-rw-r--r--passes/techmap/libparse.h4
-rw-r--r--passes/techmap/maccmap.cc394
-rw-r--r--passes/techmap/simplemap.cc423
-rw-r--r--passes/techmap/techmap.cc1104
-rw-r--r--passes/tests/Makefile.inc5
-rw-r--r--passes/tests/test_abcloop.cc285
-rw-r--r--passes/tests/test_autotb.cc353
-rw-r--r--passes/tests/test_cell.cc745
-rw-r--r--techlibs/common/Makefile.inc32
-rw-r--r--techlibs/common/adff2dff.v27
-rw-r--r--techlibs/common/blackbox.sed5
-rw-r--r--techlibs/common/simcells.v152
-rw-r--r--techlibs/common/simlib.v452
-rw-r--r--techlibs/common/stdcells.v1080
-rw-r--r--techlibs/common/synth.cc156
-rw-r--r--techlibs/common/techmap.v509
-rw-r--r--techlibs/xilinx/Makefile.inc4
-rw-r--r--techlibs/xilinx/cells.v36
-rwxr-xr-xtests/asicworld/run-test.sh3
-rw-r--r--tests/fsm/.gitignore1
-rw-r--r--tests/fsm/generate.py109
-rwxr-xr-xtests/fsm/run-test.sh32
-rw-r--r--tests/hana/README10
-rwxr-xr-xtests/hana/run-test.sh3
-rw-r--r--tests/hana/test_intermout.v418
-rw-r--r--tests/hana/test_intermout_always_comb_1_test.v13
-rw-r--r--tests/hana/test_intermout_always_comb_3_test.v10
-rw-r--r--tests/hana/test_intermout_always_comb_4_test.v9
-rw-r--r--tests/hana/test_intermout_always_comb_5_test.v11
-rw-r--r--tests/hana/test_intermout_always_ff_3_test.v15
-rw-r--r--tests/hana/test_intermout_always_ff_4_test.v11
-rw-r--r--tests/hana/test_intermout_always_ff_5_test.v13
-rw-r--r--tests/hana/test_intermout_always_ff_6_test.v7
-rw-r--r--tests/hana/test_intermout_always_ff_8_test.v11
-rw-r--r--tests/hana/test_intermout_always_ff_9_test.v14
-rw-r--r--tests/hana/test_intermout_always_latch_1_test.v9
-rw-r--r--tests/hana/test_intermout_bufrm_1_test.v4
-rw-r--r--tests/hana/test_intermout_bufrm_2_test.v7
-rw-r--r--tests/hana/test_intermout_bufrm_6_test.v22
-rw-r--r--tests/hana/test_intermout_bufrm_7_test.v33
-rw-r--r--tests/hana/test_intermout_exprs_add_test.v10
-rw-r--r--tests/hana/test_intermout_exprs_binlogic_test.v13
-rw-r--r--tests/hana/test_intermout_exprs_bitwiseneg_test.v5
-rw-r--r--tests/hana/test_intermout_exprs_buffer_test.v9
-rw-r--r--tests/hana/test_intermout_exprs_condexpr_mux_test.v11
-rw-r--r--tests/hana/test_intermout_exprs_condexpr_tribuf_test.v9
-rw-r--r--tests/hana/test_intermout_exprs_const_test.v7
-rw-r--r--tests/hana/test_intermout_exprs_constshift_test.v12
-rw-r--r--tests/hana/test_intermout_exprs_div_test.v10
-rw-r--r--tests/hana/test_intermout_exprs_logicneg_test.v7
-rw-r--r--tests/hana/test_intermout_exprs_mod_test.v10
-rw-r--r--tests/hana/test_intermout_exprs_mul_test.v10
-rw-r--r--tests/hana/test_intermout_exprs_redand_test.v5
-rw-r--r--tests/hana/test_intermout_exprs_redop_test.v16
-rw-r--r--tests/hana/test_intermout_exprs_sub_test.v10
-rw-r--r--tests/hana/test_intermout_exprs_unaryminus_test.v5
-rw-r--r--tests/hana/test_intermout_exprs_unaryplus_test.v4
-rw-r--r--tests/hana/test_intermout_exprs_varshift_test.v10
-rw-r--r--tests/hana/test_parse2synthtrans.v117
-rw-r--r--tests/hana/test_parse2synthtrans_behavopt_1_test.v22
-rw-r--r--tests/hana/test_parse2synthtrans_case_1_test.v26
-rw-r--r--tests/hana/test_parse2synthtrans_contassign_1_test.v7
-rw-r--r--tests/hana/test_parse2synthtrans_module_basic0_test.v2
-rw-r--r--tests/hana/test_parse2synthtrans_operators_1_test.v11
-rw-r--r--tests/hana/test_parse2synthtrans_param_1_test.v7
-rw-r--r--tests/hana/test_parse2synthtrans_port_scalar_1_test.v6
-rw-r--r--tests/hana/test_parse2synthtrans_port_vector_1_test.v9
-rw-r--r--tests/hana/test_parse2synthtrans_v2k_comb_logic_sens_list_test.v9
-rw-r--r--tests/hana/test_parser.v87
-rw-r--r--tests/hana/test_parser_constructs_module_basic1_test.v2
-rw-r--r--tests/hana/test_parser_constructs_param_basic0_test.v10
-rw-r--r--tests/hana/test_parser_constructs_port_basic0_test.v8
-rw-r--r--tests/hana/test_parser_directives_define_simpledef_test.v9
-rw-r--r--tests/hana/test_parser_misc_operators_test.v29
-rw-r--r--tests/hana/test_parser_v2k_comb_port_data_type_test.v6
-rw-r--r--tests/hana/test_parser_v2k_comma_sep_sens_list_test.v9
-rw-r--r--tests/hana/test_simulation_always.v135
-rw-r--r--tests/hana/test_simulation_always_15_test.v5
-rw-r--r--tests/hana/test_simulation_always_17_test.v13
-rw-r--r--tests/hana/test_simulation_always_18_test.v10
-rw-r--r--tests/hana/test_simulation_always_19_test.v11
-rw-r--r--tests/hana/test_simulation_always_1_test.v5
-rw-r--r--tests/hana/test_simulation_always_20_test.v15
-rw-r--r--tests/hana/test_simulation_always_21_test.v11
-rw-r--r--tests/hana/test_simulation_always_22_test.v7
-rw-r--r--tests/hana/test_simulation_always_23_test.v14
-rw-r--r--tests/hana/test_simulation_always_27_test.v13
-rw-r--r--tests/hana/test_simulation_always_29_test.v9
-rw-r--r--tests/hana/test_simulation_and.v35
-rw-r--r--tests/hana/test_simulation_and_1_test.v3
-rw-r--r--tests/hana/test_simulation_and_2_test.v3
-rw-r--r--tests/hana/test_simulation_and_3_test.v3
-rw-r--r--tests/hana/test_simulation_and_4_test.v3
-rw-r--r--tests/hana/test_simulation_and_5_test.v3
-rw-r--r--tests/hana/test_simulation_and_6_test.v3
-rw-r--r--tests/hana/test_simulation_and_7_test.v3
-rw-r--r--tests/hana/test_simulation_buffer.v17
-rw-r--r--tests/hana/test_simulation_buffer_1_test.v3
-rw-r--r--tests/hana/test_simulation_buffer_2_test.v4
-rw-r--r--tests/hana/test_simulation_buffer_3_test.v4
-rw-r--r--tests/hana/test_simulation_decoder.v (renamed from tests/hana/test_simulation_decoder_8_test.v)145
-rw-r--r--tests/hana/test_simulation_decoder_2_test.v14
-rw-r--r--tests/hana/test_simulation_decoder_3_test.v14
-rw-r--r--tests/hana/test_simulation_decoder_4_test.v14
-rw-r--r--tests/hana/test_simulation_decoder_5_test.v17
-rw-r--r--tests/hana/test_simulation_decoder_6_test.v27
-rw-r--r--tests/hana/test_simulation_decoder_7_test.v43
-rw-r--r--tests/hana/test_simulation_inc.v42
-rw-r--r--tests/hana/test_simulation_inc_16_test.v5
-rw-r--r--tests/hana/test_simulation_inc_1_test.v5
-rw-r--r--tests/hana/test_simulation_inc_2_test.v5
-rw-r--r--tests/hana/test_simulation_inc_32_test.v5
-rw-r--r--tests/hana/test_simulation_inc_4_test.v5
-rw-r--r--tests/hana/test_simulation_inc_8_test.v5
-rw-r--r--tests/hana/test_simulation_mod_1_xx.v13
-rw-r--r--tests/hana/test_simulation_mux.v176
-rw-r--r--tests/hana/test_simulation_mux_16_test.v22
-rw-r--r--tests/hana/test_simulation_mux_2_test.v8
-rw-r--r--tests/hana/test_simulation_mux_32_test.v39
-rw-r--r--tests/hana/test_simulation_mux_4_test.v10
-rw-r--r--tests/hana/test_simulation_mux_64_test.v71
-rw-r--r--tests/hana/test_simulation_mux_8_test.v14
-rw-r--r--tests/hana/test_simulation_nand.v25
-rw-r--r--tests/hana/test_simulation_nand_1_test.v3
-rw-r--r--tests/hana/test_simulation_nand_3_test.v3
-rw-r--r--tests/hana/test_simulation_nand_4_test.v3
-rw-r--r--tests/hana/test_simulation_nand_5_test.v3
-rw-r--r--tests/hana/test_simulation_nand_6_test.v3
-rw-r--r--tests/hana/test_simulation_nor.v20
-rw-r--r--tests/hana/test_simulation_nor_1_test.v3
-rw-r--r--tests/hana/test_simulation_nor_2_test.v3
-rw-r--r--tests/hana/test_simulation_nor_3_test.v3
-rw-r--r--tests/hana/test_simulation_nor_4_test.v3
-rw-r--r--tests/hana/test_simulation_opt_constprop_contassign_1_test.v3
-rw-r--r--tests/hana/test_simulation_or.v30
-rw-r--r--tests/hana/test_simulation_or_1_test.v3
-rw-r--r--tests/hana/test_simulation_or_2_test.v3
-rw-r--r--tests/hana/test_simulation_or_3_test.v3
-rw-r--r--tests/hana/test_simulation_or_4_test.v3
-rw-r--r--tests/hana/test_simulation_or_5_test.v3
-rw-r--r--tests/hana/test_simulation_or_6_test.v3
-rw-r--r--tests/hana/test_simulation_seq.v12
-rw-r--r--tests/hana/test_simulation_seq_ff_1_test.v4
-rw-r--r--tests/hana/test_simulation_seq_ff_2_test.v4
-rw-r--r--tests/hana/test_simulation_shifter.v60
-rw-r--r--tests/hana/test_simulation_shifter_left_16_test.v4
-rw-r--r--tests/hana/test_simulation_shifter_left_32_test.v4
-rw-r--r--tests/hana/test_simulation_shifter_left_4_test.v4
-rw-r--r--tests/hana/test_simulation_shifter_left_64_test.v4
-rw-r--r--tests/hana/test_simulation_shifter_left_8_test.v4
-rw-r--r--tests/hana/test_simulation_shifter_right_16_test.v4
-rw-r--r--tests/hana/test_simulation_shifter_right_32_test.v4
-rw-r--r--tests/hana/test_simulation_shifter_right_4_test.v4
-rw-r--r--tests/hana/test_simulation_shifter_right_64_test.v4
-rw-r--r--tests/hana/test_simulation_shifter_right_8_test.v4
-rw-r--r--tests/hana/test_simulation_sop.v65
-rw-r--r--tests/hana/test_simulation_sop_basic_10_test.v8
-rw-r--r--tests/hana/test_simulation_sop_basic_11_test.v10
-rw-r--r--tests/hana/test_simulation_sop_basic_12_test.v14
-rw-r--r--tests/hana/test_simulation_sop_basic_18_test.v5
-rw-r--r--tests/hana/test_simulation_sop_basic_3_test.v3
-rw-r--r--tests/hana/test_simulation_sop_basic_7_test.v3
-rw-r--r--tests/hana/test_simulation_sop_basic_8_test.v3
-rw-r--r--tests/hana/test_simulation_sop_basic_9_test.v3
-rw-r--r--tests/hana/test_simulation_techmap.v (renamed from tests/hana/test_simulation_techmap_mux_128_test.v)40
-rw-r--r--tests/hana/test_simulation_techmap_and_19_tech.v7
-rw-r--r--tests/hana/test_simulation_techmap_and_5_tech.v3
-rw-r--r--tests/hana/test_simulation_techmap_buf_test.v3
-rw-r--r--tests/hana/test_simulation_techmap_inv_test.v3
-rw-r--r--tests/hana/test_simulation_techmap_mux_0_test.v8
-rw-r--r--tests/hana/test_simulation_techmap_mux_8_test.v14
-rw-r--r--tests/hana/test_simulation_techmap_nand_19_tech.v11
-rw-r--r--tests/hana/test_simulation_techmap_nand_2_tech.v11
-rw-r--r--tests/hana/test_simulation_techmap_nand_5_tech.v11
-rw-r--r--tests/hana/test_simulation_techmap_nor_19_tech.v11
-rw-r--r--tests/hana/test_simulation_techmap_nor_2_tech.v11
-rw-r--r--tests/hana/test_simulation_techmap_nor_5_tech.v11
-rw-r--r--tests/hana/test_simulation_techmap_or_19_tech.v7
-rw-r--r--tests/hana/test_simulation_techmap_or_5_tech.v3
-rw-r--r--tests/hana/test_simulation_techmap_tech.v143
-rw-r--r--tests/hana/test_simulation_techmap_xnor_2_tech.v6
-rw-r--r--tests/hana/test_simulation_techmap_xnor_5_tech.v6
-rw-r--r--tests/hana/test_simulation_techmap_xor_19_tech.v3
-rw-r--r--tests/hana/test_simulation_techmap_xor_2_tech.v6
-rw-r--r--tests/hana/test_simulation_techmap_xor_5_tech.v6
-rw-r--r--tests/hana/test_simulation_tribuf_2_test.v3
-rw-r--r--tests/hana/test_simulation_vlib.v (renamed from tests/hana/test_simulation_always_31_tt.v)17
-rw-r--r--tests/hana/test_simulation_xnor.v20
-rw-r--r--tests/hana/test_simulation_xnor_1_test.v3
-rw-r--r--tests/hana/test_simulation_xnor_2_test.v3
-rw-r--r--tests/hana/test_simulation_xnor_3_test.v3
-rw-r--r--tests/hana/test_simulation_xnor_4_test.v3
-rw-r--r--tests/hana/test_simulation_xor.v20
-rw-r--r--tests/hana/test_simulation_xor_1_test.v3
-rw-r--r--tests/hana/test_simulation_xor_2_test.v3
-rw-r--r--tests/hana/test_simulation_xor_3_test.v3
-rw-r--r--tests/hana/test_simulation_xor_4_test.v3
-rw-r--r--tests/memories/.gitignore3
-rw-r--r--tests/memories/amber23_sram_byte_en.v84
-rw-r--r--tests/memories/implicit_en.v24
-rw-r--r--tests/memories/no_implicit_en.v24
-rwxr-xr-xtests/memories/run-test.sh19
-rw-r--r--tests/memories/shared_ports.v25
-rw-r--r--tests/memories/simple_sram_byte_en.v26
-rw-r--r--tests/realmath/.gitignore1
-rw-r--r--tests/realmath/generate.py91
-rwxr-xr-xtests/realmath/run-test.sh24
-rw-r--r--tests/sat/asserts.ys2
-rw-r--r--tests/sat/asserts_seq.ys2
-rw-r--r--tests/sat/initval.v15
-rw-r--r--tests/sat/initval.ys4
-rw-r--r--tests/sat/share.v32
-rw-r--r--tests/sat/share.ys17
-rw-r--r--tests/share/.gitignore1
-rw-r--r--tests/share/generate.py73
-rwxr-xr-xtests/share/run-test.sh27
-rw-r--r--tests/simple/arraycells.v15
-rw-r--r--tests/simple/forgen01.v3
-rw-r--r--tests/simple/fsm.v2
-rw-r--r--tests/simple/generate.v6
-rw-r--r--tests/simple/i2c_master_tests.v4
-rw-r--r--tests/simple/macros.v7
-rw-r--r--tests/simple/mem2reg.v16
-rw-r--r--tests/simple/mem_arst.v2
-rw-r--r--tests/simple/memory.v101
-rw-r--r--tests/simple/operators.v2
-rw-r--r--tests/simple/paramods.v6
-rw-r--r--tests/simple/partsel.v59
-rw-r--r--tests/simple/realexpr.v24
-rw-r--r--tests/simple/repwhile.v36
-rwxr-xr-xtests/simple/run-test.sh3
-rw-r--r--tests/simple/scopes.v63
-rw-r--r--tests/simple/signedexpr.v2
-rw-r--r--tests/simple/task_func.v15
-rw-r--r--tests/simple/undef_eqx_nex.v2
-rw-r--r--tests/simple/usb_phy_tests.v (renamed from tests/simple/usb_phy_tetsts.v)2
-rw-r--r--tests/techmap/.gitignore1
-rw-r--r--tests/techmap/mem_simple_4x1_cells.v13
-rw-r--r--tests/techmap/mem_simple_4x1_map.v140
-rw-r--r--tests/techmap/mem_simple_4x1_runtest.sh17
-rw-r--r--tests/techmap/mem_simple_4x1_tb.v29
-rw-r--r--tests/techmap/mem_simple_4x1_uut.v15
-rwxr-xr-xtests/techmap/run-test.sh10
-rw-r--r--tests/tools/autotest.mk8
-rwxr-xr-xtests/tools/autotest.sh65
-rwxr-xr-xtests/tools/txt2tikztiming.py109
-rwxr-xr-xtests/tools/vcd2txt.pl61
-rw-r--r--tests/various/.gitignore1
-rw-r--r--tests/various/constmsk_test.v4
-rw-r--r--tests/various/constmsk_test.ys15
-rw-r--r--tests/various/constmsk_testmap.v49
-rwxr-xr-xtests/various/run-test.sh6
-rw-r--r--tests/various/submod_extract.ys21
-rw-r--r--tests/vloghtb/.gitignore9
-rw-r--r--tests/vloghtb/common.sh70
-rwxr-xr-xtests/vloghtb/run-test.sh15
-rw-r--r--tests/vloghtb/test_makefile9
-rw-r--r--tests/vloghtb/test_mapopt.sh17
-rw-r--r--tests/vloghtb/test_share.sh11
513 files changed, 34829 insertions, 12050 deletions
diff --git a/.gitignore b/.gitignore
index f251d2b6..803e1302 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
.*.swp
/.cproject
/.project
+/.settings
/qtcreator.files
/qtcreator.includes
/qtcreator.config
@@ -14,6 +15,5 @@
/yosys-abc
/yosys-config
/yosys-filterlib
-/yosys-svgviewer
/kernel/version_*.cc
/share
diff --git a/CHANGELOG b/CHANGELOG
index fa2c9b08..35695729 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,45 +1,184 @@
-List of incompatible changes and major milestones between releases
-==================================================================
+List of changes and major improvements between releases
+=======================================================
-Yosys 0.1.0 .. Yoys 0.1.0+
+Yosys 0.3.0 .. Yoys 0.3.0+
--------------------------
+ ... TBD ...
+
+
+Yosys 0.2.0 .. Yoys 0.3.0
+--------------------------
+
+ * Driver program and overall behavior:
+ - Added "design -push" and "design -pop"
+ - Added "tee" command for redirecting log output
+
+ * Changes in the internal cell library:
+ - Added $dlatchsr and $_DLATCHSR_???_ cell types
+
+ * Improvements in Verilog frontend:
+ - Improved support for const functions (case, always, repeat)
+ - The generate..endgenerate keywords are now optional
+ - Added support for arrays of module instances
+ - Added support for "`default_nettype" directive
+ - Added support for "`line" directive
+
+ * Other front- and back-ends:
+ - Various changes to "write_blif" options
+ - Various improvements in EDIF backend
+ - Added "vhdl2verilog" pseudo-front-end
+ - Added "verific" pseudo-front-end
+
+ * Improvements in technology mapping:
+ - Added support for recursive techmap
+ - Added CONSTMSK and CONSTVAL features to techmap
+ - Added _TECHMAP_CONNMAP_*_ feature to techmap
+ - Added _TECHMAP_REPLACE_ feature to techmap
+ - Added "connwrappers" command for wrap-extract-unwrap method
+ - Added "extract -map %<design_name>" feature
+ - Added "extract -ignore_param ..." and "extract -ignore_parameters"
+ - Added "techmap -max_iter" option
+
+ * Improvements to "eval" and "sat" framework:
+ - Now include a copy of Minisat (with build fixes applied)
+ - Switched to Minisat::SimpSolver as SAT back-end
+ - Added "sat -dump_vcd" feature
+ - Added "sat -dump_cnf" feature
+ - Added "sat -initsteps <N>" feature
+ - Added "freduce -stop <N>" feature
+ - Added "fredure -dump <prefix>" feature
+
+ * Integration with ABC:
+ - Updated ABC rev to 7600ffb9340c
+
+ * Improvements in the internal APIs:
+ - Added RTLIL::Module::add... helper methods
+ - Various build fixes for OSX (Darwin) and OpenBSD
+
+
+Yosys 0.1.0 .. Yoys 0.2.0
+-------------------------
+
+ * Changes to the driver program:
+ - Added "yosys -h" and "yosys -H"
+ - Added support for backslash line continuation in scripts
+ - Added support for #-comments in same line as command
+ - Added "echo" and "log" commands
+
* Improvements in Verilog frontend:
- Added support for local registers in named blocks
- Added support for "case" in "generate" blocks
- Added support for $clog2 system function
+ - Added support for basic SystemVerilog assert statements
- Added preprocessor support for macro arguments
- Added preprocessor support for `elsif statement
+ - Added "verilog_defaults" command
+ - Added read_verilog -icells option
+ - Added support for constant sizes from parameters
+ - Added "read_verilog -setattr"
+ - Added support for function returning 'integer'
+ - Added limited support for function calls in parameter values
+ - Added "read_verilog -defer" to suppress evaluation of modules with default parameters
+
+ * Other front- and back-ends:
+ - Added BTOR backend
+ - Added Liberty frontend
* Improvements in technology mapping:
- The "dfflibmap" command now strongly prefers solutions with
no inverters in clock paths
- The "dfflibmap" command now prefers cells with smaller area
+ - Added support for multiple -map options to techmap
+ - Added "dfflibmap" support for //-comments in liberty files
+ - Added "memory_unpack" command to revert "memory_collect"
+ - Added standard techmap rule "techmap -share_map pmux2mux.v"
+ - Added "iopadmap -bits"
+ - Added "setundef" command
+ - Added "hilomap" command
+
+ * Changes in the internal cell library:
+ - Major rewrite of simlib.v for better compatibility with other tools
+ - Added PRIORITY parameter to $memwr cells
+ - Added TRANSPARENT parameter to $memrd cells
+ - Added RD_TRANSPARENT parameter to $mem cells
+ - Added $bu0 cell (always 0-extend, even undef MSB)
+ - Added $assert cell type
+ - Added $slice and $concat cell types
* Integration with ABC:
- - Updated ABC to hg rev 57517e81666b
+ - Updated ABC to hg rev 2058c8ccea68
- Tighter integration of ABC build with Yosys build. The make
targets 'make abc' and 'make install-abc' are now obsolete.
- Added support for passing FFs from one clock domain through ABC
- Now always use BLIF as exchange format with ABC
+ - Added support for "abc -script +<command_sequence>"
+ - Improved standard ABC recipe
+ - Added support for "keep" attribute to abc command
+ - Added "abc -dff / -clk / -keepff" options
* Improvements to "eval" and "sat" framework:
- Added support for "0" and "~0" in right-hand side -set expressions
- Added "eval -set-undef" and "eval -table"
- - Added "sat -set-init" support for sequential problems
+ - Added "sat -set-init" and "sat -set-init-*" for sequential problems
- Added undef support to SAT solver, incl. various new "sat" options
- Added correct support for === and !== for "eval" and "sat"
+ - Added "sat -tempinduct" (default -seq is now non-induction sequential)
+ - Added "sat -prove-asserts"
+ - Complete rewrite of the 'freduce' command
+ - Added "miter" command
+ - Added "sat -show-inputs" and "sat -show-outputs"
+ - Added "sat -ignore_unknown_cells" (now produce an error by default)
+ - Added "sat -falsify"
+ - Now "sat -verify" and "sat -falsify" can also be used without "-prove"
+ - Added "expose" command
+ - Added support for @<sel_name> to sat and eval signal expressions
+
+ * Changes in the 'make test' framework and auxilary test tools:
+ - Added autotest.sh -p and -f options
+ - Replaced autotest.sh ISIM support with XSIM support
+ - Added test cases for SAT framework
* Added "abbreviated IDs":
- Now $<something>$foo can be abbriviated as $foo.
- Usually this last part is a unique id (from RTLIL::autoidx)
- This abbreviated IDs are now also used in "show" output
+ * Other changes to selection framework:
+ - Now */ is optional in */<mode>:<arg> expressions
+ - Added "select -assert-none" and "select -assert-any"
+ - Added support for matching modules by attribute (A:<expr>)
+ - Added "select -none"
+ - Added support for r:<expr> pattern for matching cell parameters
+ - Added support for !=, <, <=, >=, > for attribute and parameter matching
+ - Added support for %s for selecting sub-modules
+ - Added support for %m for expanding selections to whole modules
+ - Added support for i:*, o:* and x:* pattern for selecting module ports
+ - Added support for s:<expr> pattern for matching wire width
+ - Added support for %a operation to select wire aliases
+
* Various other changes to commands and options:
- The "ls" command now supports wildcards
- Added "show -pause" and "show -format dot"
+ - Added "show -color" support for cells
+ - Added "show -label" and "show -notitle"
- Added "dump -m" and "dump -n"
- Added "history" command
+ - Added "rename -hide"
+ - Added "connect" command
+ - Added "splitnets -driver"
+ - Added "opt_const -mux_undef"
+ - Added "opt_const -mux_bool"
+ - Added "opt_const -undriven"
+ - Added "opt -mux_undef -mux_bool -undriven -purge"
+ - Added "hierarchy -libdir"
+ - Added "hierarchy -purge_lib" (by default now do not remove lib cells)
+ - Added "delete" command
+ - Added "dump -append"
+ - Added "setattr" and "setparam" commands
+ - Added "design -stash/-copy-from/-copy-to"
+ - Added "copy" command
+ - Added "splice" command
diff --git a/CodingReadme b/CodingReadme
new file mode 100644
index 00000000..8f515e1f
--- /dev/null
+++ b/CodingReadme
@@ -0,0 +1,194 @@
+
+
+Getting Started
+===============
+
+
+Reading List
+------------
+
+To write Yosys C++ code you need to know at least the following classes in kernel/rtlil.h:
+
+ RTLIL::Wire
+ RTLIL::Cell
+ RTLIL::Module
+ RTLIL::SigSpec
+
+The following yosys commands are a good starting point if you are looking for examples
+of how to use the Yosys API:
+
+ passes/opt/wreduce.cc
+ passes/techmap/maccmap.cc
+
+
+Notes on the existing codebase
+------------------------------
+
+For historical reasons not all parts of Yosys adhere to the current coding
+styles. When adding code to existing parts of the system, adhere to this guide
+for the new code instead of trying to mimic the style of the surrounding code.
+
+
+
+Coding Style
+============
+
+
+Formatting of code
+------------------
+
+- Yosys code is using tabs for indentation. Tabs are 8 characters.
+
+- A continuation of a statement in the following line is indented by
+ two additional tabs.
+
+- Lines are as long as you want them to be. A good rule of thumb is
+ to break lines at about column 150.
+
+- Opening braces can be put on the same or next line as the statement
+ opening the block (if, switch, for, while, do). Put the opening brace
+ on its own line for larger blocks, especially blocks that contains
+ blank lines.
+
+- Otherwise stick to the Linux Kernel Coding Stlye:
+ https://www.kernel.org/doc/Documentation/CodingStyle
+
+
+C++ Langugage
+-------------
+
+Yosys is written in C++11. At the moment only constructs supported by
+gcc 4.6 is allowed in Yosys code. This will change in future releases.
+
+In general Yosys uses "int" instead of "size_t". To avoid compiler
+warnings for implicit type casts, always use "SIZE(foobar)" instead
+of "foobar.size()". (the macro SIZE() is defined by kernel/yosys.h)
+
+Use range-based for loops whenever applicable.
+
+
+
+Checklist for adding internal cell types
+========================================
+
+Things to do right away:
+
+ - Add to kernel/celltypes.h (incl. eval() handling for non-mem cells)
+ - Add to InternalCellChecker::check() in kernel/rtlil.cc
+ - Add to techlibs/common/simlib.v
+ - Add to techlibs/common/techmap.v
+
+Things to do after finalizing the cell interface:
+
+ - Add support to kernel/satgen.h for the new cell type
+ - Add to manual/CHAPTER_CellLib.tex (or just add a fixme to the bottom)
+ - Maybe add support to the verilog backend for dumping such cells as expression
+
+
+
+Checklist for creating Yosys releases
+=====================================
+
+Update the CHANGELOG file:
+
+ cd ~yosys
+ gitk &
+ vi CHANGELOG
+
+
+Run all tests with "make config-{clang-debug,gcc-debug,gcc-4.6,release}":
+
+ cd ~yosys
+ make clean
+ make test vloghtb
+ make install
+
+ cd ~yosys-bigsim
+ make clean
+ make full
+
+ cd ~vloghammer
+ make purge
+ make gen_issues gen_samples
+ make SYN_LIST="yosys" SIM_LIST="icarus yosim verilator" FULL=1 world
+ chromium-browser report.html
+
+
+Then with default config setting:
+
+ cd ~yosys
+ ./yosys -p 'proc; show' tests/simple/fiedler-cooley.v
+ ./yosys -p 'proc; opt; show' tests/simple/fiedler-cooley.v
+
+ cd ~yosys
+ make manual
+ - sanity check the figures in the appnotes and presentation
+ - if there are any odd things -> investigate
+ - make cosmetic changes to the .tex files if necessary
+
+
+Also with default config setting:
+
+ cd ~yosys/techlibs/cmos
+ bash testbench.sh
+
+ cd ~yosys/techlibs/xilinx/example_sim_counter
+ bash run_sim.sh
+
+ cd ~yosys/techlibs/xilinx/example_mojo_counter
+ bash example.sh
+
+
+Finally if a current verific library is available:
+
+ cd ~yosys
+ cat frontends/verific/build_amd64.txt
+ - follow instructions
+
+ cd frontends/verific
+ ../../yosys test_navre.ys
+
+
+Release candiate:
+
+ - create branch yosys-x.y.z-rc and push to github
+ - contact the usual suspects per mail and ask them to test
+ - post on the reddit and ask people to test
+ - commit KISS fixes to the -rc branch if necessary
+
+
+Release:
+
+ - set YOSYS_VER to x.y.z in Makefile
+ - update version string in CHANGELOG
+ git commit -am "Yosys x.y.z"
+
+ - push tag to github
+ - post changelog on github
+ - post short release note on reddit
+ - delete -rc branch from github
+
+
+Updating the website:
+
+ cd ~yosys
+ make manual
+ make install
+
+ - update pdf files on the website
+
+ cd ~yosys-web
+ make update_cmd
+ make update_show
+ git commit -am update
+ make push
+
+
+In master branch:
+
+ git merge {release-tag}
+ - set version to x.y.z+ in Makefile
+ - add section "Yosys x.y.z .. x.y.z+" to CHANGELOG
+ git commit --amend -am "Yosys x.y.z+"
+
+
diff --git a/Makefile b/Makefile
index 697cf69f..5a75320c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,15 @@
-CONFIG := clang-debug
-# CONFIG := gcc-debug
-# CONFIG := release
+CONFIG := clang
+# CONFIG := gcc
+# CONFIG := gcc-4.6
+# CONFIG := emcc
# features (the more the better)
ENABLE_TCL := 1
-ENABLE_QT4 := 1
-ENABLE_MINISAT := 1
ENABLE_ABC := 1
+ENABLE_PLUGINS := 1
+ENABLE_READLINE := 1
+ENABLE_VERIFIC := 0
# other configuration flags
ENABLE_GPROF := 0
@@ -20,15 +22,30 @@ GENFILES =
EXTRA_TARGETS =
TARGETS = yosys yosys-config
+PRETTY = 1
+SMALL = 0
+
all: top-all
-CXXFLAGS = -Wall -Wextra -ggdb -I"$(shell pwd)" -MD -D_YOSYS_ -fPIC
-LDFLAGS = -rdynamic
-LDLIBS = -lstdc++ -lreadline -lm -ldl -lrt
+CXXFLAGS = -Wall -Wextra -ggdb -I"$(shell pwd)" -MD -DYOSYS_SRC='"$(shell pwd)"' -D_YOSYS_ -fPIC -I${DESTDIR}/include
+LDFLAGS = -L${DESTDIR}/lib
+LDLIBS = -lstdc++ -lm
QMAKE = qmake-qt4
+SED = sed
+
+ifeq (Darwin,$(findstring Darwin,$(shell uname)))
+ # add macports include and library path to search directories, don't use '-rdynamic' and '-lrt':
+ CXXFLAGS += -I/opt/local/include
+ LDFLAGS += -L/opt/local/lib
+ QMAKE = qmake
+ SED = gsed
+else
+ LDFLAGS += -rdynamic
+ LDLIBS += -lrt
+endif
-YOSYS_VER := 0.1.0+
-GIT_REV := $(shell git rev-parse --short HEAD || echo UNKOWN)
+YOSYS_VER := 0.3.0+$(shell test -d .git && { git log --author=clifford@clifford.at --oneline ca125bf41.. | wc -l; })
+GIT_REV := $(shell git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
OBJS = kernel/version_$(GIT_REV).o
# set 'ABCREV = default' to use abc/ as it is
@@ -37,108 +54,214 @@ 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 = 10cc13a2a0f1
+ABCREV = 4d547a5e065b
ABCPULL = 1
--include Makefile.conf
+define newline
+
+
+endef
+
+ifneq ($(wildcard Makefile.conf),)
+$(info $(subst $$--$$,$(newline),$(shell sed 's,^,[Makefile.conf] ,; s,$$,$$--$$,;' < Makefile.conf | tr -d '\n' | sed 's,\$$--\$$$$,,')))
+include Makefile.conf
+endif
-ifeq ($(CONFIG),clang-debug)
+ifeq ($(CONFIG),clang)
CXX = clang
CXXFLAGS += -std=c++11 -Os
-endif
-ifeq ($(CONFIG),gcc-debug)
+else ifeq ($(CONFIG),gcc)
CXX = gcc
CXXFLAGS += -std=gnu++0x -Os
+
+else ifeq ($(CONFIG),gcc-4.6)
+CXX = gcc-4.6
+CXXFLAGS += -std=gnu++0x -Os
+
+else ifeq ($(CONFIG),emcc)
+CXX = emcc
+CXXFLAGS += -std=c++11 -Os -Wno-warn-absolute-paths
+CXXFLAGS := $(filter-out -ggdb,$(CXXFLAGS))
+
+else ifneq ($(CONFIG),none)
+$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.6, emcc, none)
endif
-ifeq ($(CONFIG),release)
-CXX = gcc
-CXXFLAGS += -std=gnu++0x -march=native -O3 -DNDEBUG
+ifeq ($(ENABLE_READLINE),1)
+CXXFLAGS += -DYOSYS_ENABLE_READLINE
+LDLIBS += -lreadline
+endif
+
+ifeq ($(ENABLE_PLUGINS),1)
+CXXFLAGS += -DYOSYS_ENABLE_PLUGINS $(shell pkg-config --silence-errors --cflags libffi)
+LDLIBS += $(shell pkg-config --silence-errors --libs libffi || echo -lffi) -ldl
endif
ifeq ($(ENABLE_TCL),1)
-CXXFLAGS += -I/usr/include/tcl8.5 -DYOSYS_ENABLE_TCL
-LDLIBS += -ltcl8.5
+TCL_VERSION ?= tcl8.5
+TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
+CXXFLAGS += -I$(TCL_INCLUDE) -DYOSYS_ENABLE_TCL
+LDLIBS += -l$(TCL_VERSION)
endif
ifeq ($(ENABLE_GPROF),1)
-CXXFLAGS += -pg -fno-inline
+CXXFLAGS += -pg
LDFLAGS += -pg
endif
-ifeq ($(ENABLE_QT4),1)
-TARGETS += yosys-svgviewer
-endif
-
ifeq ($(ENABLE_ABC),1)
+CXXFLAGS += -DYOSYS_ENABLE_ABC
TARGETS += yosys-abc
endif
-OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o
+ifeq ($(ENABLE_VERIFIC),1)
+VERIFIC_DIR ?= /usr/local/src/verific_lib_eval
+VERIFIC_COMPONENTS ?= verilog vhdl database util containers
+CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC
+LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS))
+endif
+
+ifeq ($(PRETTY), 1)
+P_STATUS = 0
+P_OFFSET = 0
+P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys | gawk 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
+P_SHOW = [$(shell gawk "BEGIN { N=$(words $(OBJS) yosys); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
+P = @echo "$(if $(findstring $@,$(TARGETS) $(EXTRA_TARGETS)),$(eval P_OFFSET = 10))$(call P_UPDATE)$(call P_SHOW) Building $@";
+Q = @
+S = -s
+else
+P_SHOW = ->
+P =
+Q =
+S =
+endif
+
+OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o
OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o
OBJS += libs/bigint/BigUnsigned.o libs/bigint/BigUnsignedInABase.o
OBJS += libs/sha1/sha1.o
+
+ifneq ($(SMALL),1)
+
OBJS += libs/subcircuit/subcircuit.o
-OBJS += libs/ezsat/ezsat.o
-ifeq ($(ENABLE_MINISAT),1)
-CXXFLAGS += -DYOSYS_ENABLE_MINISAT
+OBJS += libs/ezsat/ezsat.o
OBJS += libs/ezsat/ezminisat.o
-LDLIBS += -lminisat
-endif
+
+OBJS += libs/minisat/Options.o
+OBJS += libs/minisat/SimpSolver.o
+OBJS += libs/minisat/Solver.o
+OBJS += libs/minisat/System.o
include frontends/*/Makefile.inc
include passes/*/Makefile.inc
include backends/*/Makefile.inc
include techlibs/*/Makefile.inc
+else
+
+include frontends/verilog/Makefile.inc
+include frontends/ilang/Makefile.inc
+include frontends/ast/Makefile.inc
+
+OBJS += passes/hierarchy/hierarchy.o
+OBJS += passes/cmds/select.o
+OBJS += passes/cmds/show.o
+OBJS += passes/cmds/stat.o
+OBJS += passes/cmds/cover.o
+OBJS += passes/cmds/design.o
+OBJS += passes/cmds/plugin.o
+
+include passes/proc/Makefile.inc
+include passes/opt/Makefile.inc
+include passes/techmap/Makefile.inc
+include passes/abc/Makefile.inc
+
+include backends/verilog/Makefile.inc
+include backends/ilang/Makefile.inc
+
+include techlibs/common/Makefile.inc
+
+endif
+
top-all: $(TARGETS) $(EXTRA_TARGETS)
+ @echo ""
+ @echo " Build successful."
+ @echo ""
yosys: $(OBJS)
- $(CXX) -o yosys $(LDFLAGS) $(OBJS) $(LDLIBS)
+ $(P) $(CXX) -o yosys $(LDFLAGS) $(OBJS) $(LDLIBS)
+
+%.o: %.cc
+ $(P) $(CXX) -o $@ -c $(CXXFLAGS) $<
+
+%.o: %.cpp
+ $(P) $(CXX) -o $@ -c $(CXXFLAGS) $<
kernel/version_$(GIT_REV).cc: Makefile
- rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc
- echo "extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys $(YOSYS_VER) (git sha1 $(GIT_REV))\";" > kernel/version_$(GIT_REV).cc
+ $(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc
+ $(Q) echo "extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys $(YOSYS_VER) (git sha1 $(GIT_REV), $(CXX) ` \
+ $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1` $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)))\";" > kernel/version_$(GIT_REV).cc
yosys-config: yosys-config.in
- sed -e 's,@CXX@,$(CXX),;' -e 's,@CXXFLAGS@,$(CXXFLAGS),;' -e 's,@LDFLAGS@,$(LDFLAGS),;' -e 's,@LDLIBS@,$(LDLIBS),;' \
+ $(P) $(SED) -e 's,@CXX@,$(CXX),;' -e 's,@CXXFLAGS@,$(CXXFLAGS),;' -e 's,@LDFLAGS@,$(LDFLAGS),;' -e 's,@LDLIBS@,$(LDLIBS),;' \
-e 's,@BINDIR@,$(DESTDIR)/bin,;' -e 's,@DATDIR@,$(DESTDIR)/share/yosys,;' < yosys-config.in > yosys-config
- chmod +x yosys-config
-
-yosys-svgviewer: libs/svgviewer/*.h libs/svgviewer/*.cpp
- cd libs/svgviewer && $(QMAKE) && make
- cp libs/svgviewer/svgviewer yosys-svgviewer
+ $(Q) chmod +x yosys-config
abc/abc-$(ABCREV):
+ $(P)
ifneq ($(ABCREV),default)
- if ( cd abc && hg identify; ) | grep -q +; then \
+ $(Q) if ( cd abc 2> /dev/null && hg identify; ) | grep -q +; then \
echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
fi
- if test "`cd abc && hg identify | cut -f1 -d' '`" != "$(ABCREV)"; then \
+ $(Q) if test "`cd abc 2> /dev/null && hg identify | cut -f1 -d' '`" != "$(ABCREV)"; then \
test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \
+ echo "Pulling ABC from bitbucket.org:"; \
test -d abc || hg clone https://bitbucket.org/alanmi/abc abc; \
cd abc && hg pull && hg update -r $(ABCREV); \
fi
endif
- rm -f abc/abc-[0-9a-f]*
- cd abc && $(MAKE) PROG="abc-$(ABCREV)" MSG_PREFIX="YOSYS-ABC: "
+ $(Q) rm -f abc/abc-[0-9a-f]*
+ $(Q) cd abc && $(MAKE) $(S) PROG="abc-$(ABCREV)" MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: "
ifeq ($(ABCREV),default)
.PHONY: abc/abc-$(ABCREV)
endif
yosys-abc: abc/abc-$(ABCREV)
- cp abc/abc-$(ABCREV) yosys-abc
-
-test: yosys
- cd tests/simple && bash run-test.sh
- cd tests/hana && bash run-test.sh
- cd tests/asicworld && bash run-test.sh
- cd tests/sat && bash run-test.sh
+ $(P) cp abc/abc-$(ABCREV) yosys-abc
+
+test: $(TARGETS) $(EXTRA_TARGETS)
+ +cd tests/simple && bash run-test.sh
+ +cd tests/hana && bash run-test.sh
+ +cd tests/asicworld && bash run-test.sh
+ +cd tests/realmath && bash run-test.sh
+ +cd tests/share && bash run-test.sh
+ +cd tests/fsm && bash run-test.sh
+ +cd tests/techmap && bash run-test.sh
+ +cd tests/memories && bash run-test.sh
+ +cd tests/various && bash run-test.sh
+ +cd tests/sat && bash run-test.sh
+ @echo ""
+ @echo " Passed \"make test\"."
+ @echo ""
+
+VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all
+
+vgtest: $(TARGETS) $(EXTRA_TARGETS)
+ $(VALGRIND) ./yosys -p 'setattr -mod -unset top; hierarchy; proc; opt; memory -nomap; opt -fine; techmap; opt' $$( ls tests/simple/*.v | grep -v repwhile.v )
+ @echo ""
+ @echo " Passed \"make vgtest\"."
+ @echo ""
+
+vloghtb: $(TARGETS) $(EXTRA_TARGETS)
+ +cd tests/vloghtb && bash run-test.sh
+ @echo ""
+ @echo " Passed \"make vloghtb\"."
+ @echo ""
install: $(TARGETS) $(EXTRA_TARGETS)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)/bin
@@ -152,12 +275,15 @@ manual: $(TARGETS) $(EXTRA_TARGETS)
cd manual && bash manual.sh
clean:
- rm -rvf share
+ rm -rf share
cd manual && bash clean.sh
- rm -vf $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS)
- rm -vf kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]*
- rm -vf libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d
- test ! -f libs/svgviewer/Makefile || make -C libs/svgviewer distclean
+ rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS)
+ rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]*
+ rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d
+
+clean-abc:
+ make -C abc clean
+ rm -f yosys-abc abc/abc-[0-9a-f]*
mrproper: clean
git clean -xdf
@@ -172,17 +298,24 @@ qtcreator:
config-clean: clean
rm -f Makefile.conf
-config-clang-debug: clean
- echo 'CONFIG := clang-debug' > Makefile.conf
+config-clang: clean
+ echo 'CONFIG := clang' > Makefile.conf
+
+config-gcc: clean
+ echo 'CONFIG := gcc' > Makefile.conf
-config-gcc-debug: clean
- echo 'CONFIG := gcc-debug' > Makefile.conf
+config-gcc-4.6: clean
+ echo 'CONFIG := gcc-4.6' > Makefile.conf
-config-release: clean
- echo 'CONFIG := release' > Makefile.conf
+config-emcc: clean
+ echo 'CONFIG := emcc' > Makefile.conf
+ echo 'ENABLE_TCL := 0' >> Makefile.conf
+ echo 'ENABLE_ABC := 0' >> Makefile.conf
+ echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
+ echo 'ENABLE_READLINE := 0' >> Makefile.conf
config-gprof: clean
- echo 'CONFIG := gcc-debug' > Makefile.conf
+ echo 'CONFIG := gcc' > Makefile.conf
echo 'ENABLE_GPROF := 1' >> Makefile.conf
config-sudo:
@@ -196,5 +329,5 @@ config-sudo:
-include techlibs/*/*.d
.PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator
-.PHONY: config-clean config-clang-debug config-gcc-debug config-release
+.PHONY: config-clean config-clang config-gcc config-gcc-4.6 config-gprof config-sudo
diff --git a/README b/README
index 385ee2c0..d7f5aaa4 100644
--- a/README
+++ b/README
@@ -50,39 +50,31 @@ Getting Started
You need a C++ compiler with C++11 support (up-to-date CLANG or GCC is
recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make.
-The Qt4 library is needed for the yosys SVG viewer, that is used to display
-schematics, the minisat library is required for the SAT features in yosys
-and TCL for the scripting functionality. The extensive test suite requires
-Icarus Verilog. For example on Ubuntu Linux 12.04 LTS the following commands
-will install all prerequisites for building yosys:
-
- $ sudo apt-get install git
- $ sudo apt-get install g++
- $ sudo apt-get install clang
- $ sudo apt-get install make
- $ sudo apt-get install bison
- $ sudo apt-get install flex
- $ sudo apt-get install libreadline-dev
- $ sudo apt-get install tcl8.5-dev
- $ sudo apt-get install minisat
- $ sudo apt-get install zlib1g-dev
- $ sudo apt-get install libqt4-dev
- $ sudo apt-get install mercurial
- $ sudo apt-get install iverilog
- $ sudo apt-get install graphviz
-
-To configure the build system to use a specific set of compiler and
-build configuration, use one of
-
- $ make config-clang-debug
- $ make config-gcc-debug
- $ make config-release
+TCL, readline and libffi are optional (see ENABLE_* settings in Makefile).
+Xdot (graphviz) is used by the "show" command in yosys to display schematics.
+For example on Ubuntu Linux 14.04 LTS the following commands will install all
+prerequisites for building yosys:
+
+ $ yosys_deps="build-essential clang bison flex libreadline-dev
+ tcl8.5-dev libffi-dev git mercurial graphviz xdot"
+ $ sudo apt-get install $yosys_deps
+
+There are also pre-compiled packages for Yosys on Ubuntu. Visit the Yosys
+download page to learn more about this:
+
+ http://www.clifford.at/yosys/download.html
+
+To configure the build system to use a specific compiler, use one of
+
+ $ make config-clang
+ $ make config-gcc
For other compilers and build configurations it might be
necessary to make some changes to the config section of the
Makefile.
- $ vi Makefile
+ $ vi Makefile ..or..
+ $ vi Makefile.conf
To build Yosys simply type 'make' in this directory.
@@ -90,9 +82,6 @@ To build Yosys simply type 'make' in this directory.
$ make test
$ sudo make install
-If you encounter any problems during build, make sure to check the section
-"Workarounds for known build problems" at the end of this README file.
-
Note that this also downloads, builds and installs ABC (using yosys-abc
as executeable name).
@@ -116,12 +105,16 @@ writing the design to the console in yosys's internal format:
yosys> write_ilang
+elaborate design hierarchy:
+
+ yosys> hierarchy
+
convert processes ("always" blocks) to netlist elements and perform
some simple optimizations:
yosys> proc; opt
-display design netlist using the yosys svg viewer:
+display design netlist using xdot:
yosys> show
@@ -139,13 +132,14 @@ write design netlist to a new verilog file:
a similar synthesis can be performed using yosys command line options only:
- $ ./yosys -o synth.v -p proc -p opt -p techmap -p opt tests/simple/fiedler-cooley.v
+ $ ./yosys -o synth.v -p hierarchy -p proc -p opt \
+ -p techmap -p opt tests/simple/fiedler-cooley.v
or using a simple synthesis script:
$ cat synth.ys
read_verilog tests/simple/fiedler-cooley.v
- proc; opt; techmap; opt
+ hierarchy; proc; opt; techmap; opt
write_verilog synth.v
$ ./yosys synth.ys
@@ -154,21 +148,24 @@ It is also possible to only have the synthesis commands but not the read/write
commands in the synthesis script:
$ cat synth.ys
- proc; opt; techmap; opt
+ hierarchy; proc; opt; techmap; opt
$ ./yosys -o synth.v tests/simple/fiedler-cooley.v synth.ys
-The following synthesis script works reasonable for all designs:
+The following very basic synthesis script should work well with all designs:
# check design hierarchy
hierarchy
- # translate processes (always blocks) and memories (arrays)
- proc; memory; opt
+ # translate processes (always blocks)
+ proc; opt
# detect and optimize FSM encodings
fsm; opt
+ # implement memories (arrays)
+ memory; opt
+
# convert to gate logic
techmap; opt
@@ -177,7 +174,7 @@ in the liberty file mycells.lib, the following synthesis script will synthesize
for the given cell library:
# the high-level stuff
- hierarchy; proc; memory; opt; fsm; opt
+ hierarchy; proc; fsm; opt; memory; opt
# mapping to internal cell library
techmap; opt
@@ -194,6 +191,27 @@ for the given cell library:
If you do not have a liberty file but want to test this synthesis script,
you can use the file techlibs/cmos/cmos_cells.lib from the yosys sources.
+Various more complex liberty files (for testing) can be found here:
+
+ http://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/..
+ ../cadence/lib/tsmc025/signalstorm/osu025_stdcells.lib
+ ../cadence/lib/ami035/signalstorm/osu035_stdcells.lib
+ ../cadence/lib/tsmc018/signalstorm/osu018_stdcells.lib
+ ../cadence/lib/ami05/signalstorm/osu05_stdcells.lib
+
+The command "synth" provides a good default synthesis script (see "help synth").
+If possible a synthesis script should borrow from "synth". For example:
+
+ # the high-level stuff
+ hierarchy
+ synth -run coarse
+
+ # mapping to internal cells
+ techmap; opt -fast
+ dfflibmap -liberty mycells.lib
+ abc -liberty mycells.lib
+ clean
+
Yosys is under construction. A more detailed documentation will follow.
@@ -270,41 +288,83 @@ Verilog Attributes and non-standard features
for everything that comes after the {* ... *} statement. (Reset
by adding an empty {* *} statement.)
-- The "assert" statement from SystemVerilog is supported in its most basic
- form. In module context: "assert property (<expression>);" and within an
- always block: "assert(<expression>);". It is transformed to a $assert cell
- that is supported by the "sat" and "write_btor" commands.
+- Modules can be declared with "module mod_name(...);" (with three dots
+ instead of a list of moudle ports). With this syntax it is sufficient
+ to simply declare a module port as 'input' or 'output' in the module
+ body.
+
+- When defining a macro with `define, all text between tripple double quotes
+ is interpreted as macro body, even if it contains unescaped newlines. The
+ tripple double quotes are removed from the macro body. For example:
+
+ `define MY_MACRO(a, b) """
+ assign a = 23;
+ assign b = 42;
+ """
+
+- The attribute "via_celltype" can be used to implement a verilog task or
+ function by instantiating the specified cell type. The value is the name
+ of the cell type to use. For functions the name of the output port can
+ be specified by appending it to the cell type separated by a whitespace.
+ The body of the task or function is unused in this case and can be used
+ to specify a behavioral model of the cell type for simulation. For example:
+
+ module my_add3(A, B, C, Y);
+ parameter WIDTH = 8;
+ input [WIDTH-1:0] A, B, C;
+ output [WIDTH-1:0] Y;
+ ...
+ endmodule
+
+ module top;
+ ...
+ (* via_celltype = "my_add3 Y" *)
+ (* via_celltype_defparam_WIDTH = 32 *)
+ function [31:0] add3;
+ input [31:0] A, B, C;
+ begin
+ add3 = A + B + C;
+ end
+ endfunction
+ ...
+ endmodule
+
+- A limited subset of DPI-C functions is supported. The plugin mechanism
+ (see "help plugin") can be used load .so files with implementations of
+ DPI-C routines. As a non-standard extension it is possible to specify
+ a plugin alias using the "<alias>:" syntax. for example:
+
+ module dpitest;
+ import "DPI-C" function foo:round = real my_round (real);
+ parameter real r = my_round(12.345);
+ endmodule
+
+ $ 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 expresion is not a simple identifier, it
must be put in parentheses. Examples: WIDTH'd42, (4+2)'b101010
-Workarounds for known build problems
-====================================
-
-You might get an error message like this one during build when building with
-a recent version of gcc:
+Supported features from SystemVerilog
+=====================================
- /usr/include/minisat/utils/Options.h:285:29: error:
- unable to find string literal operator ‘operator"" PRIi64’
+When read_verilog is called with -sv, it accepts some language features
+from SystemVerilog:
-This is a bug in the minisat header. It can be fixed by adding spaces before
-and after each occurrence of PRIi64 in the header file:
+- The "assert" statement from SystemVerilog is supported in its most basic
+ form. In module context: "assert property (<expression>);" and within an
+ always block: "assert(<expression>);". It is transformed to a $assert cell
+ that is supported by the "sat" and "write_btor" commands.
- sudo sed -i 's/PRIi64/ & /' /usr/include/minisat/utils/Options.h
+- The keywords "always_comb", "always_ff" and "always_latch", "logic" and
+ "bit" are supported.
Roadmap / Large-scale TODOs
===========================
-- Verification and Regression Tests
- - VlogHammer: http://www.clifford.at/yosys/vloghammer.html
- - yosys-bigsim: https://github.com/cliffordwolf/yosys-bigsim
-
- Technology mapping for real-world applications
- - Add bit-wise const-folding via cell parameters to techmap pass
- - Rewrite current stdcells.v techmap rules (modular and clean)
- Improve Xilinx FGPA synthesis (RAMB, CARRY4, SLR, etc.)
- Implement SAT-based formal equivialence checker
@@ -321,7 +381,6 @@ Other Unsorted TODOs
- Implement missing Verilog 2005 features:
- - Multi-dimensional arrays
- Support for real (float) const. expressions and parameters
- ROM modeling using $readmemh/$readmemb in "initial" blocks
- Ignore what needs to be ignored (e.g. drive and charge strengths)
@@ -331,7 +390,4 @@ Other Unsorted TODOs
- Add brief source code documentation to most passes and kernel code
- Implement mux-to-tribuf pass and rebalance mixed mux/tribuf trees
- - Add more commands for changing the design (delete, add, modify objects)
- - Add full support for $lut cell type (const evaluation, sat solving, etc.)
- - Smarter resource sharing pass (add MUXes and get rid of duplicated cells)
diff --git a/backends/autotest/Makefile.inc b/backends/autotest/Makefile.inc
deleted file mode 100644
index 9308dcd4..00000000
--- a/backends/autotest/Makefile.inc
+++ /dev/null
@@ -1,3 +0,0 @@
-
-OBJS += backends/autotest/autotest.o
-
diff --git a/backends/autotest/autotest.cc b/backends/autotest/autotest.cc
deleted file mode 100644
index 3e2fab00..00000000
--- a/backends/autotest/autotest.cc
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-#include "kernel/register.h"
-#include "kernel/log.h"
-#include <stdlib.h>
-#include <stdio.h>
-
-#define NUM_ITER 1000
-
-static std::string id(std::string internal_id)
-{
- const char *str = internal_id.c_str();
- bool do_escape = false;
-
- if (*str == '\\')
- str++;
-
- if ('0' <= *str && *str <= '9')
- do_escape = true;
-
- for (int i = 0; str[i]; i++) {
- if ('0' <= str[i] && str[i] <= '9')
- continue;
- if ('a' <= str[i] && str[i] <= 'z')
- continue;
- if ('A' <= str[i] && str[i] <= 'Z')
- continue;
- if (str[i] == '_')
- continue;
- do_escape = true;
- break;
- }
-
- if (do_escape)
- return "\\" + std::string(str) + " ";
- return std::string(str);
-}
-
-static std::string idx(std::string str)
-{
- if (str[0] == '\\')
- return str.substr(1);
- return str;
-}
-
-static std::string idy(std::string str1, std::string str2 = std::string(), std::string str3 = std::string())
-{
- str1 = idx(str1);
- if (!str2.empty())
- str1 += "_" + idx(str2);
- if (!str3.empty())
- str1 += "_" + idx(str3);
- return id(str1);
-}
-
-static void autotest(FILE *f, RTLIL::Design *design)
-{
- fprintf(f, "module testbench;\n\n");
-
- fprintf(f, "integer i;\n\n");
-
- fprintf(f, "reg [31:0] xorshift128_x = 123456789;\n");
- fprintf(f, "reg [31:0] xorshift128_y = 362436069;\n");
- fprintf(f, "reg [31:0] xorshift128_z = 521288629;\n");
- fprintf(f, "reg [31:0] xorshift128_w = 88675123;\n");
- fprintf(f, "reg [31:0] xorshift128_t;\n\n");
- fprintf(f, "task xorshift128;\n");
- fprintf(f, "begin\n");
- fprintf(f, "\txorshift128_t = xorshift128_x ^ (xorshift128_x << 11);\n");
- fprintf(f, "\txorshift128_x = xorshift128_y;\n");
- fprintf(f, "\txorshift128_y = xorshift128_z;\n");
- fprintf(f, "\txorshift128_z = xorshift128_w;\n");
- fprintf(f, "\txorshift128_w = xorshift128_w ^ (xorshift128_w >> 19) ^ xorshift128_t ^ (xorshift128_t >> 8);\n");
- fprintf(f, "end\n");
- fprintf(f, "endtask\n\n");
-
- for (auto it = design->modules.begin(); it != design->modules.end(); it++)
- {
- std::map<std::string, int> signal_in;
- std::map<std::string, std::string> signal_const;
- std::map<std::string, int> signal_clk;
- std::map<std::string, int> signal_out;
-
- RTLIL::Module *mod = it->second;
-
- if (mod->get_bool_attribute("\\gentb_skip"))
- continue;
-
- int count_ports = 0;
- log("Generating test bench for module `%s'.\n", it->first.c_str());
- for (auto it2 = mod->wires.begin(); it2 != mod->wires.end(); it2++) {
- RTLIL::Wire *wire = it2->second;
- if (wire->port_output) {
- count_ports++;
- signal_out[idy("sig", mod->name, wire->name)] = wire->width;
- fprintf(f, "wire [%d:0] %s;\n", wire->width-1, idy("sig", mod->name, wire->name).c_str());
- } else if (wire->port_input) {
- count_ports++;
- bool is_clksignal = wire->get_bool_attribute("\\gentb_clock");
- for (auto it3 = mod->processes.begin(); it3 != mod->processes.end(); it3++)
- for (auto it4 = it3->second->syncs.begin(); it4 != it3->second->syncs.end(); it4++) {
- if ((*it4)->type == RTLIL::ST0 || (*it4)->type == RTLIL::ST1)
- continue;
- RTLIL::SigSpec &signal = (*it4)->signal;
- for (size_t i = 0; i < signal.chunks.size(); i++) {
- if (signal.chunks[i].wire == wire)
- is_clksignal = true;
- }
- }
- if (is_clksignal && wire->attributes.count("\\gentb_constant") == 0) {
- signal_clk[idy("sig", mod->name, wire->name)] = wire->width;
- } else {
- signal_in[idy("sig", mod->name, wire->name)] = wire->width;
- if (wire->attributes.count("\\gentb_constant") != 0)
- signal_const[idy("sig", mod->name, wire->name)] = wire->attributes["\\gentb_constant"].as_string();
- }
- fprintf(f, "reg [%d:0] %s;\n", wire->width-1, idy("sig", mod->name, wire->name).c_str());
- }
- }
- fprintf(f, "%s %s(\n", id(mod->name).c_str(), idy("uut", mod->name).c_str());
- for (auto it2 = mod->wires.begin(); it2 != mod->wires.end(); it2++) {
- RTLIL::Wire *wire = it2->second;
- if (wire->port_output || wire->port_input)
- fprintf(f, "\t.%s(%s)%s\n", id(wire->name).c_str(),
- idy("sig", mod->name, wire->name).c_str(), --count_ports ? "," : "");
- }
- fprintf(f, ");\n\n");
-
- fprintf(f, "task %s;\n", idy(mod->name, "reset").c_str());
- fprintf(f, "begin\n");
- int delay_counter = 0;
- for (auto it = signal_in.begin(); it != signal_in.end(); it++)
- fprintf(f, "\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
- for (auto it = signal_clk.begin(); it != signal_clk.end(); it++)
- fprintf(f, "\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
- for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
- fprintf(f, "\t#100; %s <= 1;\n", it->first.c_str());
- fprintf(f, "\t#100; %s <= 0;\n", it->first.c_str());
- }
- delay_counter = 0;
- for (auto it = signal_in.begin(); it != signal_in.end(); it++)
- fprintf(f, "\t%s <= #%d ~0;\n", it->first.c_str(), ++delay_counter*2);
- for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
- fprintf(f, "\t#100; %s <= 1;\n", it->first.c_str());
- fprintf(f, "\t#100; %s <= 0;\n", it->first.c_str());
- }
- delay_counter = 0;
- for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
- if (signal_const.count(it->first) == 0)
- continue;
- fprintf(f, "\t%s <= #%d 'b%s;\n", it->first.c_str(), ++delay_counter*2, signal_const[it->first].c_str());
- }
- fprintf(f, "end\n");
- fprintf(f, "endtask\n\n");
-
- fprintf(f, "task %s;\n", idy(mod->name, "update_data").c_str());
- fprintf(f, "begin\n");
- delay_counter = 0;
- for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
- if (signal_const.count(it->first) > 0)
- continue;
- fprintf(f, "\txorshift128;\n");
- fprintf(f, "\t%s <= #%d { xorshift128_x, xorshift128_y, xorshift128_z, xorshift128_w };\n", it->first.c_str(), ++delay_counter*2);
- }
- fprintf(f, "end\n");
- fprintf(f, "endtask\n\n");
-
- fprintf(f, "task %s;\n", idy(mod->name, "update_clock").c_str());
- fprintf(f, "begin\n");
- if (signal_clk.size()) {
- fprintf(f, "\txorshift128;\n");
- fprintf(f, "\t{");
- int total_clock_bits = 0;
- for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
- fprintf(f, "%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
- total_clock_bits += it->second;
- }
- fprintf(f, " } = {");
- for (auto it = signal_clk.begin(); it != signal_clk.end(); it++)
- fprintf(f, "%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
- fprintf(f, " } ^ (%d'b1 << (xorshift128_w %% %d));\n", total_clock_bits, total_clock_bits);
- }
- fprintf(f, "end\n");
- fprintf(f, "endtask\n\n");
-
- char shorthand = 'A';
- std::vector<std::string> header1;
- std::string header2 = "";
-
- fprintf(f, "task %s;\n", idy(mod->name, "print_status").c_str());
- fprintf(f, "begin\n");
- fprintf(f, "\t$display(\"#OUT# %%b %%b %%b %%t %%d\", {");
- if (signal_in.size())
- for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
- fprintf(f, "%s %s", it == signal_in.begin() ? "" : ",", it->first.c_str());
- int len = it->second;
- if (len > 1)
- header2 += "/", len--;
- while (len > 1)
- header2 += "-", len--;
- if (len > 0)
- header2 += shorthand, len--;
- header1.push_back(" " + it->first);
- header1.back()[0] = shorthand++;
- }
- else {
- fprintf(f, " 1'bx");
- header2 += "#";
- }
- fprintf(f, " }, {");
- header2 += " ";
- if (signal_clk.size()) {
- for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
- fprintf(f, "%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
- int len = it->second;
- if (len > 1)
- header2 += "/", len--;
- while (len > 1)
- header2 += "-", len--;
- if (len > 0)
- header2 += shorthand, len--;
- header1.push_back(" " + it->first);
- header1.back()[0] = shorthand++;
- }
- } else {
- fprintf(f, " 1'bx");
- header2 += "#";
- }
- fprintf(f, " }, {");
- header2 += " ";
- if (signal_out.size()) {
- for (auto it = signal_out.begin(); it != signal_out.end(); it++) {
- fprintf(f, "%s %s", it == signal_out.begin() ? "" : ",", it->first.c_str());
- int len = it->second;
- if (len > 1)
- header2 += "/", len--;
- while (len > 1)
- header2 += "-", len--;
- if (len > 0)
- header2 += shorthand, len--;
- header1.push_back(" " + it->first);
- header1.back()[0] = shorthand++;
- }
- } else {
- fprintf(f, " 1'bx");
- header2 += "#";
- }
- fprintf(f, " }, $time, i);\n");
- fprintf(f, "end\n");
- fprintf(f, "endtask\n\n");
-
- fprintf(f, "task %s;\n", idy(mod->name, "print_header").c_str());
- fprintf(f, "begin\n");
- fprintf(f, "\t$display(\"#OUT#\");\n");
- for (auto &hdr : header1)
- fprintf(f, "\t$display(\"#OUT# %s\");\n", hdr.c_str());
- fprintf(f, "\t$display(\"#OUT#\");\n");
- fprintf(f, "\t$display(\"#OUT# %s\");\n", header2.c_str());
- fprintf(f, "end\n");
- fprintf(f, "endtask\n\n");
-
- fprintf(f, "task %s;\n", idy(mod->name, "test").c_str());
- fprintf(f, "begin\n");
- fprintf(f, "\t$display(\"#OUT#\\n#OUT# ==== %s ====\");\n", idy(mod->name).c_str());
- fprintf(f, "\t%s;\n", idy(mod->name, "reset").c_str());
- fprintf(f, "\tfor (i=0; i<%d; i=i+1) begin\n", NUM_ITER);
- fprintf(f, "\t\tif (i %% 20 == 0) %s;\n", idy(mod->name, "print_header").c_str());
- fprintf(f, "\t\t#100; %s;\n", idy(mod->name, "update_data").c_str());
- fprintf(f, "\t\t#100; %s;\n", idy(mod->name, "update_clock").c_str());
- fprintf(f, "\t\t#100; %s;\n", idy(mod->name, "print_status").c_str());
- fprintf(f, "\tend\n");
- fprintf(f, "end\n");
- fprintf(f, "endtask\n\n");
- }
-
- fprintf(f, "initial begin\n");
- fprintf(f, "\t// $dumpfile(\"testbench.vcd\");\n");
- fprintf(f, "\t// $dumpvars(0, testbench);\n");
- for (auto it = design->modules.begin(); it != design->modules.end(); it++)
- if (!it->second->get_bool_attribute("\\gentb_skip"))
- fprintf(f, "\t%s;\n", idy(it->first, "test").c_str());
- fprintf(f, "\t$finish;\n");
- fprintf(f, "end\n\n");
-
- fprintf(f, "endmodule\n");
-}
-
-struct AutotestBackend : public Backend {
- AutotestBackend() : Backend("autotest", "generate simple test benches") { }
- virtual void help()
- {
- // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
- log("\n");
- log(" write_autotest [filename]\n");
- log("\n");
- log("Automatically create primitive verilog test benches for all modules in the\n");
- log("design. The generated testbenches toggle the input pins of the module in\n");
- log("a semi-random manner and dumps the resulting output signals.\n");
- log("\n");
- log("This can be used to check the synthesis results for simple circuits by\n");
- log("comparing the testbench output for the input files and the synthesis results.\n");
- log("\n");
- log("The backend automatically detects clock signals. Additionally a signal can\n");
- log("be forced to be interpreted as clock signal by setting the attribute\n");
- log("'gentb_clock' on the signal.\n");
- log("\n");
- log("The attribute 'gentb_constant' can be used to force a signal to a constant\n");
- log("value after initialization. This can e.g. be used to force a reset signal\n");
- log("low in order to explore more inner states in a state machine.\n");
- log("\n");
- }
- virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
- {
- log_header("Executing AUTOTEST backend (auto-generate pseudo-random test benches).\n");
- extra_args(f, filename, args, 1);
- autotest(f, design);
- }
-} AutotestBackend;
-
diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc
index f5a98276..ee12546c 100644
--- a/backends/blif/blif.cc
+++ b/backends/blif/blif.cc
@@ -27,29 +27,30 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
-#include <assert.h>
struct BlifDumperConfig
{
- bool subckt_mode;
+ bool icells_mode;
bool conn_mode;
bool impltf_mode;
+ bool gates_mode;
+ bool param_mode;
std::string buf_type, buf_in, buf_out;
std::string true_type, true_out, false_type, false_out;
- BlifDumperConfig() : subckt_mode(false), conn_mode(false), impltf_mode(false) { }
+ BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false), param_mode(false) { }
};
struct BlifDumper
{
- FILE *f;
+ std::ostream &f;
RTLIL::Module *module;
RTLIL::Design *design;
BlifDumperConfig *config;
CellTypes ct;
- BlifDumper(FILE *f, RTLIL::Module *module, RTLIL::Design *design, BlifDumperConfig *config) :
+ BlifDumper(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BlifDumperConfig *config) :
f(f), module(module), design(design), config(config), ct(design)
{
}
@@ -66,34 +67,42 @@ struct BlifDumper
return cstr_buf.back().c_str();
}
- const char *cstr(RTLIL::SigSpec sig)
+ const char *cstr(RTLIL::SigBit sig)
{
- sig.optimize();
- log_assert(sig.width == 1);
+ if (sig.wire == NULL)
+ return sig == RTLIL::State::S1 ? "$true" : "$false";
- if (sig.chunks.at(0).wire == NULL)
- return sig.chunks.at(0).data.bits.at(0) == RTLIL::State::S1 ? "$true" : "$false";
-
- std::string str = RTLIL::unescape_id(sig.chunks.at(0).wire->name);
+ std::string str = RTLIL::unescape_id(sig.wire->name);
for (size_t i = 0; i < str.size(); i++)
if (str[i] == '#' || str[i] == '=')
str[i] = '?';
- if (sig.chunks.at(0).wire->width != 1)
- str += stringf("[%d]", sig.chunks.at(0).offset);
+ if (sig.wire->width != 1)
+ str += stringf("[%d]", sig.offset);
cstr_buf.push_back(str);
return cstr_buf.back().c_str();
}
+ const char *subckt_or_gate(std::string cell_type)
+ {
+ if (!config->gates_mode)
+ 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"))
+ return "gate";
+ return "subckt";
+ }
+
void dump()
{
- fprintf(f, "\n");
- fprintf(f, ".model %s\n", cstr(module->name));
+ f << stringf("\n");
+ f << stringf(".model %s\n", cstr(module->name));
std::map<int, RTLIL::Wire*> inputs, outputs;
- for (auto &wire_it : module->wires) {
+ for (auto &wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_input)
inputs[wire->port_id] = wire;
@@ -101,107 +110,150 @@ struct BlifDumper
outputs[wire->port_id] = wire;
}
- fprintf(f, ".inputs");
+ f << stringf(".inputs");
for (auto &it : inputs) {
RTLIL::Wire *wire = it.second;
for (int i = 0; i < wire->width; i++)
- fprintf(f, " %s", cstr(RTLIL::SigSpec(wire, 1, i)));
+ f << stringf(" %s", cstr(RTLIL::SigSpec(wire, i)));
}
- fprintf(f, "\n");
+ f << stringf("\n");
- fprintf(f, ".outputs");
+ f << stringf(".outputs");
for (auto &it : outputs) {
RTLIL::Wire *wire = it.second;
for (int i = 0; i < wire->width; i++)
- fprintf(f, " %s", cstr(RTLIL::SigSpec(wire, 1, i)));
+ f << stringf(" %s", cstr(RTLIL::SigSpec(wire, i)));
}
- fprintf(f, "\n");
+ f << stringf("\n");
if (!config->impltf_mode) {
if (!config->false_type.empty())
- fprintf(f, ".subckt %s %s=$false\n", config->false_type.c_str(), config->false_out.c_str());
+ f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type),
+ config->false_type.c_str(), config->false_out.c_str());
else
- fprintf(f, ".names $false\n");
+ f << stringf(".names $false\n");
if (!config->true_type.empty())
- fprintf(f, ".subckt %s %s=$true\n", config->true_type.c_str(), config->true_out.c_str());
+ f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type),
+ config->true_type.c_str(), config->true_out.c_str());
else
- fprintf(f, ".names $true\n1\n");
+ f << stringf(".names $true\n1\n");
}
- for (auto &cell_it : module->cells)
+ for (auto &cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
- if (!config->subckt_mode && cell->type == "$_INV_") {
- fprintf(f, ".names %s %s\n0 1\n",
- cstr(cell->connections.at("\\A")), cstr(cell->connections.at("\\Y")));
+ if (!config->icells_mode && cell->type == "$_NOT_") {
+ f << stringf(".names %s %s\n0 1\n",
+ cstr(cell->getPort("\\A")), cstr(cell->getPort("\\Y")));
+ continue;
+ }
+
+ if (!config->icells_mode && cell->type == "$_AND_") {
+ f << stringf(".names %s %s %s\n11 1\n",
+ cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
continue;
}
- if (!config->subckt_mode && cell->type == "$_AND_") {
- fprintf(f, ".names %s %s %s\n11 1\n",
- cstr(cell->connections.at("\\A")), cstr(cell->connections.at("\\B")), cstr(cell->connections.at("\\Y")));
+ if (!config->icells_mode && cell->type == "$_OR_") {
+ f << stringf(".names %s %s %s\n1- 1\n-1 1\n",
+ cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
continue;
}
- if (!config->subckt_mode && cell->type == "$_OR_") {
- fprintf(f, ".names %s %s %s\n1- 1\n-1 1\n",
- cstr(cell->connections.at("\\A")), cstr(cell->connections.at("\\B")), cstr(cell->connections.at("\\Y")));
+ if (!config->icells_mode && cell->type == "$_XOR_") {
+ f << stringf(".names %s %s %s\n10 1\n01 1\n",
+ cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
continue;
}
- if (!config->subckt_mode && cell->type == "$_XOR_") {
- fprintf(f, ".names %s %s %s\n10 1\n01 1\n",
- cstr(cell->connections.at("\\A")), cstr(cell->connections.at("\\B")), cstr(cell->connections.at("\\Y")));
+ if (!config->icells_mode && cell->type == "$_MUX_") {
+ f << stringf(".names %s %s %s %s\n1-0 1\n-11 1\n",
+ cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")),
+ cstr(cell->getPort("\\S")), cstr(cell->getPort("\\Y")));
continue;
}
- if (!config->subckt_mode && cell->type == "$_MUX_") {
- fprintf(f, ".names %s %s %s %s\n1-0 1\n-11 1\n",
- cstr(cell->connections.at("\\A")), cstr(cell->connections.at("\\B")),
- cstr(cell->connections.at("\\S")), cstr(cell->connections.at("\\Y")));
+ if (!config->icells_mode && cell->type == "$_DFF_N_") {
+ f << stringf(".latch %s %s fe %s\n",
+ cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), cstr(cell->getPort("\\C")));
continue;
}
- if (!config->subckt_mode && cell->type == "$_DFF_N_") {
- fprintf(f, ".latch %s %s fe %s\n",
- cstr(cell->connections.at("\\D")), cstr(cell->connections.at("\\Q")), cstr(cell->connections.at("\\C")));
+ if (!config->icells_mode && cell->type == "$_DFF_P_") {
+ f << stringf(".latch %s %s re %s\n",
+ cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), cstr(cell->getPort("\\C")));
continue;
}
- if (!config->subckt_mode && cell->type == "$_DFF_P_") {
- fprintf(f, ".latch %s %s re %s\n",
- cstr(cell->connections.at("\\D")), cstr(cell->connections.at("\\Q")), cstr(cell->connections.at("\\C")));
+ if (!config->icells_mode && cell->type == "$lut") {
+ f << stringf(".names");
+ auto &inputs = cell->getPort("\\A");
+ auto width = cell->parameters.at("\\WIDTH").as_int();
+ log_assert(inputs.size() == width);
+ for (int i = 0; i < inputs.size(); i++) {
+ f << stringf(" %s", cstr(inputs.extract(i, 1)));
+ }
+ auto &output = cell->getPort("\\Y");
+ log_assert(output.size() == 1);
+ f << stringf(" %s", cstr(output));
+ f << stringf("\n");
+ auto mask = cell->parameters.at("\\LUT").as_string();
+ for (int i = 0; i < (1 << width); i++) {
+ if (mask[i] == '0') continue;
+ for (int j = width-1; j >= 0; j--) {
+ f << ((i>>j)&1 ? '1' : '0');
+ }
+ f << stringf(" %c\n", mask[i]);
+ }
continue;
}
- fprintf(f, ".subckt %s", cstr(cell->type));
- for (auto &conn : cell->connections)
- for (int i = 0; i < conn.second.width; i++) {
- if (conn.second.width == 1)
- fprintf(f, " %s", cstr(conn.first));
+ 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
- fprintf(f, " %s[%d]", cstr(conn.first), i);
- fprintf(f, "=%s", cstr(conn.second.extract(i, 1)));
+ f << stringf(" %s[%d]", cstr(conn.first), i);
+ f << stringf("=%s", cstr(conn.second.extract(i, 1)));
}
- fprintf(f, "\n");
+ f << stringf("\n");
+
+ if (config->param_mode)
+ for (auto &param : cell->parameters) {
+ f << stringf(".param %s ", RTLIL::id2cstr(param.first));
+ if (param.second.flags & RTLIL::CONST_FLAG_STRING) {
+ std::string str = param.second.decode_string();
+ f << stringf("\"");
+ for (char ch : str)
+ if (ch == '"' || ch == '\\')
+ f << stringf("\\%c", ch);
+ else if (ch < 32 || ch >= 127)
+ f << stringf("\\%03o", ch);
+ else
+ f << stringf("%c", ch);
+ f << stringf("\"\n");
+ } else
+ f << stringf("%s\n", param.second.as_string().c_str());
+ }
}
- for (auto &conn : module->connections)
- for (int i = 0; i < conn.first.width; i++)
+ for (auto &conn : module->connections())
+ for (int i = 0; i < conn.first.size(); i++)
if (config->conn_mode)
- fprintf(f, ".conn %s %s\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1)));
+ f << stringf(".conn %s %s\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1)));
else if (!config->buf_type.empty())
- fprintf(f, ".subckt %s %s=%s %s=%s\n", config->buf_type.c_str(), config->buf_in.c_str(), cstr(conn.second.extract(i, 1)),
+ f << stringf(".%s %s %s=%s %s=%s\n", subckt_or_gate(config->buf_type), config->buf_type.c_str(), config->buf_in.c_str(), cstr(conn.second.extract(i, 1)),
config->buf_out.c_str(), cstr(conn.first.extract(i, 1)));
else
- fprintf(f, ".names %s %s\n1 1\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1)));
+ f << stringf(".names %s %s\n1 1\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1)));
- fprintf(f, ".end\n");
+ f << stringf(".end\n");
}
- static void dump(FILE *f, RTLIL::Module *module, RTLIL::Design *design, BlifDumperConfig &config)
+ static void dump(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BlifDumperConfig &config)
{
BlifDumper dumper(f, module, design, &config);
dumper.dump();
@@ -228,23 +280,30 @@ struct BlifBackend : public Backend {
log(" -false <cell-type> <out-port>\n");
log(" use the specified cell types to drive nets that are constant 1 or 0\n");
log("\n");
- log("The following options can be usefull when the generated file is not going to be\n");
+ log("The following options can be useful when the generated file is not going to be\n");
log("read by a BLIF parser but a custom tool. It is recommended to not name the output\n");
log("file *.blif when any of this options is used.\n");
log("\n");
- log(" -subckt\n");
+ log(" -icells\n");
log(" do not translate Yosys's internal gates to generic BLIF logic\n");
- log(" functions. Instead create .subckt lines for all cells.\n");
+ log(" functions. Instead create .subckt or .gate lines for all cells.\n");
+ log("\n");
+ log(" -gates\n");
+ log(" print .gate instead of .subckt lines for all cells that are not\n");
+ log(" instantiations of other modules from this design.\n");
log("\n");
log(" -conn\n");
log(" do not generate buffers for connected wires. instead use the\n");
log(" non-standard .conn statement.\n");
log("\n");
+ log(" -param\n");
+ log(" use the non-standard .param statement to write module parameters\n");
+ log("\n");
log(" -impltf\n");
log(" do not write definitions for the $true and $false wires.\n");
log("\n");
}
- virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
std::string top_module_name;
std::string buf_type, buf_in, buf_out;
@@ -277,14 +336,22 @@ struct BlifBackend : public Backend {
config.false_out = args[++argidx];
continue;
}
- if (args[argidx] == "-subckt") {
- config.subckt_mode = true;
+ if (args[argidx] == "-icells") {
+ config.icells_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-gates") {
+ config.gates_mode = true;
continue;
}
if (args[argidx] == "-conn") {
config.conn_mode = true;
continue;
}
+ if (args[argidx] == "-param") {
+ config.param_mode = true;
+ continue;
+ }
if (args[argidx] == "-impltf") {
config.impltf_mode = true;
continue;
@@ -294,15 +361,15 @@ struct BlifBackend : public Backend {
extra_args(f, filename, args, argidx);
if (top_module_name.empty())
- for (auto & mod_it:design->modules)
+ for (auto & mod_it:design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
- top_module_name = mod_it.first;
+ top_module_name = mod_it.first.str();
- fprintf(f, "# Generated by %s\n", yosys_version_str);
+ *f << stringf("# Generated by %s\n", yosys_version_str);
std::vector<RTLIL::Module*> mod_list;
- for (auto module_it : design->modules)
+ for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox"))
@@ -314,7 +381,7 @@ struct BlifBackend : public Backend {
log_error("Found munmapped emories in module %s: unmapped memories are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name));
if (module->name == RTLIL::escape_id(top_module_name)) {
- BlifDumper::dump(f, module, design, config);
+ BlifDumper::dump(*f, module, design, config);
top_module_name.clear();
continue;
}
@@ -326,7 +393,7 @@ struct BlifBackend : public Backend {
log_error("Can't find top module `%s'!\n", top_module_name.c_str());
for (auto module : mod_list)
- BlifDumper::dump(f, module, design, config);
+ BlifDumper::dump(*f, module, design, config);
}
} BlifBackend;
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index abe09943..8ce5bb5e 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -28,7 +28,6 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
-#include <assert.h>
#include <math.h>
struct BtorDumperConfig
@@ -46,9 +45,9 @@ struct BtorDumperConfig
struct WireInfo
{
RTLIL::IdString cell_name;
- RTLIL::SigChunk *chunk;
+ const RTLIL::SigChunk *chunk;
- WireInfo(RTLIL::IdString c, RTLIL::SigChunk* ch) : cell_name(c), chunk(ch) { }
+ WireInfo(RTLIL::IdString c, const RTLIL::SigChunk* ch) : cell_name(c), chunk(ch) { }
};
struct WireInfoOrder
@@ -61,7 +60,7 @@ struct WireInfoOrder
struct BtorDumper
{
- FILE *f;
+ std::ostream &f;
RTLIL::Module *module;
RTLIL::Design *design;
BtorDumperConfig *config;
@@ -75,14 +74,14 @@ struct BtorDumper
std::string str;//temp string for writing file
std::map<RTLIL::IdString, bool> basic_wires;//input wires and registers
RTLIL::IdString curr_cell; //current cell being dumped
- std::set<int> mem_next; //if memory (line_number) already has next
- std::map<std::string, std::string> cell_type_translation, s_cell_type_translation; //RTLIL to BTOR translation
- BtorDumper(FILE *f, RTLIL::Module *module, RTLIL::Design *design, BtorDumperConfig *config) :
- f(f), module(module), design(design), config(config), ct(design), sigmap(module)
+ std::map<std::string, std::string> cell_type_translation, s_cell_type_translation; //RTLIL to BTOR translation
+ std::set<int> mem_next; //if memory (line_number) already has next
+ BtorDumper(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BtorDumperConfig *config) :
+ f(f), module(module), design(design), config(config), ct(design), sigmap(module)
{
line_num=0;
str.clear();
- for(auto it=module->wires.begin(); it!=module->wires.end(); ++it)
+ for(auto it=module->wires_.begin(); it!=module->wires_.end(); ++it)
{
if(it->second->port_input)
{
@@ -113,6 +112,8 @@ struct BtorDumper
cell_type_translation["$shl"] = "sll";
cell_type_translation["$sshr"] = "sra";
cell_type_translation["$sshl"] = "sll";
+ cell_type_translation["$shift"] = "srl";
+ cell_type_translation["$shiftx"] = "srl";
cell_type_translation["$lt"] = "ult";
cell_type_translation["$le"] = "ulte";
cell_type_translation["$gt"] = "ugt";
@@ -174,7 +175,7 @@ struct BtorDumper
++line_num;
line_ref[wire->name]=line_num;
str = stringf("%d var %d %s", line_num, wire->width, cstr(wire->name));
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
return line_num;
}
else return it->second;
@@ -194,11 +195,11 @@ struct BtorDumper
if(cell_id == curr_cell)
break;
log(" -- found cell %s\n", cstr(cell_id));
- RTLIL::Cell* cell = module->cells.at(cell_id);
- RTLIL::SigSpec* cell_output = get_cell_output(cell);
+ RTLIL::Cell* cell = module->cells_.at(cell_id);
+ const RTLIL::SigSpec* cell_output = get_cell_output(cell);
int cell_line = dump_cell(cell);
- if(dep_set.size()==1 && wire->width == cell_output->width)
+ if(dep_set.size()==1 && wire->width == cell_output->size())
{
wire_line = cell_line;
break;
@@ -207,22 +208,22 @@ struct BtorDumper
{
int prev_wire_line=0; //previously dumped wire line
int start_bit=0;
- for(unsigned j=0; j<cell_output->chunks.size(); ++j)
+ for(unsigned j=0; j<cell_output->chunks().size(); ++j)
{
- start_bit+=cell_output->chunks[j].width;
- if(cell_output->chunks[j].wire->name == wire->name)
+ start_bit+=cell_output->chunks().at(j).width;
+ if(cell_output->chunks().at(j).wire->name == wire->name)
{
prev_wire_line = wire_line;
wire_line = ++line_num;
- str = stringf("%d slice %d %d %d %d;1", line_num, cell_output->chunks[j].width,
- cell_line, start_bit-1, start_bit-cell_output->chunks[j].width);
- fprintf(f, "%s\n", str.c_str());
- wire_width += cell_output->chunks[j].width;
+ str = stringf("%d slice %d %d %d %d;1", line_num, cell_output->chunks().at(j).width,
+ cell_line, start_bit-1, start_bit-cell_output->chunks().at(j).width);
+ f << stringf("%s\n", str.c_str());
+ wire_width += cell_output->chunks().at(j).width;
if(prev_wire_line!=0)
{
++line_num;
str = stringf("%d concat %d %d %d", line_num, wire_width, wire_line, prev_wire_line);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
wire_line = line_num;
}
}
@@ -233,7 +234,7 @@ struct BtorDumper
{
log(" - checking sigmap\n");
RTLIL::SigSpec s = RTLIL::SigSpec(wire);
- wire_line = dump_sigspec(&s, s.width);
+ wire_line = dump_sigspec(&s, s.size());
line_ref[wire->name]=wire_line;
}
line_ref[wire->name]=wire_line;
@@ -245,7 +246,7 @@ struct BtorDumper
return it->second;
}
}
- assert(false);
+ log_abort();
return -1;
}
@@ -259,7 +260,7 @@ struct BtorDumper
int address_bits = ceil(log(memory->size)/log(2));
str = stringf("%d array %d %d", line_num, memory->width, address_bits);
line_ref[memory->name]=line_num;
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
return line_num;
}
else return it->second;
@@ -279,12 +280,12 @@ struct BtorDumper
++line_num;
str = stringf("%d const %d %s", line_num, width, data_str.c_str());
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
return line_num;
}
else
log("writing const error\n");
- assert(false);
+ log_abort();
return -1;
}
@@ -294,7 +295,8 @@ struct BtorDumper
int l=-1;
if(chunk->wire == NULL)
{
- l=dump_const(&chunk->data, chunk->width, chunk->offset);
+ RTLIL::Const data_const(chunk->data);
+ l=dump_const(&data_const, chunk->width, chunk->offset);
}
else
{
@@ -303,11 +305,11 @@ struct BtorDumper
else
{
int wire_line_num = dump_wire(chunk->wire);
- assert(wire_line_num>0);
+ log_assert(wire_line_num>0);
++line_num;
str = stringf("%d slice %d %d %d %d;2", line_num, chunk->width, wire_line_num,
chunk->width + chunk->offset - 1, chunk->offset);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
l = line_num;
}
}
@@ -322,24 +324,24 @@ struct BtorDumper
auto it = sig_ref.find(s);
if(it == std::end(sig_ref))
{
- if (s.chunks.size() == 1)
+ if (s.is_chunk())
{
- l = dump_sigchunk(&s.chunks[0]);
+ l = dump_sigchunk(&s.chunks().front());
}
else
{
int l1, l2, w1, w2;
- l1 = dump_sigchunk(&s.chunks[0]);
- assert(l1>0);
- w1 = s.chunks[0].width;
- for (unsigned i=1; i < s.chunks.size(); ++i)
+ l1 = dump_sigchunk(&s.chunks().front());
+ log_assert(l1>0);
+ w1 = s.chunks().front().width;
+ for (unsigned i=1; i < s.chunks().size(); ++i)
{
- l2 = dump_sigchunk(&s.chunks[i]);
- assert(l2>0);
- w2 = s.chunks[i].width;
+ l2 = dump_sigchunk(&s.chunks().at(i));
+ log_assert(l2>0);
+ w2 = s.chunks().at(i).width;
++line_num;
str = stringf("%d concat %d %d %d", line_num, w1+w2, l2, l1);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
l1=line_num;
w1+=w2;
}
@@ -352,30 +354,30 @@ struct BtorDumper
l = it->second;
}
- if (expected_width != s.width)
+ if (expected_width != s.size())
{
log(" - changing width of sigspec\n");
//TODO: this block may not be needed anymore, due to explicit type conversion by "splice" command
- if(expected_width > s.width)
+ if(expected_width > s.size())
{
//TODO: case the signal is signed
++line_num;
- str = stringf ("%d zero %d", line_num, expected_width - s.width);
- fprintf(f, "%s\n", str.c_str());
+ str = stringf ("%d zero %d", line_num, expected_width - s.size());
+ f << stringf("%s\n", str.c_str());
++line_num;
str = stringf ("%d concat %d %d %d", line_num, expected_width, line_num-1, l);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
l = line_num;
}
- else if(expected_width < s.width)
+ else if(expected_width < s.size())
{
++line_num;
str = stringf ("%d slice %d %d %d %d;3", line_num, expected_width, l, expected_width-1, 0);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
l = line_num;
}
}
- assert(l>0);
+ log_assert(l>0);
return l;
}
@@ -389,29 +391,29 @@ struct BtorDumper
if(cell->type == "$assert")
{
log("writing assert cell - %s\n", cstr(cell->type));
- const RTLIL::SigSpec* expr = &cell->connections.at(RTLIL::IdString("\\A"));
- const RTLIL::SigSpec* en = &cell->connections.at(RTLIL::IdString("\\EN"));
- assert(expr->width == 1);
- assert(en->width == 1);
+ const RTLIL::SigSpec* expr = &cell->getPort(RTLIL::IdString("\\A"));
+ const RTLIL::SigSpec* en = &cell->getPort(RTLIL::IdString("\\EN"));
+ log_assert(expr->size() == 1);
+ log_assert(en->size() == 1);
int expr_line = dump_sigspec(expr, 1);
int en_line = dump_sigspec(en, 1);
int one_line = ++line_num;
str = stringf("%d one 1", line_num);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d %s %d %d %d", line_num, cell_type_translation.at("$eq").c_str(), 1, en_line, one_line);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d %s %d %d %d %d", line_num, cell_type_translation.at("$mux").c_str(), 1, line_num-1,
expr_line, one_line);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
int cell_line = ++line_num;
str = stringf("%d %s %d %d", line_num, cell_type_translation.at("$assert").c_str(), 1, -1*(line_num-1));
//multiplying the line number with -1, which means logical negation
//the reason for negative sign is that the properties in btor are given as "negation of the original property"
//bug identified by bobosoft
//http://www.reddit.com/r/yosys/comments/1w3xig/btor_backend_bug/
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
line_ref[cell->name]=cell_line;
}
//unary cells
@@ -422,20 +424,20 @@ struct BtorDumper
int w = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
w = w>output_width ? w:output_width; //padding of w
- int l = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), w);
+ int l = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), w);
int cell_line = l;
if(cell->type != "$pos")
{
cell_line = ++line_num;
bool reduced = (cell->type == "$not" || cell->type == "$neg") ? false : true;
- str = stringf ("%d %s %d %d", cell_line, cell_type_translation.at(cell->type).c_str(), reduced?output_width:w, l);
- fprintf(f, "%s\n", str.c_str());
+ str = stringf ("%d %s %d %d", cell_line, cell_type_translation.at(cell->type.str()).c_str(), reduced?output_width:w, l);
+ f << stringf("%s\n", str.c_str());
}
if(output_width < w && (cell->type == "$not" || cell->type == "$neg" || cell->type == "$pos"))
{
++line_num;
str = stringf ("%d slice %d %d %d %d;4", line_num, output_width, cell_line, output_width-1, 0);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
cell_line = line_num;
}
line_ref[cell->name]=cell_line;
@@ -445,25 +447,23 @@ struct BtorDumper
log("writing unary cell - %s\n", cstr(cell->type));
int w = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
- assert(output_width == 1);
- int l = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), w);
+ log_assert(output_width == 1);
+ int l = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), w);
if(cell->type == "$logic_not" && w > 1)
{
++line_num;
str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$reduce_or").c_str(), output_width, l);
- fprintf(f, "%s\n", str.c_str());
- l = line_num;
+ f << stringf("%s\n", str.c_str());
}
else if(cell->type == "$reduce_xnor")
{
++line_num;
str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$reduce_xor").c_str(), output_width, l);
- fprintf(f, "%s\n", str.c_str());
- l = line_num;
+ f << stringf("%s\n", str.c_str());
}
++line_num;
str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$not").c_str(), output_width, l);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
//binary cells
@@ -473,7 +473,7 @@ struct BtorDumper
{
log("writing binary cell - %s\n", cstr(cell->type));
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
- assert(!(cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" ||
+ log_assert(!(cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" ||
cell->type == "$ge" || cell->type == "$gt") || output_width == 1);
bool l1_signed = cell->parameters.at(RTLIL::IdString("\\A_SIGNED")).as_bool();
bool l2_signed = cell->parameters.at(RTLIL::IdString("\\B_SIGNED")).as_bool();
@@ -485,21 +485,21 @@ struct BtorDumper
l1_width = l1_width > l2_width ? l1_width : l2_width;
l2_width = l2_width > l1_width ? l2_width : l1_width;
- int l1 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), l1_width);
- int l2 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), l2_width);
+ int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), l1_width);
+ int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), l2_width);
++line_num;
- std::string op = cell_type_translation.at(cell->type);
+ std::string op = cell_type_translation.at(cell->type.str());
if(cell->type == "$lt" || cell->type == "$le" ||
cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" ||
cell->type == "$ge" || cell->type == "$gt")
{
if(l1_signed)
- op = s_cell_type_translation.at(cell->type);
+ op = s_cell_type_translation.at(cell->type.str());
}
str = stringf ("%d %s %d %d %d", line_num, op.c_str(), output_width, l1, l2);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
@@ -514,18 +514,18 @@ struct BtorDumper
int l1_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
int l2_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
- assert(l1_signed == l2_signed);
+ log_assert(l1_signed == l2_signed);
l1_width = l1_width > output_width ? l1_width : output_width;
l1_width = l1_width > l2_width ? l1_width : l2_width;
l2_width = l2_width > l1_width ? l2_width : l1_width;
- int l1 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), l1_width);
- int l2 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), l2_width);
+ int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), l1_width);
+ int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), l2_width);
++line_num;
- std::string op = cell_type_translation.at(cell->type);
+ std::string op = cell_type_translation.at(cell->type.str());
if(cell->type == "$div" && l1_signed)
- op = s_cell_type_translation.at(cell->type);
+ op = s_cell_type_translation.at(cell->type.str());
else if(cell->type == "$mod")
{
if(l1_signed)
@@ -534,17 +534,17 @@ struct BtorDumper
op = s_cell_type_translation.at("$mody");
}
str = stringf ("%d %s %d %d %d", line_num, op.c_str(), l1_width, l1, l2);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
if(output_width < l1_width)
{
++line_num;
str = stringf ("%d slice %d %d %d %d;5", line_num, output_width, line_num-1, output_width-1, 0);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
}
line_ref[cell->name]=line_num;
}
- else if(cell->type == "$shr" || cell->type == "$shl" || cell->type == "$sshr" || cell->type == "$sshl")
+ else if(cell->type == "$shr" || cell->type == "$shl" || cell->type == "$sshr" || cell->type == "$sshl" || cell->type == "$shift" || cell->type == "$shiftx")
{
log("writing binary cell - %s\n", cstr(cell->type));
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
@@ -553,32 +553,32 @@ struct BtorDumper
int l1_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
l1_width = pow(2, ceil(log(l1_width)/log(2)));
int l2_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
- //assert(l2_width <= ceil(log(l1_width)/log(2)) );
- int l1 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), l1_width);
- int l2 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), ceil(log(l1_width)/log(2)));
+ //log_assert(l2_width <= ceil(log(l1_width)/log(2)) );
+ int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), l1_width);
+ int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), ceil(log(l1_width)/log(2)));
int cell_output = ++line_num;
- str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type).c_str(), l1_width, l1, l2);
- fprintf(f, "%s\n", str.c_str());
+ str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type.str()).c_str(), l1_width, l1, l2);
+ f << stringf("%s\n", str.c_str());
if(l2_width > ceil(log(l1_width)/log(2)))
{
int extra_width = l2_width - ceil(log(l1_width)/log(2));
- l2 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), l2_width);
+ l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), l2_width);
++line_num;
str = stringf ("%d slice %d %d %d %d;6", line_num, extra_width, l2, l2_width-1, l2_width-extra_width);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
++line_num;
str = stringf ("%d one %d", line_num, extra_width);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
int mux = ++line_num;
str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at("$gt").c_str(), 1, line_num-2, line_num-1);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d %s %d", line_num, l1_signed && cell->type == "$sshr" ? "ones":"zero", l1_width);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
++line_num;
str = stringf ("%d %s %d %d %d %d", line_num, cell_type_translation.at("$mux").c_str(), l1_width, mux, line_num-1, cell_output);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
cell_output = line_num;
}
@@ -586,7 +586,7 @@ struct BtorDumper
{
++line_num;
str = stringf ("%d slice %d %d %d %d;5", line_num, output_width, cell_output, output_width-1, 0);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
cell_output = line_num;
}
line_ref[cell->name] = cell_output;
@@ -595,23 +595,23 @@ struct BtorDumper
{
log("writing binary cell - %s\n", cstr(cell->type));
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
- assert(output_width == 1);
- int l1 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), output_width);
- int l2 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), output_width);
+ log_assert(output_width == 1);
+ int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), output_width);
+ int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), output_width);
int l1_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
int l2_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
if(l1_width >1)
{
++line_num;
str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$reduce_or").c_str(), output_width, l1);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
l1 = line_num;
}
if(l2_width > 1)
{
++line_num;
str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$reduce_or").c_str(), output_width, l2);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
l2 = line_num;
}
if(cell->type == "$logic_and")
@@ -624,7 +624,7 @@ struct BtorDumper
++line_num;
str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at("$or").c_str(), output_width, l1, l2);
}
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
//multiplexers
@@ -632,13 +632,14 @@ struct BtorDumper
{
log("writing mux cell\n");
int output_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
- int l1 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), output_width);
- int l2 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), output_width);
- int s = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\S")), 1);
+ int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), output_width);
+ int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), output_width);
+ int s = dump_sigspec(&cell->getPort(RTLIL::IdString("\\S")), 1);
++line_num;
str = stringf ("%d %s %d %d %d %d",
- line_num, cell_type_translation.at(cell->type).c_str(), output_width, s, l2, l1);//if s is 0 then l1, if s is 1 then l2 //according to the implementation of mux cell
- fprintf(f, "%s\n", str.c_str());
+ line_num, cell_type_translation.at(cell->type.str()).c_str(), output_width, s, l2, l1);
+ //if s is 0 then l1, if s is 1 then l2 //according to the implementation of mux cell
+ f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
else if(cell->type == "$pmux")
@@ -646,97 +647,97 @@ struct BtorDumper
log("writing pmux cell\n");
int output_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
int select_width = cell->parameters.at(RTLIL::IdString("\\S_WIDTH")).as_int();
- int default_case = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), output_width);
- int cases = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), output_width*select_width);
- int select = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\S")), select_width);
+ int default_case = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), output_width);
+ int cases = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), output_width*select_width);
+ int select = dump_sigspec(&cell->getPort(RTLIL::IdString("\\S")), select_width);
int *c = new int[select_width];
for (int i=0; i<select_width; ++i)
{
++line_num;
str = stringf ("%d slice 1 %d %d %d", line_num, select, i, i);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
c[i] = line_num;
++line_num;
str = stringf ("%d slice %d %d %d %d", line_num, output_width, cases, i*output_width+output_width-1,
i*output_width);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
}
++line_num;
str = stringf ("%d cond %d %d %d %d", line_num, output_width, c[select_width-1], c[select_width-1]+1, default_case);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
for (int i=select_width-2; i>=0; --i)
{
++line_num;
str = stringf ("%d cond %d %d %d %d", line_num, output_width, c[i], c[i]+1, line_num-1);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
}
line_ref[cell->name]=line_num;
}
- //registers
+ //registers
else if(cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffsr")
{
//TODO: remodelling fo adff cells
log("writing cell - %s\n", cstr(cell->type));
int output_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
log(" - width is %d\n", output_width);
- int cond = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\CLK")), 1);
+ int cond = dump_sigspec(&cell->getPort(RTLIL::IdString("\\CLK")), 1);
bool polarity = cell->parameters.at(RTLIL::IdString("\\CLK_POLARITY")).as_bool();
- const RTLIL::SigSpec* cell_output = &cell->connections.at(RTLIL::IdString("\\Q"));
- int value = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\D")), output_width);
+ const RTLIL::SigSpec* cell_output = &cell->getPort(RTLIL::IdString("\\Q"));
+ int value = dump_sigspec(&cell->getPort(RTLIL::IdString("\\D")), output_width);
unsigned start_bit = 0;
- for(unsigned i=0; i<cell_output->chunks.size(); ++i)
+ for(unsigned i=0; i<cell_output->chunks().size(); ++i)
{
- output_width = cell_output->chunks[i].width;
- assert( output_width == cell_output->chunks[i].wire->width);//full reg is given the next value
- int reg = dump_wire(cell_output->chunks[i].wire);//register
+ output_width = cell_output->chunks().at(i).width;
+ log_assert( output_width == cell_output->chunks().at(i).wire->width);//full reg is given the next value
+ int reg = dump_wire(cell_output->chunks().at(i).wire);//register
int slice = value;
- if(cell_output->chunks.size()>1)
+ if(cell_output->chunks().size()>1)
{
start_bit+=output_width;
slice = ++line_num;
str = stringf ("%d slice %d %d %d %d;", line_num, output_width, value, start_bit-1,
start_bit-output_width);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
}
if(cell->type == "$dffsr")
{
- int sync_reset = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\CLR")), 1);
+ int sync_reset = dump_sigspec(&cell->getPort(RTLIL::IdString("\\CLR")), 1);
bool sync_reset_pol = cell->parameters.at(RTLIL::IdString("\\CLR_POLARITY")).as_bool();
- int sync_reset_value = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\SET")),
+ int sync_reset_value = dump_sigspec(&cell->getPort(RTLIL::IdString("\\SET")),
output_width);
bool sync_reset_value_pol = cell->parameters.at(RTLIL::IdString("\\SET_POLARITY")).as_bool();
++line_num;
str = stringf ("%d %s %d %s%d %s%d %d", line_num, cell_type_translation.at("$mux").c_str(),
output_width, sync_reset_pol ? "":"-", sync_reset, sync_reset_value_pol? "":"-",
sync_reset_value, slice);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
slice = line_num;
}
++line_num;
str = stringf ("%d %s %d %s%d %d %d", line_num, cell_type_translation.at("$mux").c_str(),
output_width, polarity?"":"-", cond, slice, reg);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
int next = line_num;
if(cell->type == "$adff")
{
- int async_reset = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\ARST")), 1);
+ int async_reset = dump_sigspec(&cell->getPort(RTLIL::IdString("\\ARST")), 1);
bool async_reset_pol = cell->parameters.at(RTLIL::IdString("\\ARST_POLARITY")).as_bool();
int async_reset_value = dump_const(&cell->parameters.at(RTLIL::IdString("\\ARST_VALUE")),
output_width, 0);
++line_num;
str = stringf ("%d %s %d %s%d %d %d", line_num, cell_type_translation.at("$mux").c_str(),
output_width, async_reset_pol ? "":"-", async_reset, async_reset_value, next);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
}
++line_num;
- str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type).c_str(),
+ str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type.str()).c_str(),
output_width, reg, next);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
}
line_ref[cell->name]=line_num;
}
@@ -749,11 +750,11 @@ struct BtorDumper
str = cell->parameters.at(RTLIL::IdString("\\MEMID")).decode_string();
int mem = dump_memory(module->memories.at(RTLIL::IdString(str.c_str())));
int address_width = cell->parameters.at(RTLIL::IdString("\\ABITS")).as_int();
- int address = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\ADDR")), address_width);
+ int address = dump_sigspec(&cell->getPort(RTLIL::IdString("\\ADDR")), address_width);
int data_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
++line_num;
str = stringf("%d read %d %d %d", line_num, data_width, mem, address);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
else if(cell->type == "$memwr")
@@ -761,13 +762,13 @@ struct BtorDumper
log("writing memwr cell\n");
if (cell->parameters.at("\\CLK_ENABLE").as_bool() == false)
log_error("The btor backen does not support $memwr cells without built-in registers. Run memory_dff (but with -wr_only).\n");
- int clk = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\CLK")), 1);
+ int clk = dump_sigspec(&cell->getPort(RTLIL::IdString("\\CLK")), 1);
bool polarity = cell->parameters.at(RTLIL::IdString("\\CLK_POLARITY")).as_bool();
- int enable = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\EN")), 1);
+ int enable = dump_sigspec(&cell->getPort(RTLIL::IdString("\\EN")), 1);
int address_width = cell->parameters.at(RTLIL::IdString("\\ABITS")).as_int();
- int address = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\ADDR")), address_width);
- int data_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
- int data = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\DATA")), data_width);
+ int address = dump_sigspec(&cell->getPort(RTLIL::IdString("\\ADDR")), address_width);
+ int data_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
+ int data = dump_sigspec(&cell->getPort(RTLIL::IdString("\\DATA")), data_width);
str = cell->parameters.at(RTLIL::IdString("\\MEMID")).decode_string();
int mem = dump_memory(module->memories.at(RTLIL::IdString(str.c_str())));
//check if the memory has already next
@@ -779,68 +780,67 @@ struct BtorDumper
RTLIL::Memory *memory = module->memories.at(RTLIL::IdString(str.c_str()));
int address_bits = ceil(log(memory->size)/log(2));
str = stringf("%d array %d %d", line_num, memory->width, address_bits);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d eq 1 %d %d", line_num, mem, line_num - 1);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
mem = line_num - 1;
}
- ++line_num;
+ ++line_num;
if(polarity)
str = stringf("%d one 1", line_num);
else
str = stringf("%d zero 1", line_num);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d eq 1 %d %d", line_num, clk, line_num-1);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d and 1 %d %d", line_num, line_num-1, enable);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d write %d %d %d %d %d", line_num, data_width, address_width, mem, address, data);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d acond %d %d %d %d %d", line_num, data_width, address_width, line_num-2/*enable*/, line_num-1, mem);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d anext %d %d %d %d", line_num, data_width, address_width, mem, line_num-1);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
mem_next.insert(mem);
- line_ref[cell->name]=line_num;
+ line_ref[cell->name]=line_num;
}
else if(cell->type == "$slice")
{
log("writing slice cell\n");
- const RTLIL::SigSpec* input = &cell->connections.at(RTLIL::IdString("\\A"));
+ const RTLIL::SigSpec* input = &cell->getPort(RTLIL::IdString("\\A"));
int input_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
- assert(input->width == input_width);
+ log_assert(input->size() == input_width);
int input_line = dump_sigspec(input, input_width);
- const RTLIL::SigSpec* output = &cell->connections.at(RTLIL::IdString("\\Y"));
+ const RTLIL::SigSpec* output = &cell->getPort(RTLIL::IdString("\\Y"));
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
- assert(output->width == output_width);
+ log_assert(output->size() == output_width);
int offset = cell->parameters.at(RTLIL::IdString("\\OFFSET")).as_int();
++line_num;
- str = stringf("%d %s %d %d %d %d", line_num, cell_type_translation.at(cell->type).c_str(),
- output_width, input_line, output_width+offset-1, offset);
- fprintf(f, "%s\n", str.c_str());
+ str = stringf("%d %s %d %d %d %d", line_num, cell_type_translation.at(cell->type.str()).c_str(), output_width, input_line, output_width+offset-1, offset);
+ f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
else if(cell->type == "$concat")
{
log("writing concat cell\n");
- const RTLIL::SigSpec* input_a = &cell->connections.at(RTLIL::IdString("\\A"));
+ const RTLIL::SigSpec* input_a = &cell->getPort(RTLIL::IdString("\\A"));
int input_a_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
- assert(input_a->width == input_a_width);
+ log_assert(input_a->size() == input_a_width);
int input_a_line = dump_sigspec(input_a, input_a_width);
- const RTLIL::SigSpec* input_b = &cell->connections.at(RTLIL::IdString("\\B"));
+ const RTLIL::SigSpec* input_b = &cell->getPort(RTLIL::IdString("\\B"));
int input_b_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
- assert(input_b->width == input_b_width);
+ log_assert(input_b->size() == input_b_width);
int input_b_line = dump_sigspec(input_b, input_b_width);
++line_num;
- str = stringf("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type).c_str(), input_a_width+input_b_width,
+ str = stringf("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type.str()).c_str(), input_a_width+input_b_width,
input_a_line, input_b_line);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
curr_cell.clear();
@@ -852,12 +852,12 @@ struct BtorDumper
}
}
- RTLIL::SigSpec* get_cell_output(RTLIL::Cell* cell)
+ const RTLIL::SigSpec* get_cell_output(RTLIL::Cell* cell)
{
- RTLIL::SigSpec *output_sig = nullptr;
+ const RTLIL::SigSpec *output_sig = nullptr;
if (cell->type == "$memrd")
{
- output_sig = &cell->connections.at(RTLIL::IdString("\\DATA"));
+ output_sig = &cell->getPort(RTLIL::IdString("\\DATA"));
}
else if(cell->type == "$memwr" || cell->type == "$assert")
{
@@ -865,11 +865,11 @@ struct BtorDumper
}
else if(cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffsr")
{
- output_sig = &cell->connections.at(RTLIL::IdString("\\Q"));
+ output_sig = &cell->getPort(RTLIL::IdString("\\Q"));
}
else
{
- output_sig = &cell->connections.at(RTLIL::IdString("\\Y"));
+ output_sig = &cell->getPort(RTLIL::IdString("\\Y"));
}
return output_sig;
}
@@ -879,19 +879,19 @@ struct BtorDumper
int l = dump_wire(wire);
++line_num;
str = stringf("%d root 1 %d", line_num, l);
- fprintf(f, "%s\n", str.c_str());
+ f << stringf("%s\n", str.c_str());
}
void dump()
{
- fprintf(f, ";module %s\n", cstr(module->name));
+ f << stringf(";module %s\n", cstr(module->name));
log("creating intermediate wires map\n");
//creating map of intermediate wires as output of some cell
- for (auto it = module->cells.begin(); it != module->cells.end(); ++it)
+ for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it)
{
RTLIL::Cell *cell = it->second;
- RTLIL::SigSpec* output_sig = get_cell_output(cell);
+ const RTLIL::SigSpec* output_sig = get_cell_output(cell);
if(output_sig==nullptr)
continue;
RTLIL::SigSpec s = sigmap(*output_sig);
@@ -899,11 +899,11 @@ struct BtorDumper
log(" - %s\n", cstr(it->second->type));
if (cell->type == "$memrd")
{
- for(unsigned i=0; i<output_sig->chunks.size(); ++i)
+ for(unsigned i=0; i<output_sig->chunks().size(); ++i)
{
- RTLIL::Wire *w = output_sig->chunks[i].wire;
+ RTLIL::Wire *w = output_sig->chunks().at(i).wire;
RTLIL::IdString wire_id = w->name;
- inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks[i]));
+ inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks().at(i)));
}
}
else if(cell->type == "$memwr")
@@ -912,22 +912,22 @@ struct BtorDumper
}
else if(cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffsr")
{
- RTLIL::IdString wire_id = output_sig->chunks[0].wire->name;
- for(unsigned i=0; i<output_sig->chunks.size(); ++i)
+ RTLIL::IdString wire_id = output_sig->chunks().front().wire->name;
+ for(unsigned i=0; i<output_sig->chunks().size(); ++i)
{
- RTLIL::Wire *w = output_sig->chunks[i].wire;
+ RTLIL::Wire *w = output_sig->chunks().at(i).wire;
RTLIL::IdString wire_id = w->name;
- inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks[i]));
+ inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks().at(i)));
basic_wires[wire_id] = true;
}
}
else
{
- for(unsigned i=0; i<output_sig->chunks.size(); ++i)
+ for(unsigned i=0; i<output_sig->chunks().size(); ++i)
{
- RTLIL::Wire *w = output_sig->chunks[i].wire;
+ RTLIL::Wire *w = output_sig->chunks().at(i).wire;
RTLIL::IdString wire_id = w->name;
- inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks[i]));
+ inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks().at(i)));
}
}
}
@@ -936,23 +936,23 @@ struct BtorDumper
std::map<int, RTLIL::Wire*> inputs, outputs;
std::vector<RTLIL::Wire*> safety;
- for (auto &wire_it : module->wires) {
+ for (auto &wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_input)
inputs[wire->port_id] = wire;
if (wire->port_output) {
outputs[wire->port_id] = wire;
- if (wire->name.find("safety") != std::string::npos )
+ if (wire->name.str().find("safety") != std::string::npos )
safety.push_back(wire);
}
}
- fprintf(f, ";inputs\n");
+ f << stringf(";inputs\n");
for (auto &it : inputs) {
RTLIL::Wire *wire = it.second;
dump_wire(wire);
}
- fprintf(f, "\n");
+ f << stringf("\n");
log("writing memories\n");
for(auto mem_it = module->memories.begin(); mem_it != module->memories.end(); ++mem_it)
@@ -967,7 +967,7 @@ struct BtorDumper
}
log("writing cells\n");
- for(auto cell_it = module->cells.begin(); cell_it != module->cells.end(); ++cell_it)
+ for(auto cell_it = module->cells_.begin(); cell_it != module->cells_.end(); ++cell_it)
{
dump_cell(cell_it->second);
}
@@ -975,19 +975,19 @@ struct BtorDumper
for(auto it: safety)
dump_property(it);
- fprintf(f, "\n");
+ f << stringf("\n");
log("writing outputs info\n");
- fprintf(f, ";outputs\n");
+ f << stringf(";outputs\n");
for (auto &it : outputs) {
RTLIL::Wire *wire = it.second;
int l = dump_wire(wire);
- fprintf(f, ";%d %s", l, cstr(wire->name));
+ f << stringf(";%d %s", l, cstr(wire->name));
}
- fprintf(f, "\n");
+ f << stringf("\n");
}
- static void dump(FILE *f, RTLIL::Module *module, RTLIL::Design *design, BtorDumperConfig &config)
+ static void dump(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BtorDumperConfig &config)
{
BtorDumper dumper(f, module, design, &config);
dumper.dump();
@@ -1006,7 +1006,7 @@ struct BtorBackend : public Backend {
log("Write the current design to an BTOR file.\n");
}
- virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
std::string top_module_name;
std::string buf_type, buf_in, buf_out;
@@ -1020,18 +1020,18 @@ struct BtorBackend : public Backend {
extra_args(f, filename, args, argidx);
if (top_module_name.empty())
- for (auto & mod_it:design->modules)
+ for (auto & mod_it:design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
- top_module_name = mod_it.first;
+ top_module_name = mod_it.first.str();
- fprintf(f, "; Generated by %s\n", yosys_version_str);
- fprintf(f, "; %s developed and maintained by Clifford Wolf <clifford@clifford.at>\n", yosys_version_str);
- fprintf(f, "; BTOR Backend developed by Ahmed Irfan <irfan@fbk.eu> - Fondazione Bruno Kessler, Trento, Italy\n");
- fprintf(f, ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
+ *f << stringf("; Generated by %s\n", yosys_version_str);
+ *f << stringf("; %s developed and maintained by Clifford Wolf <clifford@clifford.at>\n", yosys_version_str);
+ *f << stringf("; BTOR Backend developed by Ahmed Irfan <irfan@fbk.eu> - Fondazione Bruno Kessler, Trento, Italy\n");
+ *f << stringf(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
std::vector<RTLIL::Module*> mod_list;
- for (auto module_it : design->modules)
+ for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox"))
@@ -1041,7 +1041,7 @@ struct BtorBackend : public Backend {
log_error("Found unmapped processes in module %s: unmapped processes are not supported in BTOR backend!\n", RTLIL::id2cstr(module->name));
if (module->name == RTLIL::escape_id(top_module_name)) {
- BtorDumper::dump(f, module, design, config);
+ BtorDumper::dump(*f, module, design, config);
top_module_name.clear();
continue;
}
@@ -1053,7 +1053,7 @@ struct BtorBackend : public Backend {
log_error("Can't find top module `%s'!\n", top_module_name.c_str());
for (auto module : mod_list)
- BtorDumper::dump(f, module, design, config);
+ BtorDumper::dump(*f, module, design, config);
}
} BtorBackend;
diff --git a/backends/btor/verilog2btor.sh b/backends/btor/verilog2btor.sh
index 870f0a28..ab45b490 100755
--- a/backends/btor/verilog2btor.sh
+++ b/backends/btor/verilog2btor.sh
@@ -17,14 +17,14 @@ FULL_PATH=$(readlink -f $1)
DIR=$(dirname $FULL_PATH)
./yosys -q -p "
-read_verilog $1;
+read_verilog -sv $1;
hierarchy -top $3;
hierarchy -libdir $DIR;
hierarchy -check;
proc;
opt; opt_const -mux_undef; opt;
rename -hide;;;
-techmap -share_map pmux2mux.v;;
+#techmap -share_map pmux2mux.v;;
splice; opt;
memory_dff -wr_only;
memory_collect;;
diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc
index 1748ed81..ccedd91d 100644
--- a/backends/edif/edif.cc
+++ b/backends/edif/edif.cc
@@ -26,9 +26,9 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
-#include <assert.h>
-#define EDIF_NAME(_id) edif_names(RTLIL::unescape_id(_id)).c_str()
+#define EDIF_DEF(_id) edif_names(RTLIL::unescape_id(_id), true).c_str()
+#define EDIF_REF(_id) edif_names(RTLIL::unescape_id(_id), false).c_str()
namespace
{
@@ -40,8 +40,13 @@ namespace
EdifNames() : counter(1) { }
- std::string operator()(std::string id)
+ std::string operator()(std::string id, bool define)
{
+ if (define) {
+ std::string new_id = operator()(id, false);
+ return new_id != id ? stringf("(rename %s \"%s\")", new_id.c_str(), id.c_str()) : id;
+ }
+
if (name_map.count(id) > 0)
return name_map.at(id);
if (generated_names.count(id) > 0)
@@ -74,7 +79,7 @@ namespace
}
generated_names.insert(gen_name);
name_map[id] = gen_name;
- return stringf("(rename %s \"%s\")", gen_name.c_str(), id.c_str());
+ return gen_name;
}
};
}
@@ -98,12 +103,12 @@ struct EdifBackend : public Backend {
log("is targeted.\n");
log("\n");
}
- virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing EDIF backend.\n");
std::string top_module_name;
- std::map<std::string, std::set<std::string>> lib_cell_ports;
+ std::map<RTLIL::IdString, std::set<RTLIL::IdString>> lib_cell_ports;
CellTypes ct(design);
EdifNames edif_names;
@@ -119,31 +124,31 @@ struct EdifBackend : public Backend {
extra_args(f, filename, args, argidx);
if (top_module_name.empty())
- for (auto & mod_it:design->modules)
+ for (auto & mod_it:design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
- top_module_name = mod_it.first;
+ top_module_name = mod_it.first.str();
- for (auto module_it : design->modules)
+ for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox"))
continue;
if (top_module_name.empty())
- top_module_name = module->name;
+ top_module_name = module->name.str();
if (module->processes.size() != 0)
log_error("Found unmapped processes in module %s: unmapped processes are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name));
if (module->memories.size() != 0)
log_error("Found munmapped emories in module %s: unmapped memories are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name));
- for (auto cell_it : module->cells)
+ 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_bool_attribute("\\blackbox")) {
lib_cell_ports[cell->type];
- for (auto p : cell->connections) {
- if (p.second.width > 1)
+ for (auto p : cell->connections()) {
+ if (p.second.size() > 1)
log_error("Found multi-bit port %s on library cell %s.%s (%s): not supported in EDIF backend!\n",
RTLIL::id2cstr(p.first), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
lib_cell_ports[cell->type].insert(p.first);
@@ -155,38 +160,38 @@ struct EdifBackend : public Backend {
if (top_module_name.empty())
log_error("No module found in design!\n");
- fprintf(f, "(edif %s\n", EDIF_NAME(top_module_name));
- fprintf(f, " (edifVersion 2 0 0)\n");
- fprintf(f, " (edifLevel 0)\n");
- fprintf(f, " (keywordMap (keywordLevel 0))\n");
- fprintf(f, " (comment \"Generated by %s\")\n", yosys_version_str);
-
- fprintf(f, " (external LIB\n");
- fprintf(f, " (edifLevel 0)\n");
- fprintf(f, " (technology (numberDefinition))\n");
-
- fprintf(f, " (cell GND\n");
- fprintf(f, " (cellType GENERIC)\n");
- fprintf(f, " (view VIEW_NETLIST\n");
- fprintf(f, " (viewType NETLIST)\n");
- fprintf(f, " (interface (port G (direction OUTPUT)))\n");
- fprintf(f, " )\n");
- fprintf(f, " )\n");
-
- fprintf(f, " (cell VCC\n");
- fprintf(f, " (cellType GENERIC)\n");
- fprintf(f, " (view VIEW_NETLIST\n");
- fprintf(f, " (viewType NETLIST)\n");
- fprintf(f, " (interface (port P (direction OUTPUT)))\n");
- fprintf(f, " )\n");
- fprintf(f, " )\n");
+ *f << stringf("(edif %s\n", EDIF_DEF(top_module_name));
+ *f << stringf(" (edifVersion 2 0 0)\n");
+ *f << stringf(" (edifLevel 0)\n");
+ *f << stringf(" (keywordMap (keywordLevel 0))\n");
+ *f << stringf(" (comment \"Generated by %s\")\n", yosys_version_str);
+
+ *f << stringf(" (external LIB\n");
+ *f << stringf(" (edifLevel 0)\n");
+ *f << stringf(" (technology (numberDefinition))\n");
+
+ *f << stringf(" (cell GND\n");
+ *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(" )\n");
+ *f << stringf(" )\n");
+
+ *f << stringf(" (cell VCC\n");
+ *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(" )\n");
+ *f << stringf(" )\n");
for (auto &cell_it : lib_cell_ports) {
- fprintf(f, " (cell %s\n", EDIF_NAME(cell_it.first));
- fprintf(f, " (cellType GENERIC)\n");
- fprintf(f, " (view VIEW_NETLIST\n");
- fprintf(f, " (viewType NETLIST)\n");
- fprintf(f, " (interface\n");
+ *f << stringf(" (cell %s\n", EDIF_DEF(cell_it.first));
+ *f << stringf(" (cellType GENERIC)\n");
+ *f << stringf(" (view VIEW_NETLIST\n");
+ *f << stringf(" (viewType NETLIST)\n");
+ *f << stringf(" (interface\n");
for (auto &port_it : cell_it.second) {
const char *dir = "INOUT";
if (ct.cell_known(cell_it.first)) {
@@ -195,23 +200,23 @@ struct EdifBackend : public Backend {
else if (!ct.cell_input(cell_it.first, port_it))
dir = "OUTPUT";
}
- fprintf(f, " (port %s (direction %s))\n", EDIF_NAME(port_it), dir);
+ *f << stringf(" (port %s (direction %s))\n", EDIF_DEF(port_it), dir);
}
- fprintf(f, " )\n");
- fprintf(f, " )\n");
- fprintf(f, " )\n");
+ *f << stringf(" )\n");
+ *f << stringf(" )\n");
+ *f << stringf(" )\n");
}
- fprintf(f, " )\n");
+ *f << stringf(" )\n");
std::vector<RTLIL::Module*> sorted_modules;
// extract module dependencies
std::map<RTLIL::Module*, std::set<RTLIL::Module*>> module_deps;
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
module_deps[mod_it.second] = std::set<RTLIL::Module*>();
- for (auto &cell_it : mod_it.second->cells)
- if (design->modules.count(cell_it.second->type) > 0)
- module_deps[mod_it.second].insert(design->modules.at(cell_it.second->type));
+ for (auto &cell_it : mod_it.second->cells_)
+ if (design->modules_.count(cell_it.second->type) > 0)
+ module_deps[mod_it.second].insert(design->modules_.at(cell_it.second->type));
}
// simple good-enough topological sort
@@ -233,9 +238,9 @@ struct EdifBackend : public Backend {
}
- fprintf(f, " (library DESIGN\n");
- fprintf(f, " (edifLevel 0)\n");
- fprintf(f, " (technology (numberDefinition))\n");
+ *f << stringf(" (library DESIGN\n");
+ *f << stringf(" (edifLevel 0)\n");
+ *f << stringf(" (technology (numberDefinition))\n");
for (auto module : sorted_modules)
{
if (module->get_bool_attribute("\\blackbox"))
@@ -244,12 +249,12 @@ struct EdifBackend : public Backend {
SigMap sigmap(module);
std::map<RTLIL::SigSpec, std::set<std::string>> net_join_db;
- fprintf(f, " (cell %s\n", EDIF_NAME(module->name));
- fprintf(f, " (cellType GENERIC)\n");
- fprintf(f, " (view VIEW_NETLIST\n");
- fprintf(f, " (viewType NETLIST)\n");
- fprintf(f, " (interface\n");
- for (auto &wire_it : module->wires) {
+ *f << stringf(" (cell %s\n", EDIF_DEF(module->name));
+ *f << stringf(" (cellType GENERIC)\n");
+ *f << stringf(" (view VIEW_NETLIST\n");
+ *f << stringf(" (viewType NETLIST)\n");
+ *f << stringf(" (interface\n");
+ for (auto &wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_id == 0)
continue;
@@ -259,31 +264,31 @@ struct EdifBackend : public Backend {
else if (!wire->port_input)
dir = "OUTPUT";
if (wire->width == 1) {
- fprintf(f, " (port %s (direction %s))\n", EDIF_NAME(wire->name), dir);
+ *f << stringf(" (port %s (direction %s))\n", EDIF_DEF(wire->name), dir);
RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire));
- net_join_db[sig].insert(stringf("(portRef %s)", EDIF_NAME(wire->name)));
+ net_join_db[sig].insert(stringf("(portRef %s)", EDIF_REF(wire->name)));
} else {
- fprintf(f, " (port (array %s %d) (direction %s))\n", EDIF_NAME(wire->name), wire->width, dir);
+ *f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEF(wire->name), wire->width, dir);
for (int i = 0; i < wire->width; i++) {
- RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire, 1, i));
- net_join_db[sig].insert(stringf("(portRef (member %s %d))", EDIF_NAME(wire->name), i));
+ RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire, i));
+ net_join_db[sig].insert(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), i));
}
}
}
- fprintf(f, " )\n");
- fprintf(f, " (contents\n");
- fprintf(f, " (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n");
- fprintf(f, " (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n");
- for (auto &cell_it : module->cells) {
+ *f << stringf(" )\n");
+ *f << stringf(" (contents\n");
+ *f << stringf(" (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n");
+ *f << stringf(" (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n");
+ for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
- fprintf(f, " (instance %s\n", EDIF_NAME(cell->name));
- fprintf(f, " (viewRef VIEW_NETLIST (cellRef %s%s))", EDIF_NAME(cell->type),
+ *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)
- fprintf(f, "\n (property %s (string \"%s\"))", EDIF_NAME(p.first), p.second.decode_string().c_str());
+ *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())
- fprintf(f, "\n (property %s (integer %u))", EDIF_NAME(p.first), p.second.as_int());
+ *f << stringf("\n (property %s (integer %u))", EDIF_DEF(p.first), p.second.as_int());
else {
std::string hex_string = "";
for (size_t i = 0; i < p.second.bits.size(); i += 4) {
@@ -295,53 +300,48 @@ struct EdifBackend : public Backend {
char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
hex_string = std::string(digit_str) + hex_string;
}
- fprintf(f, "\n (property %s (string \"%s\"))", EDIF_NAME(p.first), hex_string.c_str());
+ *f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(p.first), hex_string.c_str());
}
- fprintf(f, ")\n");
- for (auto &p : cell->connections) {
+ *f << stringf(")\n");
+ for (auto &p : cell->connections()) {
RTLIL::SigSpec sig = sigmap(p.second);
- sig.expand();
- for (int i = 0; i < sig.width; i++) {
- RTLIL::SigSpec sigbit(sig.chunks.at(i));
- std::string portname = sig.width > 1 ? stringf("%s[%d]", RTLIL::id2cstr(p.first), i) : RTLIL::id2cstr(p.first);
- net_join_db[sigbit].insert(stringf("(portRef %s (instanceRef %s))", edif_names(portname).c_str(), EDIF_NAME(cell->name)));
- }
+ for (int i = 0; i < SIZE(sig); i++)
+ if (sig.size() == 1)
+ net_join_db[sig[i]].insert(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name)));
+ else
+ net_join_db[sig[i]].insert(stringf("(portRef (member %s %d) (instanceRef %s))", EDIF_REF(p.first), i, EDIF_REF(cell->name)));
}
}
for (auto &it : net_join_db) {
- RTLIL::SigSpec sig = it.first;
- sig.optimize();
- log_assert(sig.width == 1);
- if (sig.chunks.at(0).wire == NULL) {
- if (sig.chunks.at(0).data.bits.at(0) != RTLIL::State::S0 && sig.chunks.at(0).data.bits.at(0) != RTLIL::State::S1)
- continue;
- }
+ RTLIL::SigBit sig = it.first;
+ if (sig.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1)
+ continue;
std::string netname = log_signal(sig);
for (size_t i = 0; i < netname.size(); i++)
if (netname[i] == ' ' || netname[i] == '\\')
netname.erase(netname.begin() + i--);
- fprintf(f, " (net %s (joined\n", edif_names(netname).c_str());
+ *f << stringf(" (net %s (joined\n", EDIF_DEF(netname));
for (auto &ref : it.second)
- fprintf(f, " %s\n", ref.c_str());
- if (sig.chunks.at(0).wire == NULL) {
- if (sig.chunks.at(0).data.bits.at(0) == RTLIL::State::S0)
- fprintf(f, " (portRef G (instanceRef GND))\n");
- if (sig.chunks.at(0).data.bits.at(0) == RTLIL::State::S1)
- fprintf(f, " (portRef P (instanceRef VCC))\n");
+ *f << stringf(" %s\n", ref.c_str());
+ if (sig.wire == NULL) {
+ if (sig == RTLIL::State::S0)
+ *f << stringf(" (portRef G (instanceRef GND))\n");
+ if (sig == RTLIL::State::S1)
+ *f << stringf(" (portRef P (instanceRef VCC))\n");
}
- fprintf(f, " ))\n");
+ *f << stringf(" ))\n");
}
- fprintf(f, " )\n");
- fprintf(f, " )\n");
- fprintf(f, " )\n");
+ *f << stringf(" )\n");
+ *f << stringf(" )\n");
+ *f << stringf(" )\n");
}
- fprintf(f, " )\n");
+ *f << stringf(" )\n");
- fprintf(f, " (design %s\n", EDIF_NAME(top_module_name));
- fprintf(f, " (cellRef %s (libraryRef DESIGN))\n", EDIF_NAME(top_module_name));
- fprintf(f, " )\n");
+ *f << stringf(" (design %s\n", EDIF_DEF(top_module_name));
+ *f << stringf(" (cellRef %s (libraryRef DESIGN))\n", EDIF_REF(top_module_name));
+ *f << stringf(" )\n");
- fprintf(f, ")\n");
+ *f << stringf(")\n");
}
} EdifBackend;
diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc
index c585d40c..48d818d7 100644
--- a/backends/ilang/ilang_backend.cc
+++ b/backends/ilang/ilang_backend.cc
@@ -23,16 +23,12 @@
*/
#include "ilang_backend.h"
-#include "kernel/register.h"
-#include "kernel/log.h"
-#include <string>
-#include <assert.h>
-#include <string.h>
+#include "kernel/yosys.h"
#include <errno.h>
using namespace ILANG_BACKEND;
-void ILANG_BACKEND::dump_const(FILE *f, const RTLIL::Const &data, int width, int offset, bool autoint)
+void ILANG_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int width, int offset, bool autoint)
{
if (width < 0)
width = data.bits.size() - offset;
@@ -40,7 +36,7 @@ void ILANG_BACKEND::dump_const(FILE *f, const RTLIL::Const &data, int width, int
if (width == 32 && autoint) {
int32_t val = 0;
for (int i = 0; i < width; i++) {
- assert(offset+i < (int)data.bits.size());
+ log_assert(offset+i < (int)data.bits.size());
switch (data.bits[offset+i]) {
case RTLIL::S0: break;
case RTLIL::S1: val |= 1 << i; break;
@@ -48,220 +44,230 @@ void ILANG_BACKEND::dump_const(FILE *f, const RTLIL::Const &data, int width, int
}
}
if (val >= 0) {
- fprintf(f, "%d", val);
+ f << stringf("%d", val);
return;
}
}
- fprintf(f, "%d'", width);
+ f << stringf("%d'", width);
for (int i = offset+width-1; i >= offset; i--) {
- assert(i < (int)data.bits.size());
+ log_assert(i < (int)data.bits.size());
switch (data.bits[i]) {
- case RTLIL::S0: fprintf(f, "0"); break;
- case RTLIL::S1: fprintf(f, "1"); break;
- case RTLIL::Sx: fprintf(f, "x"); break;
- case RTLIL::Sz: fprintf(f, "z"); break;
- case RTLIL::Sa: fprintf(f, "-"); break;
- case RTLIL::Sm: fprintf(f, "m"); break;
+ case RTLIL::S0: f << stringf("0"); break;
+ case RTLIL::S1: f << stringf("1"); break;
+ case RTLIL::Sx: f << stringf("x"); break;
+ case RTLIL::Sz: f << stringf("z"); break;
+ case RTLIL::Sa: f << stringf("-"); break;
+ case RTLIL::Sm: f << stringf("m"); break;
}
}
} else {
- fprintf(f, "\"");
+ f << stringf("\"");
std::string str = data.decode_string();
for (size_t i = 0; i < str.size(); i++) {
if (str[i] == '\n')
- fprintf(f, "\\n");
+ f << stringf("\\n");
else if (str[i] == '\t')
- fprintf(f, "\\t");
+ f << stringf("\\t");
else if (str[i] < 32)
- fprintf(f, "\\%03o", str[i]);
+ f << stringf("\\%03o", str[i]);
else if (str[i] == '"')
- fprintf(f, "\\\"");
+ f << stringf("\\\"");
else if (str[i] == '\\')
- fprintf(f, "\\\\");
+ f << stringf("\\\\");
else
- fputc(str[i], f);
+ f << str[i];
}
- fprintf(f, "\"");
+ f << stringf("\"");
}
}
-void ILANG_BACKEND::dump_sigchunk(FILE *f, const RTLIL::SigChunk &chunk, bool autoint)
+void ILANG_BACKEND::dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint)
{
if (chunk.wire == NULL) {
dump_const(f, chunk.data, chunk.width, chunk.offset, autoint);
} else {
if (chunk.width == chunk.wire->width && chunk.offset == 0)
- fprintf(f, "%s", chunk.wire->name.c_str());
+ f << stringf("%s", chunk.wire->name.c_str());
else if (chunk.width == 1)
- fprintf(f, "%s [%d]", chunk.wire->name.c_str(), chunk.offset);
+ f << stringf("%s [%d]", chunk.wire->name.c_str(), chunk.offset);
else
- fprintf(f, "%s [%d:%d]", chunk.wire->name.c_str(), chunk.offset+chunk.width-1, chunk.offset);
+ f << stringf("%s [%d:%d]", chunk.wire->name.c_str(), chunk.offset+chunk.width-1, chunk.offset);
}
}
-void ILANG_BACKEND::dump_sigspec(FILE *f, const RTLIL::SigSpec &sig, bool autoint)
+void ILANG_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint)
{
- if (sig.chunks.size() == 1) {
- dump_sigchunk(f, sig.chunks[0], autoint);
+ if (sig.is_chunk()) {
+ dump_sigchunk(f, sig.as_chunk(), autoint);
} else {
- fprintf(f, "{ ");
- for (auto it = sig.chunks.rbegin(); it != sig.chunks.rend(); it++) {
+ f << stringf("{ ");
+ for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); it++) {
dump_sigchunk(f, *it, false);
- fprintf(f, " ");
+ f << stringf(" ");
}
- fprintf(f, "}");
+ f << stringf("}");
}
}
-void ILANG_BACKEND::dump_wire(FILE *f, std::string indent, const RTLIL::Wire *wire)
+void ILANG_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire)
{
- for (auto it = wire->attributes.begin(); it != wire->attributes.end(); it++) {
- fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
+ std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_attributes(wire->attributes.begin(), wire->attributes.end());
+
+ for (auto it = sorted_attributes.begin(); it != sorted_attributes.end(); it++) {
+ f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
- fprintf(f, "\n");
+ f << stringf("\n");
}
- fprintf(f, "%s" "wire ", indent.c_str());
+ f << stringf("%s" "wire ", indent.c_str());
if (wire->width != 1)
- fprintf(f, "width %d ", wire->width);
+ f << stringf("width %d ", wire->width);
+ if (wire->upto)
+ f << stringf("upto ");
if (wire->start_offset != 0)
- fprintf(f, "offset %d ", wire->start_offset);
+ f << stringf("offset %d ", wire->start_offset);
if (wire->port_input && !wire->port_output)
- fprintf(f, "input %d ", wire->port_id);
+ f << stringf("input %d ", wire->port_id);
if (!wire->port_input && wire->port_output)
- fprintf(f, "output %d ", wire->port_id);
+ f << stringf("output %d ", wire->port_id);
if (wire->port_input && wire->port_output)
- fprintf(f, "inout %d ", wire->port_id);
- fprintf(f, "%s\n", wire->name.c_str());
+ f << stringf("inout %d ", wire->port_id);
+ f << stringf("%s\n", wire->name.c_str());
}
-void ILANG_BACKEND::dump_memory(FILE *f, std::string indent, const RTLIL::Memory *memory)
+void ILANG_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory)
{
- for (auto it = memory->attributes.begin(); it != memory->attributes.end(); it++) {
- fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
+ std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_attributes(memory->attributes.begin(), memory->attributes.end());
+
+ for (auto it = sorted_attributes.begin(); it != sorted_attributes.end(); it++) {
+ f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
- fprintf(f, "\n");
+ f << stringf("\n");
}
- fprintf(f, "%s" "memory ", indent.c_str());
+ f << stringf("%s" "memory ", indent.c_str());
if (memory->width != 1)
- fprintf(f, "width %d ", memory->width);
+ f << stringf("width %d ", memory->width);
if (memory->size != 0)
- fprintf(f, "size %d ", memory->size);
- fprintf(f, "%s\n", memory->name.c_str());
+ f << stringf("size %d ", memory->size);
+ f << stringf("%s\n", memory->name.c_str());
}
-void ILANG_BACKEND::dump_cell(FILE *f, std::string indent, const RTLIL::Cell *cell)
+void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell)
{
- for (auto it = cell->attributes.begin(); it != cell->attributes.end(); it++) {
- fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
+ std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_attributes(cell->attributes.begin(), cell->attributes.end());
+ std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_parameters(cell->parameters.begin(), cell->parameters.end());
+ std::map<RTLIL::IdString, RTLIL::SigSpec, RTLIL::sort_by_id_str> sorted_connections(cell->connections().begin(), cell->connections().end());
+
+ for (auto it = sorted_attributes.begin(); it != sorted_attributes.end(); it++) {
+ f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
- fprintf(f, "\n");
+ f << stringf("\n");
}
- fprintf(f, "%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
- for (auto it = cell->parameters.begin(); it != cell->parameters.end(); it++) {
- fprintf(f, "%s parameter%s %s ", indent.c_str(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it->first.c_str());
+ f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
+ for (auto it = sorted_parameters.begin(); it != sorted_parameters.end(); it++) {
+ f << stringf("%s parameter%s %s ", indent.c_str(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it->first.c_str());
dump_const(f, it->second);
- fprintf(f, "\n");
+ f << stringf("\n");
}
- for (auto it = cell->connections.begin(); it != cell->connections.end(); it++) {
- fprintf(f, "%s connect %s ", indent.c_str(), it->first.c_str());
+ for (auto it = sorted_connections.begin(); it != sorted_connections.end(); it++) {
+ f << stringf("%s connect %s ", indent.c_str(), it->first.c_str());
dump_sigspec(f, it->second);
- fprintf(f, "\n");
+ f << stringf("\n");
}
- fprintf(f, "%s" "end\n", indent.c_str());
+ f << stringf("%s" "end\n", indent.c_str());
}
-void ILANG_BACKEND::dump_proc_case_body(FILE *f, std::string indent, const RTLIL::CaseRule *cs)
+void ILANG_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs)
{
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)
{
- fprintf(f, "%s" "assign ", indent.c_str());
+ f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, it->first);
- fprintf(f, " ");
+ f << stringf(" ");
dump_sigspec(f, it->second);
- fprintf(f, "\n");
+ f << stringf("\n");
}
for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
dump_proc_switch(f, indent, *it);
}
-void ILANG_BACKEND::dump_proc_switch(FILE *f, std::string indent, const RTLIL::SwitchRule *sw)
+void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw)
{
for (auto it = sw->attributes.begin(); it != sw->attributes.end(); it++) {
- fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
+ f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
- fprintf(f, "\n");
+ f << stringf("\n");
}
- fprintf(f, "%s" "switch ", indent.c_str());
+ f << stringf("%s" "switch ", indent.c_str());
dump_sigspec(f, sw->signal);
- fprintf(f, "\n");
+ f << stringf("\n");
for (auto it = sw->cases.begin(); it != sw->cases.end(); it++)
{
- fprintf(f, "%s case ", indent.c_str());
+ f << stringf("%s case ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) {
if (i > 0)
- fprintf(f, ", ");
+ f << stringf(", ");
dump_sigspec(f, (*it)->compare[i]);
}
- fprintf(f, "\n");
+ f << stringf("\n");
dump_proc_case_body(f, indent + " ", *it);
}
- fprintf(f, "%s" "end\n", indent.c_str());
+ f << stringf("%s" "end\n", indent.c_str());
}
-void ILANG_BACKEND::dump_proc_sync(FILE *f, std::string indent, const RTLIL::SyncRule *sy)
+void ILANG_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy)
{
- fprintf(f, "%s" "sync ", indent.c_str());
+ f << stringf("%s" "sync ", indent.c_str());
switch (sy->type) {
- if (0) case RTLIL::ST0: fprintf(f, "low ");
- if (0) case RTLIL::ST1: fprintf(f, "high ");
- if (0) case RTLIL::STp: fprintf(f, "posedge ");
- if (0) case RTLIL::STn: fprintf(f, "negedge ");
- if (0) case RTLIL::STe: fprintf(f, "edge ");
+ if (0) case RTLIL::ST0: f << stringf("low ");
+ if (0) case RTLIL::ST1: f << stringf("high ");
+ if (0) case RTLIL::STp: f << stringf("posedge ");
+ if (0) case RTLIL::STn: f << stringf("negedge ");
+ if (0) case RTLIL::STe: f << stringf("edge ");
dump_sigspec(f, sy->signal);
- fprintf(f, "\n");
+ f << stringf("\n");
break;
- case RTLIL::STa: fprintf(f, "always\n"); break;
- case RTLIL::STi: fprintf(f, "init\n"); break;
+ case RTLIL::STa: f << stringf("always\n"); break;
+ case RTLIL::STi: f << stringf("init\n"); break;
}
for (auto it = sy->actions.begin(); it != sy->actions.end(); it++) {
- fprintf(f, "%s update ", indent.c_str());
+ f << stringf("%s update ", indent.c_str());
dump_sigspec(f, it->first);
- fprintf(f, " ");
+ f << stringf(" ");
dump_sigspec(f, it->second);
- fprintf(f, "\n");
+ f << stringf("\n");
}
}
-void ILANG_BACKEND::dump_proc(FILE *f, std::string indent, const RTLIL::Process *proc)
+void ILANG_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc)
{
for (auto it = proc->attributes.begin(); it != proc->attributes.end(); it++) {
- fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
+ f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
- fprintf(f, "\n");
+ f << stringf("\n");
}
- fprintf(f, "%s" "process %s\n", indent.c_str(), proc->name.c_str());
+ f << stringf("%s" "process %s\n", indent.c_str(), proc->name.c_str());
dump_proc_case_body(f, indent + " ", &proc->root_case);
for (auto it = proc->syncs.begin(); it != proc->syncs.end(); it++)
dump_proc_sync(f, indent + " ", *it);
- fprintf(f, "%s" "end\n", indent.c_str());
+ f << stringf("%s" "end\n", indent.c_str());
}
-void ILANG_BACKEND::dump_conn(FILE *f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
+void ILANG_BACKEND::dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
{
- fprintf(f, "%s" "connect ", indent.c_str());
+ f << stringf("%s" "connect ", indent.c_str());
dump_sigspec(f, left);
- fprintf(f, " ");
+ f << stringf(" ");
dump_sigspec(f, right);
- fprintf(f, "\n");
+ f << stringf("\n");
}
-void ILANG_BACKEND::dump_module(FILE *f, std::string indent, const RTLIL::Module *module, const RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
+void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
{
bool print_header = flag_m || design->selected_whole_module(module->name);
bool print_body = !flag_n || !design->selected_whole_module(module->name);
@@ -269,51 +275,71 @@ void ILANG_BACKEND::dump_module(FILE *f, std::string indent, const RTLIL::Module
if (print_header)
{
for (auto it = module->attributes.begin(); it != module->attributes.end(); it++) {
- fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
+ f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
- fprintf(f, "\n");
+ f << stringf("\n");
}
- fprintf(f, "%s" "module %s\n", indent.c_str(), module->name.c_str());
+ f << stringf("%s" "module %s\n", indent.c_str(), module->name.c_str());
}
if (print_body)
{
- for (auto it = module->wires.begin(); it != module->wires.end(); it++)
- if (!only_selected || design->selected(module, it->second)) {
+ std::vector<RTLIL::Wire*> sorted_wires;
+ for (auto it : module->wires())
+ sorted_wires.push_back(it);
+ std::sort(sorted_wires.begin(), sorted_wires.end(), RTLIL::sort_by_name_str<RTLIL::Wire>());
+
+ std::vector<RTLIL::Memory*> sorted_memories;
+ for (auto it : module->memories)
+ sorted_memories.push_back(it.second);
+ std::sort(sorted_memories.begin(), sorted_memories.end(), RTLIL::sort_by_name_str<RTLIL::Memory>());
+
+ std::vector<RTLIL::Cell*> sorted_cells;
+ for (auto it : module->cells())
+ sorted_cells.push_back(it);
+ std::sort(sorted_cells.begin(), sorted_cells.end(), RTLIL::sort_by_name_str<RTLIL::Cell>());
+
+ std::vector<RTLIL::Process*> sorted_processes;
+ for (auto it : module->processes)
+ sorted_processes.push_back(it.second);
+ std::sort(sorted_processes.begin(), sorted_processes.end(), RTLIL::sort_by_name_str<RTLIL::Process>());
+
+ for (auto it : sorted_wires)
+ if (!only_selected || design->selected(module, it)) {
if (only_selected)
- fprintf(f, "\n");
- dump_wire(f, indent + " ", it->second);
+ f << stringf("\n");
+ dump_wire(f, indent + " ", it);
}
- for (auto it = module->memories.begin(); it != module->memories.end(); it++)
- if (!only_selected || design->selected(module, it->second)) {
+ for (auto it : sorted_memories)
+ if (!only_selected || design->selected(module, it)) {
if (only_selected)
- fprintf(f, "\n");
- dump_memory(f, indent + " ", it->second);
+ f << stringf("\n");
+ dump_memory(f, indent + " ", it);
}
- for (auto it = module->cells.begin(); it != module->cells.end(); it++)
- if (!only_selected || design->selected(module, it->second)) {
+ for (auto it : sorted_cells)
+ if (!only_selected || design->selected(module, it)) {
if (only_selected)
- fprintf(f, "\n");
- dump_cell(f, indent + " ", it->second);
+ f << stringf("\n");
+ dump_cell(f, indent + " ", it);
}
- for (auto it = module->processes.begin(); it != module->processes.end(); it++)
- if (!only_selected || design->selected(module, it->second)) {
+ for (auto it : sorted_processes)
+ if (!only_selected || design->selected(module, it)) {
if (only_selected)
- fprintf(f, "\n");
- dump_proc(f, indent + " ", it->second);
+ f << stringf("\n");
+ dump_proc(f, indent + " ", it);
}
bool first_conn_line = true;
- for (auto it = module->connections.begin(); it != module->connections.end(); it++) {
+ for (auto it = module->connections().begin(); it != module->connections().end(); it++) {
bool show_conn = !only_selected;
if (only_selected) {
RTLIL::SigSpec sigs = it->first;
sigs.append(it->second);
- for (auto &c : sigs.chunks) {
+ for (auto &c : sigs.chunks()) {
if (c.wire == NULL || !design->selected(module, c.wire))
continue;
show_conn = true;
@@ -321,7 +347,7 @@ void ILANG_BACKEND::dump_module(FILE *f, std::string indent, const RTLIL::Module
}
if (show_conn) {
if (only_selected && first_conn_line)
- fprintf(f, "\n");
+ f << stringf("\n");
dump_conn(f, indent + " ", it->first, it->second);
first_conn_line = false;
}
@@ -329,27 +355,40 @@ void ILANG_BACKEND::dump_module(FILE *f, std::string indent, const RTLIL::Module
}
if (print_header)
- fprintf(f, "%s" "end\n", indent.c_str());
+ f << stringf("%s" "end\n", indent.c_str());
}
-void ILANG_BACKEND::dump_design(FILE *f, const RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
+void ILANG_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
{
+ int init_autoidx = autoidx;
+
if (!flag_m) {
int count_selected_mods = 0;
- for (auto it = design->modules.begin(); it != design->modules.end(); it++)
+ for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
+ if (design->selected_whole_module(it->first))
+ flag_m = true;
if (design->selected(it->second))
count_selected_mods++;
+ }
if (count_selected_mods > 1)
flag_m = true;
}
- for (auto it = design->modules.begin(); it != design->modules.end(); it++) {
+ if (!only_selected || flag_m) {
+ if (only_selected)
+ f << stringf("\n");
+ f << stringf("autoidx %d\n", autoidx);
+ }
+
+ for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
if (!only_selected || design->selected(it->second)) {
if (only_selected)
- fprintf(f, "\n");
+ f << stringf("\n");
dump_module(f, "", it->second, design, only_selected, flag_m, flag_n);
}
}
+
+ log_assert(init_autoidx == autoidx);
}
struct IlangBackend : public Backend {
@@ -367,7 +406,7 @@ struct IlangBackend : public Backend {
log(" only write selected parts of the design.\n");
log("\n");
}
- virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
bool selected = false;
@@ -385,8 +424,8 @@ struct IlangBackend : public Backend {
extra_args(f, filename, args, argidx);
log("Output filename: %s\n", filename.c_str());
- fprintf(f, "# Generated by %s\n", yosys_version_str);
- ILANG_BACKEND::dump_design(f, design, selected, true, false);
+ *f << stringf("# Generated by %s\n", yosys_version_str);
+ ILANG_BACKEND::dump_design(*f, design, selected, true, false);
}
} IlangBackend;
@@ -446,25 +485,27 @@ struct DumpPass : public Pass {
}
extra_args(args, argidx, design);
- FILE *f = NULL;
- char *buf_ptr;
- size_t buf_size;
+ std::ostream *f;
+ std::stringstream buf;
if (!filename.empty()) {
- f = fopen(filename.c_str(), append ? "a" : "w");
- if (f == NULL)
+ std::ofstream *ff = new std::ofstream;
+ ff->open(filename.c_str(), append ? std::ofstream::app : std::ofstream::trunc);
+ if (ff->fail()) {
+ delete ff;
log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+ }
+ f = ff;
} else {
- f = open_memstream(&buf_ptr, &buf_size);
+ f = &buf;
}
- ILANG_BACKEND::dump_design(f, design, true, flag_m, flag_n);
+ ILANG_BACKEND::dump_design(*f, design, true, flag_m, flag_n);
- fclose(f);
-
- if (filename.empty()) {
- log("%s", buf_ptr);
- free(buf_ptr);
+ if (!filename.empty()) {
+ delete f;
+ } else {
+ log("%s", buf.str().c_str());
}
}
} DumpPass;
diff --git a/backends/ilang/ilang_backend.h b/backends/ilang/ilang_backend.h
index fecbcc1f..159cd719 100644
--- a/backends/ilang/ilang_backend.h
+++ b/backends/ilang/ilang_backend.h
@@ -25,23 +25,27 @@
#ifndef ILANG_BACKEND_H
#define ILANG_BACKEND_H
-#include "kernel/rtlil.h"
+#include "kernel/yosys.h"
#include <stdio.h>
+YOSYS_NAMESPACE_BEGIN
+
namespace ILANG_BACKEND {
- void dump_const(FILE *f, const RTLIL::Const &data, int width = -1, int offset = 0, bool autoint = true);
- void dump_sigchunk(FILE *f, const RTLIL::SigChunk &chunk, bool autoint = true);
- void dump_sigspec(FILE *f, const RTLIL::SigSpec &sig, bool autoint = true);
- void dump_wire(FILE *f, std::string indent, const RTLIL::Wire *wire);
- void dump_memory(FILE *f, std::string indent, const RTLIL::Memory *memory);
- void dump_cell(FILE *f, std::string indent, const RTLIL::Cell *cell);
- void dump_proc_case_body(FILE *f, std::string indent, const RTLIL::CaseRule *cs);
- void dump_proc_switch(FILE *f, std::string indent, const RTLIL::SwitchRule *sw);
- void dump_proc_sync(FILE *f, std::string indent, const RTLIL::SyncRule *sy);
- void dump_proc(FILE *f, std::string indent, const RTLIL::Process *proc);
- void dump_conn(FILE *f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right);
- void dump_module(FILE *f, std::string indent, const RTLIL::Module *module, const RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false);
- void dump_design(FILE *f, const RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false);
+ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool autoint = true);
+ void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint = true);
+ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint = true);
+ void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
+ void dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory);
+ void dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell);
+ void dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs);
+ void dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw);
+ void dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy);
+ void dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc);
+ void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right);
+ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false);
+ void dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false);
}
+YOSYS_NAMESPACE_END
+
#endif
diff --git a/backends/intersynth/intersynth.cc b/backends/intersynth/intersynth.cc
index 47c1125f..8502d90f 100644
--- a/backends/intersynth/intersynth.cc
+++ b/backends/intersynth/intersynth.cc
@@ -23,30 +23,23 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
-#include <assert.h>
static std::string netname(std::set<std::string> &conntypes_code, std::set<std::string> &celltypes_code, std::set<std::string> &constcells_code, RTLIL::SigSpec sig)
{
- sig.optimize();
-
- if (sig.chunks.size() != 1)
-error:
+ if (!sig.is_fully_const() && !sig.is_wire())
log_error("Can't export composite or non-word-wide signal %s.\n", log_signal(sig));
- conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.width, sig.width, sig.width));
+ conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size()));
- if (sig.chunks[0].wire == NULL) {
- celltypes_code.insert(stringf("celltype CONST_%d b%d *CONST cfg:%d VALUE\n", sig.width, sig.width, sig.width));
- constcells_code.insert(stringf("node CONST_%d_0x%x CONST_%d CONST CONST_%d_0x%x VALUE 0x%x\n", sig.width, sig.chunks[0].data.as_int(),
- sig.width, sig.width, sig.chunks[0].data.as_int(), sig.chunks[0].data.as_int()));
- return stringf("CONST_%d_0x%x", sig.width, sig.chunks[0].data.as_int());
+ if (sig.is_fully_const()) {
+ celltypes_code.insert(stringf("celltype CONST_%d b%d *CONST cfg:%d VALUE\n", sig.size(), sig.size(), sig.size()));
+ constcells_code.insert(stringf("node CONST_%d_0x%x CONST_%d CONST CONST_%d_0x%x VALUE 0x%x\n",
+ sig.size(), sig.as_int(), sig.size(), sig.size(), sig.as_int(), sig.as_int()));
+ return stringf("CONST_%d_0x%x", sig.size(), sig.as_int());
}
- if (sig.chunks[0].offset != 0 || sig.width != sig.chunks[0].wire->width)
- goto error;
-
- return RTLIL::unescape_id(sig.chunks[0].wire->name);
+ return RTLIL::unescape_id(sig.as_wire()->name);
}
struct IntersynthBackend : public Backend {
@@ -76,7 +69,7 @@ struct IntersynthBackend : public Backend {
log("http://www.clifford.at/intersynth/\n");
log("\n");
}
- virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing INTERSYNTH backend.\n");
log_push();
@@ -108,13 +101,13 @@ struct IntersynthBackend : public Backend {
log("Output filename: %s\n", filename.c_str());
for (auto filename : libfiles) {
- FILE *f = fopen(filename.c_str(), "rt");
- if (f == NULL)
+ std::ifstream f;
+ f.open(filename.c_str());
+ if (f.fail())
log_error("Can't open lib file `%s'.\n", filename.c_str());
RTLIL::Design *lib = new RTLIL::Design;
- Frontend::frontend_call(lib, f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
+ Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
libs.push_back(lib);
- fclose(f);
}
if (libs.size() > 0)
@@ -127,14 +120,14 @@ struct IntersynthBackend : public Backend {
for (auto lib : libs)
ct.setup_design(lib);
- for (auto module_it : design->modules)
+ for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
SigMap sigmap(module);
if (module->get_bool_attribute("\\blackbox"))
continue;
- if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells.size() == 0)
+ if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells_.size() == 0)
continue;
if (selected && !design->selected_whole_module(module->name)) {
@@ -153,7 +146,7 @@ struct IntersynthBackend : public Backend {
netlists_code += stringf("netlist %s\n", RTLIL::id2cstr(module->name));
// Module Ports: "std::set<string> celltypes_code" prevents duplicate top level ports
- for (auto wire_it : module->wires) {
+ for (auto wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_input || wire->port_output) {
celltypes_code.insert(stringf("celltype !%s b%d %sPORT\n" "%s %s %d %s PORT\n",
@@ -165,7 +158,7 @@ struct IntersynthBackend : public Backend {
}
// Submodules: "std::set<string> celltypes_code" prevents duplicate cell types
- for (auto cell_it : module->cells)
+ for (auto cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
std::string celltype_code, node_code;
@@ -175,11 +168,11 @@ struct IntersynthBackend : public Backend {
celltype_code = stringf("celltype %s", RTLIL::id2cstr(cell->type));
node_code = stringf("node %s %s", RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
- for (auto &port : cell->connections) {
+ for (auto &port : cell->connections()) {
RTLIL::SigSpec sig = sigmap(port.second);
- if (sig.width != 0) {
- conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.width, sig.width, sig.width));
- celltype_code += stringf(" b%d %s%s", sig.width, ct.cell_output(cell->type, port.first) ? "*" : "", RTLIL::id2cstr(port.first));
+ if (sig.size() != 0) {
+ conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size()));
+ celltype_code += stringf(" b%d %s%s", sig.size(), ct.cell_output(cell->type, port.first) ? "*" : "", RTLIL::id2cstr(port.first));
node_code += stringf(" %s %s", RTLIL::id2cstr(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig).c_str());
}
}
@@ -205,15 +198,15 @@ struct IntersynthBackend : public Backend {
}
if (!flag_notypes) {
- fprintf(f, "### Connection Types\n");
+ *f << stringf("### Connection Types\n");
for (auto code : conntypes_code)
- fprintf(f, "%s", code.c_str());
- fprintf(f, "\n### Cell Types\n");
+ *f << stringf("%s", code.c_str());
+ *f << stringf("\n### Cell Types\n");
for (auto code : celltypes_code)
- fprintf(f, "%s", code.c_str());
+ *f << stringf("%s", code.c_str());
}
- fprintf(f, "\n### Netlists\n");
- fprintf(f, "%s", netlists_code.c_str());
+ *f << stringf("\n### Netlists\n");
+ *f << stringf("%s", netlists_code.c_str());
for (auto lib : libs)
delete lib;
diff --git a/backends/spice/spice.cc b/backends/spice/spice.cc
index e7926e90..b057063c 100644
--- a/backends/spice/spice.cc
+++ b/backends/spice/spice.cc
@@ -23,53 +23,51 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
-#include <assert.h>
-static void print_spice_net(FILE *f, RTLIL::SigSpec s, std::string &neg, std::string &pos, std::string &ncpf, int &nc_counter)
+static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, std::string &pos, std::string &ncpf, int &nc_counter)
{
- log_assert(s.chunks.size() == 1 && s.chunks[0].width == 1);
- if (s.chunks[0].wire) {
- if (s.chunks[0].wire->width > 1)
- fprintf(f, " %s[%d]", RTLIL::id2cstr(s.chunks[0].wire->name), s.chunks[0].offset);
+ if (s.wire) {
+ if (s.wire->width > 1)
+ f << stringf(" %s[%d]", RTLIL::id2cstr(s.wire->name), s.offset);
else
- fprintf(f, " %s", RTLIL::id2cstr(s.chunks[0].wire->name));
+ f << stringf(" %s", RTLIL::id2cstr(s.wire->name));
} else {
- if (s.chunks[0].data.bits.at(0) == RTLIL::State::S0)
- fprintf(f, " %s", neg.c_str());
- else if (s.chunks[0].data.bits.at(0) == RTLIL::State::S1)
- fprintf(f, " %s", pos.c_str());
+ if (s == RTLIL::State::S0)
+ f << stringf(" %s", neg.c_str());
+ else if (s == RTLIL::State::S1)
+ f << stringf(" %s", pos.c_str());
else
- fprintf(f, " %s%d", ncpf.c_str(), nc_counter++);
+ f << stringf(" %s%d", ncpf.c_str(), nc_counter++);
}
}
-static void print_spice_module(FILE *f, RTLIL::Module *module, RTLIL::Design *design, std::string &neg, std::string &pos, std::string &ncpf, bool big_endian)
+static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, std::string &neg, std::string &pos, std::string &ncpf, bool big_endian)
{
SigMap sigmap(module);
int cell_counter = 0, conn_counter = 0, nc_counter = 0;
- for (auto &cell_it : module->cells)
+ for (auto &cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
- fprintf(f, "X%d", cell_counter++);
+ f << stringf("X%d", cell_counter++);
std::vector<RTLIL::SigSpec> port_sigs;
- if (design->modules.count(cell->type) == 0)
+ if (design->modules_.count(cell->type) == 0)
{
log("Warning: no (blackbox) module for cell type `%s' (%s.%s) found! Guessing order of ports.\n",
RTLIL::id2cstr(cell->type), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name));
- for (auto &conn : cell->connections) {
+ for (auto &conn : cell->connections()) {
RTLIL::SigSpec sig = sigmap(conn.second);
port_sigs.push_back(sig);
}
}
else
{
- RTLIL::Module *mod = design->modules.at(cell->type);
+ RTLIL::Module *mod = design->modules_.at(cell->type);
std::vector<RTLIL::Wire*> ports;
- for (auto wire_it : mod->wires) {
+ for (auto wire_it : mod->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_id == 0)
continue;
@@ -81,8 +79,8 @@ static void print_spice_module(FILE *f, RTLIL::Module *module, RTLIL::Design *de
for (RTLIL::Wire *wire : ports) {
log_assert(wire != NULL);
RTLIL::SigSpec sig(RTLIL::State::Sz, wire->width);
- if (cell->connections.count(wire->name) > 0) {
- sig = sigmap(cell->connections.at(wire->name));
+ if (cell->hasPort(wire->name)) {
+ sig = sigmap(cell->getPort(wire->name));
sig.extend(wire->width, false);
}
port_sigs.push_back(sig);
@@ -90,22 +88,21 @@ static void print_spice_module(FILE *f, RTLIL::Module *module, RTLIL::Design *de
}
for (auto &sig : port_sigs) {
- for (int i = 0; i < sig.width; i++) {
- RTLIL::SigSpec s = sig.extract(big_endian ? sig.width - 1 - i : i, 1);
- log_assert(s.chunks.size() == 1 && s.chunks[0].width == 1);
+ for (int i = 0; i < sig.size(); i++) {
+ RTLIL::SigSpec s = sig.extract(big_endian ? sig.size() - 1 - i : i, 1);
print_spice_net(f, s, neg, pos, ncpf, nc_counter);
}
}
- fprintf(f, " %s\n", RTLIL::id2cstr(cell->type));
+ f << stringf(" %s\n", RTLIL::id2cstr(cell->type));
}
- for (auto &conn : module->connections)
- for (int i = 0; i < conn.first.width; i++) {
- fprintf(f, "V%d", conn_counter++);
+ for (auto &conn : module->connections())
+ for (int i = 0; i < conn.first.size(); i++) {
+ f << stringf("V%d", conn_counter++);
print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter);
print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter);
- fprintf(f, " DC 0\n");
+ f << stringf(" DC 0\n");
}
}
@@ -136,7 +133,7 @@ struct SpiceBackend : public Backend {
log(" set the specified module as design top module\n");
log("\n");
}
- virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
std::string top_module_name;
RTLIL::Module *top_module = NULL;
@@ -173,14 +170,14 @@ struct SpiceBackend : public Backend {
extra_args(f, filename, args, argidx);
if (top_module_name.empty())
- for (auto & mod_it:design->modules)
+ for (auto & mod_it:design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
- top_module_name = mod_it.first;
+ top_module_name = mod_it.first.str();
- fprintf(f, "* SPICE netlist generated by %s\n", yosys_version_str);
- fprintf(f, "\n");
+ *f << stringf("* SPICE netlist generated by %s\n", yosys_version_str);
+ *f << stringf("\n");
- for (auto module_it : design->modules)
+ for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox"))
@@ -197,7 +194,7 @@ struct SpiceBackend : public Backend {
}
std::vector<RTLIL::Wire*> ports;
- for (auto wire_it : module->wires) {
+ for (auto wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_id == 0)
continue;
@@ -206,31 +203,31 @@ struct SpiceBackend : public Backend {
ports.at(wire->port_id-1) = wire;
}
- fprintf(f, ".SUBCKT %s", RTLIL::id2cstr(module->name));
+ *f << stringf(".SUBCKT %s", RTLIL::id2cstr(module->name));
for (RTLIL::Wire *wire : ports) {
log_assert(wire != NULL);
if (wire->width > 1) {
for (int i = 0; i < wire->width; i++)
- fprintf(f, " %s[%d]", RTLIL::id2cstr(wire->name), big_endian ? wire->width - 1 - i : i);
+ *f << stringf(" %s[%d]", RTLIL::id2cstr(wire->name), big_endian ? wire->width - 1 - i : i);
} else
- fprintf(f, " %s", RTLIL::id2cstr(wire->name));
+ *f << stringf(" %s", RTLIL::id2cstr(wire->name));
}
- fprintf(f, "\n");
- print_spice_module(f, module, design, neg, pos, ncpf, big_endian);
- fprintf(f, ".ENDS %s\n\n", RTLIL::id2cstr(module->name));
+ *f << stringf("\n");
+ print_spice_module(*f, module, design, neg, pos, ncpf, big_endian);
+ *f << stringf(".ENDS %s\n\n", RTLIL::id2cstr(module->name));
}
if (!top_module_name.empty()) {
if (top_module == NULL)
log_error("Can't find top module `%s'!\n", top_module_name.c_str());
- print_spice_module(f, top_module, design, neg, pos, ncpf, big_endian);
- fprintf(f, "\n");
+ print_spice_module(*f, top_module, design, neg, pos, ncpf, big_endian);
+ *f << stringf("\n");
}
- fprintf(f, "************************\n");
- fprintf(f, "* end of SPICE netlist *\n");
- fprintf(f, "************************\n");
- fprintf(f, "\n");
+ *f << stringf("************************\n");
+ *f << stringf("* end of SPICE netlist *\n");
+ *f << stringf("************************\n");
+ *f << stringf("\n");
}
} SpiceBackend;
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index d7fe4c4e..bbdbbbfa 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -30,7 +30,6 @@
#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
-#include <assert.h>
#include <string>
#include <sstream>
#include <set>
@@ -40,14 +39,12 @@ namespace {
bool norename, noattr, attr2comment, noexpr;
int auto_name_counter, auto_name_offset, auto_name_digits;
-std::map<std::string, int> auto_name_map;
+std::map<RTLIL::IdString, int> auto_name_map;
+std::set<RTLIL::IdString> reg_wires, reg_ct;
-std::set<std::string> reg_wires;
-
-CellTypes reg_ct;
RTLIL::Module *active_module;
-void reset_auto_counter_id(const std::string &id, bool may_rename)
+void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
{
const char *str = id.c_str();
@@ -76,10 +73,10 @@ void reset_auto_counter(RTLIL::Module *module)
reset_auto_counter_id(module->name, false);
- for (auto it = module->wires.begin(); it != module->wires.end(); it++)
+ for (auto it = module->wires_.begin(); it != module->wires_.end(); it++)
reset_auto_counter_id(it->second->name, true);
- for (auto it = module->cells.begin(); it != module->cells.end(); it++) {
+ for (auto it = module->cells_.begin(); it != module->cells_.end(); it++) {
reset_auto_counter_id(it->second->name, true);
reset_auto_counter_id(it->second->type, false);
}
@@ -95,7 +92,7 @@ void reset_auto_counter(RTLIL::Module *module)
log(" renaming `%s' to `_%0*d_'.\n", it->first.c_str(), auto_name_digits, auto_name_offset + it->second);
}
-std::string id(std::string internal_id, bool may_rename = true)
+std::string id(RTLIL::IdString internal_id, bool may_rename = true)
{
const char *str = internal_id.c_str();
bool do_escape = false;
@@ -133,23 +130,27 @@ std::string id(std::string internal_id, bool may_rename = true)
bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
{
- sig.optimize();
- if (sig.chunks.size() != 1 || sig.chunks[0].wire == NULL)
+ if (!sig.is_chunk() || sig.as_chunk().wire == NULL)
return false;
- if (reg_wires.count(sig.chunks[0].wire->name) == 0)
+
+ RTLIL::SigChunk chunk = sig.as_chunk();
+
+ if (reg_wires.count(chunk.wire->name) == 0)
return false;
- reg_name = id(sig.chunks[0].wire->name);
- if (sig.width != sig.chunks[0].wire->width) {
- if (sig.width == 1)
- reg_name += stringf("[%d]", sig.chunks[0].wire->start_offset + sig.chunks[0].offset);
+
+ reg_name = id(chunk.wire->name);
+ if (sig.size() != chunk.wire->width) {
+ if (sig.size() == 1)
+ reg_name += stringf("[%d]", chunk.wire->start_offset + chunk.offset);
else
- reg_name += stringf("[%d:%d]", sig.chunks[0].wire->start_offset + sig.chunks[0].offset + sig.chunks[0].width - 1,
- sig.chunks[0].wire->start_offset + sig.chunks[0].offset);
+ reg_name += stringf("[%d:%d]", chunk.wire->start_offset + chunk.offset + chunk.width - 1,
+ chunk.wire->start_offset + chunk.offset);
}
+
return true;
}
-void dump_const(FILE *f, RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false)
+void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false)
{
if (width < 0)
width = data.bits.size() - offset;
@@ -157,159 +158,172 @@ void dump_const(FILE *f, RTLIL::Const &data, int width = -1, int offset = 0, boo
if (width == 32 && !no_decimal) {
int32_t val = 0;
for (int i = offset+width-1; i >= offset; i--) {
- assert(i < (int)data.bits.size());
+ log_assert(i < (int)data.bits.size());
if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1)
goto dump_bits;
+ if (data.bits[i] == RTLIL::S1 && (i - offset) == 31)
+ goto dump_bits;
if (data.bits[i] == RTLIL::S1)
val |= 1 << (i - offset);
}
- // fprintf(f, "%s32'sd%u", val < 0 ? "-" : "", abs(val));
- fprintf(f, "%d", val);
+ f << stringf("32'%sd%d", set_signed ? "s" : "", val);
} else {
dump_bits:
- fprintf(f, "%d'%sb", width, set_signed ? "s" : "");
+ f << stringf("%d'%sb", width, set_signed ? "s" : "");
if (width == 0)
- fprintf(f, "0");
+ f << stringf("0");
for (int i = offset+width-1; i >= offset; i--) {
- assert(i < (int)data.bits.size());
+ log_assert(i < (int)data.bits.size());
switch (data.bits[i]) {
- case RTLIL::S0: fprintf(f, "0"); break;
- case RTLIL::S1: fprintf(f, "1"); break;
- case RTLIL::Sx: fprintf(f, "x"); break;
- case RTLIL::Sz: fprintf(f, "z"); break;
- case RTLIL::Sa: fprintf(f, "z"); break;
+ case RTLIL::S0: f << stringf("0"); break;
+ case RTLIL::S1: f << stringf("1"); break;
+ case RTLIL::Sx: f << stringf("x"); break;
+ case RTLIL::Sz: f << stringf("z"); break;
+ case RTLIL::Sa: f << stringf("z"); break;
case RTLIL::Sm: log_error("Found marker state in final netlist.");
}
}
}
} else {
- fprintf(f, "\"");
+ f << stringf("\"");
std::string str = data.decode_string();
for (size_t i = 0; i < str.size(); i++) {
if (str[i] == '\n')
- fprintf(f, "\\n");
+ f << stringf("\\n");
else if (str[i] == '\t')
- fprintf(f, "\\t");
+ f << stringf("\\t");
else if (str[i] < 32)
- fprintf(f, "\\%03o", str[i]);
+ f << stringf("\\%03o", str[i]);
else if (str[i] == '"')
- fprintf(f, "\\\"");
+ f << stringf("\\\"");
else if (str[i] == '\\')
- fprintf(f, "\\\\");
+ f << stringf("\\\\");
else
- fputc(str[i], f);
+ f << str[i];
}
- fprintf(f, "\"");
+ f << stringf("\"");
}
}
-void dump_sigchunk(FILE *f, RTLIL::SigChunk &chunk, bool no_decimal = false)
+void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decimal = false)
{
if (chunk.wire == NULL) {
dump_const(f, chunk.data, chunk.width, chunk.offset, no_decimal);
} else {
- if (chunk.width == chunk.wire->width && chunk.offset == 0)
- fprintf(f, "%s", id(chunk.wire->name).c_str());
- else if (chunk.width == 1)
- fprintf(f, "%s[%d]", id(chunk.wire->name).c_str(), chunk.offset + chunk.wire->start_offset);
- else
- fprintf(f, "%s[%d:%d]", id(chunk.wire->name).c_str(),
- chunk.offset + chunk.wire->start_offset + chunk.width - 1,
- chunk.offset + chunk.wire->start_offset);
+ if (chunk.width == chunk.wire->width && chunk.offset == 0) {
+ f << stringf("%s", id(chunk.wire->name).c_str());
+ } else if (chunk.width == 1) {
+ if (chunk.wire->upto)
+ f << stringf("%s[%d]", id(chunk.wire->name).c_str(), (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset);
+ else
+ f << stringf("%s[%d]", id(chunk.wire->name).c_str(), chunk.offset + chunk.wire->start_offset);
+ } else {
+ if (chunk.wire->upto)
+ f << stringf("%s[%d:%d]", id(chunk.wire->name).c_str(),
+ (chunk.wire->width - (chunk.offset + chunk.width - 1) - 1) + chunk.wire->start_offset,
+ (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset);
+ else
+ f << stringf("%s[%d:%d]", id(chunk.wire->name).c_str(),
+ (chunk.offset + chunk.width - 1) + chunk.wire->start_offset,
+ chunk.offset + chunk.wire->start_offset);
+ }
}
}
-void dump_sigspec(FILE *f, RTLIL::SigSpec &sig)
+void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
{
- if (sig.chunks.size() == 1) {
- dump_sigchunk(f, sig.chunks[0]);
+ if (sig.is_chunk()) {
+ dump_sigchunk(f, sig.as_chunk());
} else {
- fprintf(f, "{ ");
- for (auto it = sig.chunks.rbegin(); it != sig.chunks.rend(); it++) {
- if (it != sig.chunks.rbegin())
- fprintf(f, ", ");
+ f << stringf("{ ");
+ for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); it++) {
+ if (it != sig.chunks().rbegin())
+ f << stringf(", ");
dump_sigchunk(f, *it, true);
}
- fprintf(f, " }");
+ f << stringf(" }");
}
}
-void dump_attributes(FILE *f, std::string indent, std::map<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n')
+void dump_attributes(std::ostream &f, std::string indent, std::map<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n')
{
if (noattr)
return;
for (auto it = attributes.begin(); it != attributes.end(); it++) {
- fprintf(f, "%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
- fprintf(f, " = ");
+ f << stringf("%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
+ f << stringf(" = ");
dump_const(f, it->second);
- fprintf(f, " %s%c", attr2comment ? "*/" : "*)", term);
+ f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
}
}
-void dump_wire(FILE *f, std::string indent, RTLIL::Wire *wire)
+void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
{
dump_attributes(f, indent, wire->attributes);
#if 0
if (wire->port_input && !wire->port_output)
- fprintf(f, "%s" "input %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
+ f << stringf("%s" "input %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
else if (!wire->port_input && wire->port_output)
- fprintf(f, "%s" "output %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
+ f << stringf("%s" "output %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
else if (wire->port_input && wire->port_output)
- fprintf(f, "%s" "inout %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
+ f << stringf("%s" "inout %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
else
- fprintf(f, "%s" "%s ", indent.c_str(), reg_wires.count(wire->name) ? "reg" : "wire");
+ f << stringf("%s" "%s ", indent.c_str(), reg_wires.count(wire->name) ? "reg" : "wire");
if (wire->width != 1)
- fprintf(f, "[%d:%d] ", wire->width - 1 + wire->start_offset, wire->start_offset);
- fprintf(f, "%s;\n", id(wire->name).c_str());
+ f << stringf("[%d:%d] ", wire->width - 1 + wire->start_offset, wire->start_offset);
+ f << stringf("%s;\n", id(wire->name).c_str());
#else
// do not use Verilog-2k "outut reg" syntax in verilog export
std::string range = "";
- if (wire->width != 1)
- range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset);
+ if (wire->width != 1) {
+ if (wire->upto)
+ range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset);
+ else
+ range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset);
+ }
if (wire->port_input && !wire->port_output)
- fprintf(f, "%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
+ f << stringf("%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
if (!wire->port_input && wire->port_output)
- fprintf(f, "%s" "output%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
+ f << stringf("%s" "output%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
if (wire->port_input && wire->port_output)
- fprintf(f, "%s" "inout%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
+ f << stringf("%s" "inout%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
if (reg_wires.count(wire->name))
- fprintf(f, "%s" "reg%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
+ f << stringf("%s" "reg%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
else if (!wire->port_input && !wire->port_output)
- fprintf(f, "%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
+ f << stringf("%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
#endif
}
-void dump_memory(FILE *f, std::string indent, RTLIL::Memory *memory)
+void dump_memory(std::ostream &f, std::string indent, RTLIL::Memory *memory)
{
dump_attributes(f, indent, memory->attributes);
- fprintf(f, "%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:0];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size-1);
}
-void dump_cell_expr_port(FILE *f, RTLIL::Cell *cell, std::string port, bool gen_signed = true)
+void dump_cell_expr_port(std::ostream &f, RTLIL::Cell *cell, std::string port, bool gen_signed = true)
{
if (gen_signed && cell->parameters.count("\\" + port + "_SIGNED") > 0 && cell->parameters["\\" + port + "_SIGNED"].as_bool()) {
- fprintf(f, "$signed(");
- dump_sigspec(f, cell->connections["\\" + port]);
- fprintf(f, ")");
+ f << stringf("$signed(");
+ dump_sigspec(f, cell->getPort("\\" + port));
+ f << stringf(")");
} else
- dump_sigspec(f, cell->connections["\\" + port]);
+ dump_sigspec(f, cell->getPort("\\" + port));
}
std::string cellname(RTLIL::Cell *cell)
{
- if (!norename && cell->name[0] == '$' && reg_ct.cell_known(cell->type) && cell->connections.count("\\Q") > 0)
+ if (!norename && cell->name[0] == '$' && reg_ct.count(cell->type) && cell->hasPort("\\Q"))
{
- RTLIL::SigSpec sig = cell->connections["\\Q"];
- if (sig.width != 1 || sig.is_fully_const())
+ RTLIL::SigSpec sig = cell->getPort("\\Q");
+ if (SIZE(sig) != 1 || sig.is_fully_const())
goto no_special_reg_name;
- sig.optimize();
- RTLIL::Wire *wire = sig.chunks[0].wire;
+ RTLIL::Wire *wire = sig[0].wire;
if (wire->name[0] != '\\')
goto no_special_reg_name;
- std::string cell_name = wire->name;
+ std::string cell_name = wire->name.str();
size_t pos = cell_name.find('[');
if (pos != std::string::npos)
@@ -318,7 +332,7 @@ std::string cellname(RTLIL::Cell *cell)
cell_name = cell_name + "_reg";
if (wire->width != 1)
- cell_name += stringf("[%d]", wire->start_offset + sig.chunks[0].offset);
+ cell_name += stringf("[%d]", wire->start_offset + sig[0].offset);
if (active_module && active_module->count_id(cell_name) > 0)
goto no_special_reg_name;
@@ -332,107 +346,143 @@ no_special_reg_name:
}
}
-void dump_cell_expr_uniop(FILE *f, std::string indent, RTLIL::Cell *cell, std::string op)
+void dump_cell_expr_uniop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
{
- fprintf(f, "%s" "assign ", indent.c_str());
- dump_sigspec(f, cell->connections["\\Y"]);
- fprintf(f, " = %s ", op.c_str());
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = %s ", op.c_str());
dump_attributes(f, "", cell->attributes, ' ');
dump_cell_expr_port(f, cell, "A", true);
- fprintf(f, ";\n");
+ f << stringf(";\n");
}
-void dump_cell_expr_binop(FILE *f, std::string indent, RTLIL::Cell *cell, std::string op)
+void dump_cell_expr_binop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
{
- fprintf(f, "%s" "assign ", indent.c_str());
- dump_sigspec(f, cell->connections["\\Y"]);
- fprintf(f, " = ");
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = ");
dump_cell_expr_port(f, cell, "A", true);
- fprintf(f, " %s ", op.c_str());
+ f << stringf(" %s ", op.c_str());
dump_attributes(f, "", cell->attributes, ' ');
dump_cell_expr_port(f, cell, "B", true);
- fprintf(f, ";\n");
+ f << stringf(";\n");
}
-bool dump_cell_expr(FILE *f, std::string indent, RTLIL::Cell *cell)
+bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
{
- if (cell->type == "$_INV_") {
- fprintf(f, "%s" "assign ", indent.c_str());
- dump_sigspec(f, cell->connections["\\Y"]);
- fprintf(f, " = ");
- fprintf(f, "~");
+ if (cell->type == "$_NOT_") {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = ");
+ f << stringf("~");
dump_attributes(f, "", cell->attributes, ' ');
dump_cell_expr_port(f, cell, "A", false);
- fprintf(f, ";\n");
+ f << stringf(";\n");
return true;
}
- if (cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_") {
- fprintf(f, "%s" "assign ", indent.c_str());
- dump_sigspec(f, cell->connections["\\Y"]);
- fprintf(f, " = ");
+ if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = ");
+ if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_"))
+ f << stringf("~(");
dump_cell_expr_port(f, cell, "A", false);
- fprintf(f, " ");
- if (cell->type == "$_AND_")
- fprintf(f, "&");
- if (cell->type == "$_OR_")
- fprintf(f, "|");
- if (cell->type == "$_XOR_")
- fprintf(f, "^");
+ f << stringf(" ");
+ if (cell->type.in("$_AND_", "$_NAND_"))
+ f << stringf("&");
+ if (cell->type.in("$_OR_", "$_NOR_"))
+ f << stringf("|");
+ if (cell->type.in("$_XOR_", "$_XNOR_"))
+ f << stringf("^");
dump_attributes(f, "", cell->attributes, ' ');
- fprintf(f, " ");
+ f << stringf(" ");
dump_cell_expr_port(f, cell, "B", false);
- fprintf(f, ";\n");
+ if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_"))
+ f << stringf(")");
+ f << stringf(";\n");
return true;
}
if (cell->type == "$_MUX_") {
- fprintf(f, "%s" "assign ", indent.c_str());
- dump_sigspec(f, cell->connections["\\Y"]);
- fprintf(f, " = ");
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = ");
dump_cell_expr_port(f, cell, "S", false);
- fprintf(f, " ? ");
+ f << stringf(" ? ");
dump_attributes(f, "", cell->attributes, ' ');
dump_cell_expr_port(f, cell, "B", false);
- fprintf(f, " : ");
+ f << stringf(" : ");
+ dump_cell_expr_port(f, cell, "A", false);
+ f << stringf(";\n");
+ return true;
+ }
+
+ if (cell->type.in("$_AOI3_", "$_OAI3_")) {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = ~((");
dump_cell_expr_port(f, cell, "A", false);
- fprintf(f, ";\n");
+ f << stringf(cell->type == "$_AOI3_" ? " & " : " | ");
+ dump_cell_expr_port(f, cell, "B", false);
+ f << stringf(cell->type == "$_AOI3_" ? ") |" : ") &");
+ dump_attributes(f, "", cell->attributes, ' ');
+ f << stringf(" ");
+ dump_cell_expr_port(f, cell, "C", false);
+ f << stringf(");\n");
+ return true;
+ }
+
+ if (cell->type.in("$_AOI4_", "$_OAI4_")) {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = ~((");
+ dump_cell_expr_port(f, cell, "A", false);
+ f << stringf(cell->type == "$_AOI4_" ? " & " : " | ");
+ dump_cell_expr_port(f, cell, "B", false);
+ f << stringf(cell->type == "$_AOI4_" ? ") |" : ") &");
+ dump_attributes(f, "", cell->attributes, ' ');
+ f << stringf(" (");
+ dump_cell_expr_port(f, cell, "C", false);
+ f << stringf(cell->type == "$_AOI4_" ? " & " : " | ");
+ dump_cell_expr_port(f, cell, "D", false);
+ f << stringf("));\n");
return true;
}
if (cell->type.substr(0, 6) == "$_DFF_")
{
std::string reg_name = cellname(cell);
- bool out_is_reg_wire = is_reg_wire(cell->connections["\\Q"], reg_name);
+ bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
if (!out_is_reg_wire)
- fprintf(f, "%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
+ f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
dump_attributes(f, indent, cell->attributes);
- fprintf(f, "%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg");
- dump_sigspec(f, cell->connections["\\C"]);
+ f << stringf("%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg");
+ dump_sigspec(f, cell->getPort("\\C"));
if (cell->type[7] != '_') {
- fprintf(f, " or %sedge ", cell->type[7] == 'P' ? "pos" : "neg");
- dump_sigspec(f, cell->connections["\\R"]);
+ f << stringf(" or %sedge ", cell->type[7] == 'P' ? "pos" : "neg");
+ dump_sigspec(f, cell->getPort("\\R"));
}
- fprintf(f, ")\n");
+ f << stringf(")\n");
if (cell->type[7] != '_') {
- fprintf(f, "%s" " if (%s", indent.c_str(), cell->type[7] == 'P' ? "" : "!");
- dump_sigspec(f, cell->connections["\\R"]);
- fprintf(f, ")\n");
- fprintf(f, "%s" " %s <= %c;\n", indent.c_str(), reg_name.c_str(), cell->type[8]);
- fprintf(f, "%s" " else\n", indent.c_str());
+ f << stringf("%s" " if (%s", indent.c_str(), cell->type[7] == 'P' ? "" : "!");
+ dump_sigspec(f, cell->getPort("\\R"));
+ f << stringf(")\n");
+ f << stringf("%s" " %s <= %c;\n", indent.c_str(), reg_name.c_str(), cell->type[8]);
+ f << stringf("%s" " else\n", indent.c_str());
}
- fprintf(f, "%s" " %s <= ", indent.c_str(), reg_name.c_str());
+ f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
dump_cell_expr_port(f, cell, "D", false);
- fprintf(f, ";\n");
+ f << stringf(";\n");
if (!out_is_reg_wire) {
- fprintf(f, "%s" "assign ", indent.c_str());
- dump_sigspec(f, cell->connections["\\Q"]);
- fprintf(f, " = %s;\n", reg_name.c_str());
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Q"));
+ f << stringf(" = %s;\n", reg_name.c_str());
}
return true;
@@ -443,39 +493,39 @@ bool dump_cell_expr(FILE *f, std::string indent, RTLIL::Cell *cell)
char pol_c = cell->type[8], pol_s = cell->type[9], pol_r = cell->type[10];
std::string reg_name = cellname(cell);
- bool out_is_reg_wire = is_reg_wire(cell->connections["\\Q"], reg_name);
+ bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
if (!out_is_reg_wire)
- fprintf(f, "%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
+ f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
dump_attributes(f, indent, cell->attributes);
- fprintf(f, "%s" "always @(%sedge ", indent.c_str(), pol_c == 'P' ? "pos" : "neg");
- dump_sigspec(f, cell->connections["\\C"]);
- fprintf(f, " or %sedge ", pol_s == 'P' ? "pos" : "neg");
- dump_sigspec(f, cell->connections["\\S"]);
- fprintf(f, " or %sedge ", pol_r == 'P' ? "pos" : "neg");
- dump_sigspec(f, cell->connections["\\R"]);
- fprintf(f, ")\n");
-
- fprintf(f, "%s" " if (%s", indent.c_str(), pol_r == 'P' ? "" : "!");
- dump_sigspec(f, cell->connections["\\R"]);
- fprintf(f, ")\n");
- fprintf(f, "%s" " %s <= 0;\n", indent.c_str(), reg_name.c_str());
-
- fprintf(f, "%s" " else if (%s", indent.c_str(), pol_s == 'P' ? "" : "!");
- dump_sigspec(f, cell->connections["\\S"]);
- fprintf(f, ")\n");
- fprintf(f, "%s" " %s <= 1;\n", indent.c_str(), reg_name.c_str());
-
- fprintf(f, "%s" " else\n", indent.c_str());
- fprintf(f, "%s" " %s <= ", indent.c_str(), reg_name.c_str());
+ f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_c == 'P' ? "pos" : "neg");
+ dump_sigspec(f, cell->getPort("\\C"));
+ f << stringf(" or %sedge ", pol_s == 'P' ? "pos" : "neg");
+ dump_sigspec(f, cell->getPort("\\S"));
+ f << stringf(" or %sedge ", pol_r == 'P' ? "pos" : "neg");
+ dump_sigspec(f, cell->getPort("\\R"));
+ f << stringf(")\n");
+
+ f << stringf("%s" " if (%s", indent.c_str(), pol_r == 'P' ? "" : "!");
+ dump_sigspec(f, cell->getPort("\\R"));
+ f << stringf(")\n");
+ f << stringf("%s" " %s <= 0;\n", indent.c_str(), reg_name.c_str());
+
+ f << stringf("%s" " else if (%s", indent.c_str(), pol_s == 'P' ? "" : "!");
+ dump_sigspec(f, cell->getPort("\\S"));
+ f << stringf(")\n");
+ f << stringf("%s" " %s <= 1;\n", indent.c_str(), reg_name.c_str());
+
+ f << stringf("%s" " else\n", indent.c_str());
+ f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
dump_cell_expr_port(f, cell, "D", false);
- fprintf(f, ";\n");
+ f << stringf(";\n");
if (!out_is_reg_wire) {
- fprintf(f, "%s" "assign ", indent.c_str());
- dump_sigspec(f, cell->connections["\\Q"]);
- fprintf(f, " = %s;\n", reg_name.c_str());
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Q"));
+ f << stringf(" = %s;\n", reg_name.c_str());
}
return true;
@@ -529,67 +579,87 @@ bool dump_cell_expr(FILE *f, std::string indent, RTLIL::Cell *cell)
#undef HANDLE_UNIOP
#undef HANDLE_BINOP
- if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$pmux_safe")
+ if (cell->type == "$mux")
+ {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = ");
+ dump_sigspec(f, cell->getPort("\\S"));
+ f << stringf(" ? ");
+ dump_attributes(f, "", cell->attributes, ' ');
+ dump_sigspec(f, cell->getPort("\\B"));
+ f << stringf(" : ");
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(";\n");
+ return true;
+ }
+
+ if (cell->type == "$pmux" || cell->type == "$pmux_safe")
{
int width = cell->parameters["\\WIDTH"].as_int();
- int s_width = cell->connections["\\S"].width;
- std::string reg_name = cellname(cell);
- fprintf(f, "%s" "reg [%d:0] %s;\n", indent.c_str(), width-1, reg_name.c_str());
+ int s_width = cell->getPort("\\S").size();
+ std::string func_name = cellname(cell);
- dump_attributes(f, indent, cell->attributes);
- if (!noattr)
- fprintf(f, "%s" "(* parallel_case *)\n", indent.c_str());
- fprintf(f, "%s" "always @*\n", indent.c_str());
- fprintf(f, "%s" " casez (", indent.c_str());
- dump_sigspec(f, cell->connections["\\S"]);
- fprintf(f, noattr ? ") // synopsys parallel_case\n" : ")\n");
+ f << stringf("%s" "function [%d:0] %s;\n", indent.c_str(), width-1, func_name.c_str());
+ f << stringf("%s" " input [%d:0] a;\n", indent.c_str(), width-1);
+ f << stringf("%s" " input [%d:0] b;\n", indent.c_str(), s_width*width-1);
+ f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1);
+
+ dump_attributes(f, indent + " ", cell->attributes);
+ if (cell->type != "$pmux_safe" && !noattr)
+ f << stringf("%s" " (* parallel_case *)\n", indent.c_str());
+ f << stringf("%s" " casez (s)", indent.c_str());
+ if (cell->type != "$pmux_safe")
+ f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
for (int i = 0; i < s_width; i++)
{
- fprintf(f, "%s" " %d'b", indent.c_str(), s_width);
+ f << stringf("%s" " %d'b", indent.c_str(), s_width);
for (int j = s_width-1; j >= 0; j--)
- fprintf(f, "%c", j == i ? '1' : cell->type == "$pmux_safe" ? '0' : '?');
+ f << stringf("%c", j == i ? '1' : cell->type == "$pmux_safe" ? '0' : '?');
- fprintf(f, ":\n");
- fprintf(f, "%s" " %s = ", indent.c_str(), reg_name.c_str());
-
- RTLIL::SigSpec s = cell->connections["\\B"].extract(i * width, width);
- dump_sigspec(f, s);
- fprintf(f, ";\n");
+ f << stringf(":\n");
+ f << stringf("%s" " %s = b[%d:%d];\n", indent.c_str(), func_name.c_str(), (i+1)*width-1, i*width);
}
- fprintf(f, "%s" " default:\n", indent.c_str());
- fprintf(f, "%s" " %s = ", indent.c_str(), reg_name.c_str());
- dump_sigspec(f, cell->connections["\\A"]);
- fprintf(f, ";\n");
-
- fprintf(f, "%s" " endcase\n", indent.c_str());
- fprintf(f, "%s" "assign ", indent.c_str());
- dump_sigspec(f, cell->connections["\\Y"]);
- fprintf(f, " = %s;\n", reg_name.c_str());
+ f << stringf("%s" " default:\n", indent.c_str());
+ f << stringf("%s" " %s = a;\n", indent.c_str(), func_name.c_str());
+
+ f << stringf("%s" " endcase\n", indent.c_str());
+ f << stringf("%s" "endfunction\n", indent.c_str());
+
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = %s(", func_name.c_str());
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(", ");
+ dump_sigspec(f, cell->getPort("\\B"));
+ f << stringf(", ");
+ dump_sigspec(f, cell->getPort("\\S"));
+ f << stringf(");\n");
return true;
}
if (cell->type == "$slice")
{
- fprintf(f, "%s" "assign ", indent.c_str());
- dump_sigspec(f, cell->connections["\\Y"]);
- fprintf(f, " = ");
- dump_sigspec(f, cell->connections["\\A"]);
- fprintf(f, " >> %d;\n", cell->parameters.at("\\OFFSET").as_int());
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = ");
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(" >> %d;\n", cell->parameters.at("\\OFFSET").as_int());
return true;
}
if (cell->type == "$concat")
{
- fprintf(f, "%s" "assign ", indent.c_str());
- dump_sigspec(f, cell->connections["\\Y"]);
- fprintf(f, " = { ");
- dump_sigspec(f, cell->connections["\\B"]);
- fprintf(f, " , ");
- dump_sigspec(f, cell->connections["\\A"]);
- fprintf(f, " };\n");
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = { ");
+ dump_sigspec(f, cell->getPort("\\B"));
+ f << stringf(" , ");
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(" };\n");
return true;
}
@@ -598,59 +668,59 @@ bool dump_cell_expr(FILE *f, std::string indent, RTLIL::Cell *cell)
RTLIL::SigSpec sig_clk, sig_arst, val_arst;
bool pol_clk, pol_arst = false;
- sig_clk = cell->connections["\\CLK"];
+ sig_clk = cell->getPort("\\CLK");
pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
if (cell->type == "$adff") {
- sig_arst = cell->connections["\\ARST"];
+ sig_arst = cell->getPort("\\ARST");
pol_arst = cell->parameters["\\ARST_POLARITY"].as_bool();
val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]);
}
std::string reg_name = cellname(cell);
- bool out_is_reg_wire = is_reg_wire(cell->connections["\\Q"], reg_name);
+ bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
if (!out_is_reg_wire)
- fprintf(f, "%s" "reg [%d:0] %s;\n", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
+ f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
- fprintf(f, "%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
+ f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
dump_sigspec(f, sig_clk);
if (cell->type == "$adff") {
- fprintf(f, " or %sedge ", pol_arst ? "pos" : "neg");
+ f << stringf(" or %sedge ", pol_arst ? "pos" : "neg");
dump_sigspec(f, sig_arst);
}
- fprintf(f, ")\n");
+ f << stringf(")\n");
if (cell->type == "$adff") {
- fprintf(f, "%s" " if (%s", indent.c_str(), pol_arst ? "" : "!");
+ f << stringf("%s" " if (%s", indent.c_str(), pol_arst ? "" : "!");
dump_sigspec(f, sig_arst);
- fprintf(f, ")\n");
- fprintf(f, "%s" " %s <= ", indent.c_str(), reg_name.c_str());
+ f << stringf(")\n");
+ f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
dump_sigspec(f, val_arst);
- fprintf(f, ";\n");
- fprintf(f, "%s" " else\n", indent.c_str());
+ f << stringf(";\n");
+ f << stringf("%s" " else\n", indent.c_str());
}
- fprintf(f, "%s" " %s <= ", indent.c_str(), reg_name.c_str());
+ f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
dump_cell_expr_port(f, cell, "D", false);
- fprintf(f, ";\n");
+ f << stringf(";\n");
if (!out_is_reg_wire) {
- fprintf(f, "%s" "assign ", indent.c_str());
- dump_sigspec(f, cell->connections["\\Q"]);
- fprintf(f, " = %s;\n", reg_name.c_str());
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Q"));
+ f << stringf(" = %s;\n", reg_name.c_str());
}
return true;
}
- // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_
+ // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
// FIXME: $sr, $dffsr, $dlatch, $memrd, $memwr, $mem, $fsm
return false;
}
-void dump_cell(FILE *f, std::string indent, RTLIL::Cell *cell)
+void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
{
if (cell->type[0] == '$' && !noexpr) {
if (dump_cell_expr(f, indent, cell))
@@ -658,39 +728,39 @@ void dump_cell(FILE *f, std::string indent, RTLIL::Cell *cell)
}
dump_attributes(f, indent, cell->attributes);
- fprintf(f, "%s" "%s", indent.c_str(), id(cell->type, false).c_str());
+ f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str());
if (cell->parameters.size() > 0) {
- fprintf(f, " #(");
+ f << stringf(" #(");
for (auto it = cell->parameters.begin(); it != cell->parameters.end(); it++) {
if (it != cell->parameters.begin())
- fprintf(f, ",");
- fprintf(f, "\n%s .%s(", indent.c_str(), id(it->first).c_str());
+ f << stringf(",");
+ f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
dump_const(f, it->second, -1, 0, !is_signed, is_signed);
- fprintf(f, ")");
+ f << stringf(")");
}
- fprintf(f, "\n%s" ")", indent.c_str());
+ f << stringf("\n%s" ")", indent.c_str());
}
std::string cell_name = cellname(cell);
if (cell_name != id(cell->name))
- fprintf(f, " %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str());
+ f << stringf(" %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str());
else
- fprintf(f, " %s (", cell_name.c_str());
+ f << stringf(" %s (", cell_name.c_str());
bool first_arg = true;
- std::set<std::string> numbered_ports;
+ std::set<RTLIL::IdString> numbered_ports;
for (int i = 1; true; i++) {
char str[16];
snprintf(str, 16, "$%d", i);
- for (auto it = cell->connections.begin(); it != cell->connections.end(); it++) {
+ for (auto it = cell->connections().begin(); it != cell->connections().end(); it++) {
if (it->first != str)
continue;
if (!first_arg)
- fprintf(f, ",");
+ f << stringf(",");
first_arg = false;
- fprintf(f, "\n%s ", indent.c_str());
+ f << stringf("\n%s ", indent.c_str());
dump_sigspec(f, it->second);
numbered_ports.insert(it->first);
goto found_numbered_port;
@@ -698,90 +768,90 @@ void dump_cell(FILE *f, std::string indent, RTLIL::Cell *cell)
break;
found_numbered_port:;
}
- for (auto it = cell->connections.begin(); it != cell->connections.end(); it++) {
+ for (auto it = cell->connections().begin(); it != cell->connections().end(); it++) {
if (numbered_ports.count(it->first))
continue;
if (!first_arg)
- fprintf(f, ",");
+ f << stringf(",");
first_arg = false;
- fprintf(f, "\n%s .%s(", indent.c_str(), id(it->first).c_str());
- if (it->second.width > 0)
+ f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
+ if (it->second.size() > 0)
dump_sigspec(f, it->second);
- fprintf(f, ")");
+ f << stringf(")");
}
- fprintf(f, "\n%s" ");\n", indent.c_str());
+ f << stringf("\n%s" ");\n", indent.c_str());
}
-void dump_conn(FILE *f, std::string indent, RTLIL::SigSpec &left, RTLIL::SigSpec &right)
+void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
{
- fprintf(f, "%s" "assign ", indent.c_str());
+ f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, left);
- fprintf(f, " = ");
+ f << stringf(" = ");
dump_sigspec(f, right);
- fprintf(f, ";\n");
+ f << stringf(";\n");
}
-void dump_proc_switch(FILE *f, std::string indent, RTLIL::SwitchRule *sw);
+void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw);
-void dump_case_body(FILE *f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
+void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
{
int number_of_stmts = cs->switches.size() + cs->actions.size();
if (!omit_trailing_begin && number_of_stmts >= 2)
- fprintf(f, "%s" "begin\n", indent.c_str());
+ f << stringf("%s" "begin\n", indent.c_str());
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
- if (it->first.width == 0)
+ if (it->first.size() == 0)
continue;
- fprintf(f, "%s ", indent.c_str());
+ f << stringf("%s ", indent.c_str());
dump_sigspec(f, it->first);
- fprintf(f, " = ");
+ f << stringf(" = ");
dump_sigspec(f, it->second);
- fprintf(f, ";\n");
+ f << stringf(";\n");
}
for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
dump_proc_switch(f, indent + " ", *it);
if (!omit_trailing_begin && number_of_stmts == 0)
- fprintf(f, "%s /* empty */;\n", indent.c_str());
+ f << stringf("%s /* empty */;\n", indent.c_str());
if (omit_trailing_begin || number_of_stmts >= 2)
- fprintf(f, "%s" "end\n", indent.c_str());
+ f << stringf("%s" "end\n", indent.c_str());
}
-void dump_proc_switch(FILE *f, std::string indent, RTLIL::SwitchRule *sw)
+void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw)
{
- if (sw->signal.width == 0) {
- fprintf(f, "%s" "begin\n", indent.c_str());
+ if (sw->signal.size() == 0) {
+ f << stringf("%s" "begin\n", indent.c_str());
for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
if ((*it)->compare.size() == 0)
dump_case_body(f, indent + " ", *it);
}
- fprintf(f, "%s" "end\n", indent.c_str());
+ f << stringf("%s" "end\n", indent.c_str());
return;
}
- fprintf(f, "%s" "casez (", indent.c_str());
+ f << stringf("%s" "casez (", indent.c_str());
dump_sigspec(f, sw->signal);
- fprintf(f, ")\n");
+ f << stringf(")\n");
for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
- fprintf(f, "%s ", indent.c_str());
+ f << stringf("%s ", indent.c_str());
if ((*it)->compare.size() == 0)
- fprintf(f, "default");
+ f << stringf("default");
else {
for (size_t i = 0; i < (*it)->compare.size(); i++) {
if (i > 0)
- fprintf(f, ", ");
+ f << stringf(", ");
dump_sigspec(f, (*it)->compare[i]);
}
}
- fprintf(f, ":\n");
+ f << stringf(":\n");
dump_case_body(f, indent + " ", *it);
}
- fprintf(f, "%s" "endcase\n", indent.c_str());
+ f << stringf("%s" "endcase\n", indent.c_str());
}
void case_body_find_regs(RTLIL::CaseRule *cs)
@@ -791,26 +861,26 @@ void case_body_find_regs(RTLIL::CaseRule *cs)
case_body_find_regs(*it2);
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
- for (size_t i = 0; i < it->first.chunks.size(); i++)
- if (it->first.chunks[i].wire)
- reg_wires.insert(it->first.chunks[i].wire->name);
+ for (auto &c : it->first.chunks())
+ if (c.wire != NULL)
+ reg_wires.insert(c.wire->name);
}
}
-void dump_process(FILE *f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
+void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
{
if (find_regs) {
case_body_find_regs(&proc->root_case);
for (auto it = proc->syncs.begin(); it != proc->syncs.end(); it++)
for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
- for (size_t i = 0; i < it2->first.chunks.size(); i++)
- if (it2->first.chunks[i].wire)
- reg_wires.insert(it2->first.chunks[i].wire->name);
+ for (auto &c : it2->first.chunks())
+ if (c.wire != NULL)
+ reg_wires.insert(c.wire->name);
}
return;
}
- fprintf(f, "%s" "always @* begin\n", indent.c_str());
+ f << stringf("%s" "always @* begin\n", indent.c_str());
dump_case_body(f, indent, &proc->root_case, true);
std::string backup_indent = indent;
@@ -821,23 +891,23 @@ void dump_process(FILE *f, std::string indent, RTLIL::Process *proc, bool find_r
indent = backup_indent;
if (sync->type == RTLIL::STa) {
- fprintf(f, "%s" "always @* begin\n", indent.c_str());
+ f << stringf("%s" "always @* begin\n", indent.c_str());
} else {
- fprintf(f, "%s" "always @(", indent.c_str());
+ f << stringf("%s" "always @(", indent.c_str());
if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
- fprintf(f, "posedge ");
+ f << stringf("posedge ");
if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
- fprintf(f, "negedge ");
+ f << stringf("negedge ");
dump_sigspec(f, sync->signal);
- fprintf(f, ") begin\n");
+ f << stringf(") begin\n");
}
std::string ends = indent + "end\n";
indent += " ";
if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) {
- fprintf(f, "%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
+ f << stringf("%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
dump_sigspec(f, sync->signal);
- fprintf(f, ") begin\n");
+ f << stringf(") begin\n");
ends = indent + "end\n" + ends;
indent += " ";
}
@@ -846,9 +916,9 @@ void dump_process(FILE *f, std::string indent, RTLIL::Process *proc, bool find_r
for (size_t j = 0; j < proc->syncs.size(); j++) {
RTLIL::SyncRule *sync2 = proc->syncs[j];
if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) {
- fprintf(f, "%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
+ f << stringf("%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
dump_sigspec(f, sync2->signal);
- fprintf(f, ") begin\n");
+ f << stringf(") begin\n");
ends = indent + "end\n" + ends;
indent += " ";
}
@@ -856,90 +926,93 @@ void dump_process(FILE *f, std::string indent, RTLIL::Process *proc, bool find_r
}
for (auto it = sync->actions.begin(); it != sync->actions.end(); it++) {
- if (it->first.width == 0)
+ if (it->first.size() == 0)
continue;
- fprintf(f, "%s ", indent.c_str());
+ f << stringf("%s ", indent.c_str());
dump_sigspec(f, it->first);
- fprintf(f, " <= ");
+ f << stringf(" <= ");
dump_sigspec(f, it->second);
- fprintf(f, ";\n");
+ f << stringf(";\n");
}
- fprintf(f, "%s", ends.c_str());
+ f << stringf("%s", ends.c_str());
}
}
-void dump_module(FILE *f, std::string indent, RTLIL::Module *module)
+void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
{
reg_wires.clear();
reset_auto_counter(module);
active_module = module;
- fprintf(f, "\n");
+ f << stringf("\n");
for (auto it = module->processes.begin(); it != module->processes.end(); it++)
dump_process(f, indent + " ", it->second, true);
if (!noexpr)
{
std::set<std::pair<RTLIL::Wire*,int>> reg_bits;
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
RTLIL::Cell *cell = it.second;
- if (!reg_ct.cell_known(cell->type) || cell->connections.count("\\Q") == 0)
+ if (!reg_ct.count(cell->type) || !cell->hasPort("\\Q"))
continue;
- RTLIL::SigSpec sig = cell->connections["\\Q"];
- sig.optimize();
+ RTLIL::SigSpec sig = cell->getPort("\\Q");
- if (sig.chunks.size() == 1 && sig.chunks[0].wire)
- for (int i = 0; i < sig.chunks[0].width; i++)
- reg_bits.insert(std::pair<RTLIL::Wire*,int>(sig.chunks[0].wire, sig.chunks[0].offset+i));
+ if (sig.is_chunk()) {
+ RTLIL::SigChunk chunk = sig.as_chunk();
+ if (chunk.wire != NULL)
+ for (int i = 0; i < chunk.width; i++)
+ reg_bits.insert(std::pair<RTLIL::Wire*,int>(chunk.wire, chunk.offset+i));
+ }
}
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
{
RTLIL::Wire *wire = it.second;
for (int i = 0; i < wire->width; i++)
if (reg_bits.count(std::pair<RTLIL::Wire*,int>(wire, i)) == 0)
goto this_wire_aint_reg;
- reg_wires.insert(wire->name);
+ if (wire->width)
+ reg_wires.insert(wire->name);
this_wire_aint_reg:;
}
}
dump_attributes(f, indent, module->attributes);
- fprintf(f, "%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
+ f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
bool keep_running = true;
for (int port_id = 1; keep_running; port_id++) {
keep_running = false;
- for (auto it = module->wires.begin(); it != module->wires.end(); it++) {
+ for (auto it = module->wires_.begin(); it != module->wires_.end(); it++) {
RTLIL::Wire *wire = it->second;
if (wire->port_id == port_id) {
if (port_id != 1)
- fprintf(f, ", ");
- fprintf(f, "%s", id(wire->name).c_str());
+ f << stringf(", ");
+ f << stringf("%s", id(wire->name).c_str());
keep_running = true;
continue;
}
}
}
- fprintf(f, ");\n");
+ f << stringf(");\n");
- for (auto it = module->wires.begin(); it != module->wires.end(); it++)
+ for (auto it = module->wires_.begin(); it != module->wires_.end(); it++)
dump_wire(f, indent + " ", it->second);
for (auto it = module->memories.begin(); it != module->memories.end(); it++)
dump_memory(f, indent + " ", it->second);
- for (auto it = module->cells.begin(); it != module->cells.end(); it++)
+ for (auto it = module->cells_.begin(); it != module->cells_.end(); it++)
dump_cell(f, indent + " ", it->second);
for (auto it = module->processes.begin(); it != module->processes.end(); it++)
dump_process(f, indent + " ", it->second);
- for (auto it = module->connections.begin(); it != module->connections.end(); it++)
+ for (auto it = module->connections().begin(); it != module->connections().end(); it++)
dump_conn(f, indent + " ", it->first, it->second);
- fprintf(f, "%s" "endmodule\n", indent.c_str());
+ f << stringf("%s" "endmodule\n", indent.c_str());
active_module = NULL;
}
@@ -980,7 +1053,7 @@ struct VerilogBackend : public Backend {
log(" not at all.\n");
log("\n");
}
- virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing Verilog backend.\n");
@@ -993,10 +1066,30 @@ struct VerilogBackend : public Backend {
bool selected = false;
reg_ct.clear();
- reg_ct.setup_stdcells_mem();
- reg_ct.cell_types.insert("$sr");
- reg_ct.cell_types.insert("$dff");
- reg_ct.cell_types.insert("$adff");
+
+ reg_ct.insert("$dff");
+ reg_ct.insert("$adff");
+
+ reg_ct.insert("$_DFF_N_");
+ reg_ct.insert("$_DFF_P_");
+
+ reg_ct.insert("$_DFF_NN0_");
+ reg_ct.insert("$_DFF_NN1_");
+ reg_ct.insert("$_DFF_NP0_");
+ reg_ct.insert("$_DFF_NP1_");
+ reg_ct.insert("$_DFF_PN0_");
+ reg_ct.insert("$_DFF_PN1_");
+ reg_ct.insert("$_DFF_PP0_");
+ reg_ct.insert("$_DFF_PP1_");
+
+ reg_ct.insert("$_DFFSR_NNN_");
+ reg_ct.insert("$_DFFSR_NNP_");
+ reg_ct.insert("$_DFFSR_NPN_");
+ reg_ct.insert("$_DFFSR_NPP_");
+ reg_ct.insert("$_DFFSR_PNN_");
+ reg_ct.insert("$_DFFSR_PNP_");
+ reg_ct.insert("$_DFFSR_PPN_");
+ reg_ct.insert("$_DFFSR_PPP_");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -1029,8 +1122,8 @@ struct VerilogBackend : public Backend {
}
extra_args(f, filename, args, argidx);
- fprintf(f, "/* Generated by %s */\n", yosys_version_str);
- for (auto it = design->modules.begin(); it != design->modules.end(); it++) {
+ *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)
continue;
if (selected && !design->selected_whole_module(it->first)) {
@@ -1039,7 +1132,7 @@ struct VerilogBackend : public Backend {
continue;
}
log("Dumping module `%s'.\n", it->first.c_str());
- dump_module(f, "", it->second);
+ dump_module(*f, "", it->second);
}
reg_ct.clear();
diff --git a/backends/verilog/verilog_backend.h b/backends/verilog/verilog_backend.h
index c40830ef..7e6ef5ab 100644
--- a/backends/verilog/verilog_backend.h
+++ b/backends/verilog/verilog_backend.h
@@ -29,11 +29,10 @@
#ifndef VERILOG_BACKEND_H
#define VERILOG_BACKEND_H
-#include "kernel/rtlil.h"
-#include <stdio.h>
+#include "kernel/yosys.h"
namespace VERILOG_BACKEND {
- void verilog_backend(FILE *f, std::vector<std::string> args, RTLIL::Design *design);
+ void verilog_backend(std::ostream &f, std::vector<std::string> args, RTLIL::Design *design);
}
#endif
diff --git a/frontends/ast/Makefile.inc b/frontends/ast/Makefile.inc
index 993ead92..91d917c9 100644
--- a/frontends/ast/Makefile.inc
+++ b/frontends/ast/Makefile.inc
@@ -2,4 +2,5 @@
OBJS += frontends/ast/ast.o
OBJS += frontends/ast/simplify.o
OBJS += frontends/ast/genrtlil.o
+OBJS += frontends/ast/dpicall.o
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 96608ae3..1e43875a 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -32,7 +32,9 @@
#include <sstream>
#include <stdarg.h>
-#include <assert.h>
+#include <math.h>
+
+YOSYS_NAMESPACE_BEGIN
using namespace AST;
using namespace AST_INTERNAL;
@@ -46,11 +48,10 @@ namespace AST {
// instanciate global variables (private API)
namespace AST_INTERNAL {
- bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells;
+ bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
AstNode *current_ast, *current_ast_mod;
std::map<std::string, AstNode*> current_scope;
- RTLIL::SigSpec *genRTLIL_subst_from = NULL;
- RTLIL::SigSpec *genRTLIL_subst_to = NULL;
+ const std::map<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
RTLIL::SigSpec ignoreThisSignalsInInitial;
AstNode *current_top_block, *current_block, *current_block_child;
AstModule *current_module;
@@ -67,6 +68,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_MODULE)
X(AST_TASK)
X(AST_FUNCTION)
+ X(AST_DPI_FUNCTION)
X(AST_WIRE)
X(AST_MEMORY)
X(AST_AUTOWIRE)
@@ -76,7 +78,9 @@ std::string AST::type2str(AstNodeType type)
X(AST_PARASET)
X(AST_ARGUMENT)
X(AST_RANGE)
+ X(AST_MULTIRANGE)
X(AST_CONSTANT)
+ X(AST_REALVALUE)
X(AST_CELLTYPE)
X(AST_IDENTIFIER)
X(AST_PREFIX)
@@ -127,6 +131,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_ASSIGN)
X(AST_CELL)
X(AST_PRIMITIVE)
+ X(AST_CELLARRAY)
X(AST_ALWAYS)
X(AST_INITIAL)
X(AST_BLOCK)
@@ -136,6 +141,8 @@ std::string AST::type2str(AstNodeType type)
X(AST_COND)
X(AST_DEFAULT)
X(AST_FOR)
+ X(AST_WHILE)
+ X(AST_REPEAT)
X(AST_GENVAR)
X(AST_GENFOR)
X(AST_GENIF)
@@ -177,10 +184,12 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2)
is_signed = false;
is_string = false;
range_valid = false;
+ range_swapped = false;
port_id = 0;
range_left = -1;
range_right = 0;
integer = 0;
+ realvalue = 0;
id2ast = NULL;
basic_prep = false;
@@ -243,6 +252,12 @@ void AstNode::dumpAst(FILE *f, std::string indent)
std::string type_name = type2str(type);
fprintf(f, "%s%s <%s:%d>", indent.c_str(), type_name.c_str(), filename.c_str(), linenum);
+
+ if (id2ast)
+ fprintf(f, " [%p -> %p]", this, id2ast);
+ else
+ fprintf(f, " [%p]", this);
+
if (!str.empty())
fprintf(f, " str='%s'", str.c_str());
if (!bits.empty()) {
@@ -265,9 +280,17 @@ void AstNode::dumpAst(FILE *f, std::string indent)
if (port_id > 0)
fprintf(f, " port=%d", port_id);
if (range_valid || range_left != -1 || range_right != 0)
- fprintf(f, " range=[%d:%d]%s", range_left, range_right, range_valid ? "" : "!");
+ fprintf(f, " %srange=[%d:%d]%s", range_swapped ? "swapped_" : "", range_left, range_right, range_valid ? "" : "!");
if (integer != 0)
fprintf(f, " int=%u", (int)integer);
+ if (realvalue != 0)
+ fprintf(f, " real=%e", realvalue);
+ if (!multirange_dimensions.empty()) {
+ fprintf(f, " multirange=[");
+ for (int v : multirange_dimensions)
+ fprintf(f, " %d", v);
+ fprintf(f, " ]");
+ }
fprintf(f, "\n");
for (auto &it : attributes) {
@@ -309,7 +332,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
}
for (auto &it : attributes) {
- fprintf(f, "%s" "(* %s = ", indent.c_str(), id2vl(it.first).c_str());
+ fprintf(f, "%s" "(* %s = ", indent.c_str(), id2vl(it.first.str()).c_str());
it.second->dumpVlog(f, "");
fprintf(f, " *)%s", indent.empty() ? "" : "\n");
}
@@ -451,6 +474,10 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
fprintf(f, "%zd'b %s", bits.size(), RTLIL::Const(bits).as_string().c_str());
break;
+ case AST_REALVALUE:
+ fprintf(f, "%e", realvalue);
+ break;
+
case AST_BLOCK:
if (children.size() == 1) {
children[0]->dumpVlog(f, indent);
@@ -603,6 +630,8 @@ bool AstNode::operator==(const AstNode &other) const
return false;
if (range_valid != other.range_valid)
return false;
+ if (range_swapped != other.range_swapped)
+ return false;
if (port_id != other.port_id)
return false;
if (range_left != other.range_left)
@@ -694,6 +723,14 @@ AstNode *AstNode::mkconst_str(const std::string &str)
return node;
}
+bool AstNode::bits_only_01()
+{
+ for (auto bit : bits)
+ if (bit != RTLIL::S0 && bit != RTLIL::S1)
+ return false;
+ return true;
+}
+
RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed)
{
std::vector<RTLIL::State> bits = this->bits;
@@ -746,11 +783,94 @@ bool AstNode::asBool()
return false;
}
+int AstNode::isConst()
+{
+ if (type == AST_CONSTANT)
+ return 1;
+ if (type == AST_REALVALUE)
+ return 2;
+ return 0;
+}
+
+uint64_t AstNode::asInt(bool is_signed)
+{
+ if (type == AST_CONSTANT)
+ {
+ RTLIL::Const v = bitsAsConst(64, is_signed);
+ uint64_t ret = 0;
+
+ for (int i = 0; i < 64; i++)
+ if (v.bits.at(i) == RTLIL::State::S1)
+ ret |= uint64_t(1) << i;
+
+ return ret;
+ }
+
+ if (type == AST_REALVALUE)
+ return realvalue;
+
+ log_abort();
+}
+
+double AstNode::asReal(bool is_signed)
+{
+ if (type == AST_CONSTANT)
+ {
+ RTLIL::Const val(bits);
+
+ bool is_negative = is_signed && val.bits.back() == RTLIL::State::S1;
+ if (is_negative)
+ val = const_neg(val, val, false, false, val.bits.size());
+
+ double v = 0;
+ for (size_t i = 0; i < val.bits.size(); i++)
+ // IEEE Std 1800-2012 Par 6.12.2: Individual bits that are x or z in
+ // the net or the variable shall be treated as zero upon conversion.
+ if (val.bits.at(i) == RTLIL::State::S1)
+ v += exp2(i);
+ if (is_negative)
+ v *= -1;
+
+ return v;
+ }
+
+ if (type == AST_REALVALUE)
+ return realvalue;
+
+ log_abort();
+}
+
+RTLIL::Const AstNode::realAsConst(int width)
+{
+ double v = round(realvalue);
+ RTLIL::Const result;
+#ifdef EMSCRIPTEN
+ if (!isfinite(v)) {
+#else
+ if (!std::isfinite(v)) {
+#endif
+ result.bits = std::vector<RTLIL::State>(width, RTLIL::State::Sx);
+ } else {
+ bool is_negative = v < 0;
+ if (is_negative)
+ v *= -1;
+ for (int i = 0; i < width; i++, v /= 2)
+ result.bits.push_back((fmod(floor(v), 2) != 0) ? RTLIL::State::S1 : RTLIL::State::S0);
+ if (is_negative)
+ result = const_neg(result, result, false, false, result.bits.size());
+ }
+ return result;
+}
+
// create a new AstModule from an AST_MODULE AST node
-static AstModule* process_module(AstNode *ast)
+static AstModule* process_module(AstNode *ast, bool defer)
{
- assert(ast->type == AST_MODULE);
- log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str());
+ log_assert(ast->type == AST_MODULE);
+
+ if (defer)
+ log("Storing AST representation for module `%s'.\n", ast->str.c_str());
+ else
+ log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str());
current_module = new AstModule;
current_module->ast = NULL;
@@ -766,60 +886,63 @@ static AstModule* process_module(AstNode *ast)
log("--- END OF AST DUMP ---\n");
}
- while (ast->simplify(!flag_noopt, false, false, 0, -1, false)) { }
+ if (!defer)
+ {
+ while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
- if (flag_dump_ast2) {
- log("Dumping verilog AST after simplification:\n");
- ast->dumpAst(NULL, " ");
- log("--- END OF AST DUMP ---\n");
- }
+ if (flag_dump_ast2) {
+ log("Dumping verilog 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");
- ast->dumpVlog(NULL, " ");
- log("--- END OF AST DUMP ---\n");
- }
+ if (flag_dump_vlog) {
+ log("Dumping verilog AST (as requested by dump_vlog option):\n");
+ ast->dumpVlog(NULL, " ");
+ log("--- END OF AST DUMP ---\n");
+ }
- if (flag_lib) {
- std::vector<AstNode*> new_children;
- for (auto child : ast->children) {
- if (child->type == AST_WIRE && (child->is_input || child->is_output))
- new_children.push_back(child);
- else
- delete child;
+ if (flag_lib) {
+ std::vector<AstNode*> new_children;
+ for (auto child : ast->children) {
+ if (child->type == AST_WIRE && (child->is_input || child->is_output))
+ new_children.push_back(child);
+ else
+ delete child;
+ }
+ ast->children.swap(new_children);
+ ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
}
- ast->children.swap(new_children);
- ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
- }
- ignoreThisSignalsInInitial = RTLIL::SigSpec();
+ ignoreThisSignalsInInitial = RTLIL::SigSpec();
- for (auto &attr : ast->attributes) {
- if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), ast->filename.c_str(), ast->linenum);
- current_module->attributes[attr.first] = attr.second->asAttrConst();
- }
- for (size_t i = 0; i < ast->children.size(); i++) {
- AstNode *node = ast->children[i];
- if (node->type == AST_WIRE || node->type == AST_MEMORY)
- node->genRTLIL();
- }
- for (size_t i = 0; i < ast->children.size(); i++) {
- AstNode *node = ast->children[i];
- if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
- node->genRTLIL();
- }
+ for (auto &attr : ast->attributes) {
+ if (attr.second->type != AST_CONSTANT)
+ log_error("Attribute `%s' with non-constant value at %s:%d!\n",
+ attr.first.c_str(), ast->filename.c_str(), ast->linenum);
+ current_module->attributes[attr.first] = attr.second->asAttrConst();
+ }
+ for (size_t i = 0; i < ast->children.size(); i++) {
+ AstNode *node = ast->children[i];
+ if (node->type == AST_WIRE || node->type == AST_MEMORY)
+ node->genRTLIL();
+ }
+ for (size_t i = 0; i < ast->children.size(); i++) {
+ AstNode *node = ast->children[i];
+ if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
+ node->genRTLIL();
+ }
- ignoreThisSignalsInInitial.sort_and_unify();
+ ignoreThisSignalsInInitial.sort_and_unify();
- for (size_t i = 0; i < ast->children.size(); i++) {
- AstNode *node = ast->children[i];
- if (node->type == AST_INITIAL)
- node->genRTLIL();
- }
+ for (size_t i = 0; i < ast->children.size(); i++) {
+ AstNode *node = ast->children[i];
+ if (node->type == AST_INITIAL)
+ node->genRTLIL();
+ }
- ignoreThisSignalsInInitial = RTLIL::SigSpec();
+ ignoreThisSignalsInInitial = RTLIL::SigSpec();
+ }
current_module->ast = ast_before_simplify;
current_module->nolatches = flag_nolatches;
@@ -828,11 +951,13 @@ static AstModule* process_module(AstNode *ast)
current_module->lib = flag_lib;
current_module->noopt = flag_noopt;
current_module->icells = flag_icells;
+ current_module->autowire = flag_autowire;
+ current_module->fixup_ports();
return current_module;
}
// create AstModule instances for all modules in the AST tree and add them to 'design'
-void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef)
+void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
{
current_ast = ast;
flag_dump_ast1 = dump_ast1;
@@ -844,18 +969,37 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
flag_lib = lib;
flag_noopt = noopt;
flag_icells = icells;
+ flag_autowire = autowire;
+
+ std::vector<AstNode*> global_decls;
- assert(current_ast->type == AST_DESIGN);
- for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++) {
- if (design->modules.count((*it)->str) != 0) {
- if (!ignore_redef)
- log_error("Re-definition of module `%s' at %s:%d!\n",
+ log_assert(current_ast->type == AST_DESIGN);
+ for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++)
+ {
+ if ((*it)->type == AST_MODULE)
+ {
+ for (auto n : global_decls)
+ (*it)->children.push_back(n->clone());
+
+ if (flag_icells && (*it)->str.substr(0, 2) == "\\$")
+ (*it)->str = (*it)->str.substr(1);
+
+ if (defer)
+ (*it)->str = "$abstract" + (*it)->str;
+
+ if (design->has((*it)->str)) {
+ if (!ignore_redef)
+ log_error("Re-definition of module `%s' at %s:%d!\n",
+ (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
+ log("Ignoring re-definition of module `%s' at %s:%d!\n",
(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
- log_error("Ignoring re-definition of module `%s' at %s:%d!\n",
- (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
- continue;
+ continue;
+ }
+
+ design->add(process_module(*it, defer));
}
- design->modules[(*it)->str] = process_module(*it);
+ else
+ global_decls.push_back(*it);
}
}
@@ -869,7 +1013,12 @@ AstModule::~AstModule()
// create a new parametric module (when needed) and return the name of the generated module
RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters)
{
- log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", name.c_str());
+ std::string stripped_name = name.str();
+
+ if (stripped_name.substr(0, 9) == "$abstract")
+ stripped_name = stripped_name.substr(9);
+
+ log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str());
current_ast = NULL;
flag_dump_ast1 = false;
@@ -881,16 +1030,14 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
flag_lib = lib;
flag_noopt = noopt;
flag_icells = icells;
+ flag_autowire = autowire;
use_internal_line_num();
std::string para_info;
- std::vector<unsigned char> hash_data;
- hash_data.insert(hash_data.end(), name.begin(), name.end());
- hash_data.push_back(0);
-
AstNode *new_ast = ast->clone();
int para_counter = 0;
+ int orig_parameters_n = parameters.size();
for (auto it = new_ast->children.begin(); it != new_ast->children.end(); it++) {
AstNode *child = *it;
if (child->type != AST_PARAMETER)
@@ -903,10 +1050,6 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id])));
delete child->children.at(0);
child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, (parameters[para_id].flags & RTLIL::CONST_FLAG_SIGNED) != 0);
- hash_data.insert(hash_data.end(), child->str.begin(), child->str.end());
- hash_data.push_back(0);
- hash_data.insert(hash_data.end(), parameters[para_id].bits.begin(), parameters[para_id].bits.end());
- hash_data.push_back(0xff);
parameters.erase(para_id);
continue;
}
@@ -917,33 +1060,21 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
}
}
if (parameters.size() > 0)
- log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), name.c_str());
+ log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), stripped_name.c_str());
std::string modname;
- if (para_info.size() > 60)
- {
- unsigned char hash[20];
- unsigned char *hash_data2 = new unsigned char[hash_data.size()];
- for (size_t i = 0; i < hash_data.size(); i++)
- hash_data2[i] = hash_data[i];
- sha1::calc(hash_data2, hash_data.size(), hash);
- delete[] hash_data2;
-
- char hexstring[41];
- sha1::toHexString(hash, hexstring);
-
- modname = "$paramod$" + std::string(hexstring) + name;
- }
+ if (orig_parameters_n == 0)
+ modname = stripped_name;
+ else if (para_info.size() > 60)
+ modname = "$paramod$" + sha1(para_info) + stripped_name;
else
- {
- modname = "$paramod" + name + para_info;
- }
+ modname = "$paramod" + stripped_name + para_info;
- if (design->modules.count(modname) == 0) {
+ if (!design->has(modname)) {
new_ast->str = modname;
- design->modules[modname] = process_module(new_ast);
- design->modules[modname]->check();
+ design->add(process_module(new_ast, false));
+ design->module(modname)->check();
} else {
log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
}
@@ -955,6 +1086,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
RTLIL::Module *AstModule::clone() const
{
AstModule *new_mod = new AstModule;
+ new_mod->name = name;
cloneInto(new_mod);
new_mod->ast = ast->clone();
@@ -964,6 +1096,7 @@ RTLIL::Module *AstModule::clone() const
new_mod->lib = lib;
new_mod->noopt = noopt;
new_mod->icells = icells;
+ new_mod->autowire = autowire;
return new_mod;
}
@@ -986,3 +1119,5 @@ void AST::use_internal_line_num()
get_line_num = &internal_get_line_num;
}
+YOSYS_NAMESPACE_END
+
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 01702c3c..0a401673 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -33,6 +33,8 @@
#include <stdint.h>
#include <set>
+YOSYS_NAMESPACE_BEGIN
+
namespace AST
{
// all node types, type2str() must be extended
@@ -44,6 +46,7 @@ namespace AST
AST_MODULE,
AST_TASK,
AST_FUNCTION,
+ AST_DPI_FUNCTION,
AST_WIRE,
AST_MEMORY,
@@ -54,7 +57,9 @@ namespace AST
AST_PARASET,
AST_ARGUMENT,
AST_RANGE,
+ AST_MULTIRANGE,
AST_CONSTANT,
+ AST_REALVALUE,
AST_CELLTYPE,
AST_IDENTIFIER,
AST_PREFIX,
@@ -107,6 +112,7 @@ namespace AST
AST_ASSIGN,
AST_CELL,
AST_PRIMITIVE,
+ AST_CELLARRAY,
AST_ALWAYS,
AST_INITIAL,
AST_BLOCK,
@@ -116,6 +122,8 @@ namespace AST
AST_COND,
AST_DEFAULT,
AST_FOR,
+ AST_WHILE,
+ AST_REPEAT,
AST_GENVAR,
AST_GENFOR,
@@ -147,9 +155,13 @@ namespace AST
// node content - most of it is unused in most node types
std::string str;
std::vector<RTLIL::State> bits;
- bool is_input, is_output, is_reg, is_signed, is_string, range_valid;
+ bool is_input, is_output, is_reg, is_signed, is_string, range_valid, range_swapped;
int port_id, range_left, range_right;
uint32_t integer;
+ double realvalue;
+
+ // if this is a multirange memory then this vector contains offset and length of each dimension
+ std::vector<int> multirange_dimensions;
// this is set by simplify and used during RTLIL generation
AstNode *id2ast;
@@ -183,6 +195,7 @@ namespace AST
MEM2REG_FL_SET_ELSE = 0x00000400,
MEM2REG_FL_SET_ASYNC = 0x00000800,
MEM2REG_FL_EQ2 = 0x00001000,
+ MEM2REG_FL_CMPLX_LHS = 0x00002000,
/* proc flags */
MEM2REG_FL_EQ1 = 0x01000000,
@@ -190,27 +203,33 @@ namespace AST
// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.
// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
- bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint);
+ bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param);
void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map);
- void replace_ids(std::map<std::string, std::string> &rules);
+ void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules);
void mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
std::map<AstNode*, uint32_t> &mem2reg_flags, std::map<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
void mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
+ // additional functionality for evaluating constant functions
+ struct varinfo_t { RTLIL::Const val; int offset; bool is_signed; };
+ 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);
+
// create a human-readable text representation of the AST (for debugging)
void dumpAst(FILE *f, std::string indent);
void dumpVlog(FILE *f, std::string indent);
// used by genRTLIL() for detecting expression width and sign
- void detectSignWidthWorker(int &width_hint, bool &sign_hint);
- void detectSignWidth(int &width_hint, bool &sign_hint);
+ void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL);
+ void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL);
// create RTLIL code for this AST node
// for expressions the resulting signal vector is returned
// all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module
RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false);
- RTLIL::SigSpec genWidthRTLIL(int width, RTLIL::SigSpec *subst_from = NULL, RTLIL::SigSpec *subst_to = NULL);
+ RTLIL::SigSpec genWidthRTLIL(int width, const std::map<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
// compare AST nodes
bool operator==(const AstNode &other) const;
@@ -228,17 +247,24 @@ namespace AST
RTLIL::Const bitsAsConst(int width = -1);
RTLIL::Const asAttrConst();
RTLIL::Const asParaConst();
+ uint64_t asInt(bool is_signed);
+ bool bits_only_01();
bool asBool();
+
+ // helper functions for real valued const eval
+ int isConst(); // return '1' for AST_CONSTANT and '2' for AST_REALVALUE
+ double asReal(bool is_signed);
+ RTLIL::Const realAsConst(int width);
};
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
- void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1 = false, bool dump_ast2 = false, bool dump_vlog = false, bool nolatches = false, bool nomem2reg = false, bool mem2reg = false, bool lib = false, bool noopt = false, bool icells = false, bool ignore_redef = false);
+ void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
// parametric modules are supported directly by the AST library
// therfore we need our own derivate of RTLIL::Module with overloaded virtual functions
struct AstModule : RTLIL::Module {
AstNode *ast;
- bool nolatches, nomem2reg, mem2reg, lib, noopt, icells;
+ bool nolatches, nomem2reg, mem2reg, lib, noopt, icells, autowire;
virtual ~AstModule();
virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
virtual RTLIL::Module *clone() const;
@@ -254,18 +280,24 @@ namespace AST
// set set_line_num and get_line_num to internal dummy functions (done by simplify() and AstModule::derive
// to control the filename and linenum properties of new nodes not generated by a frontend parser)
void use_internal_line_num();
+
+ // 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);
}
namespace AST_INTERNAL
{
// internal state variables
- extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells;
+ extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
extern AST::AstNode *current_ast, *current_ast_mod;
extern std::map<std::string, AST::AstNode*> current_scope;
- extern RTLIL::SigSpec *genRTLIL_subst_from, *genRTLIL_subst_to, ignoreThisSignalsInInitial;
+ extern const std::map<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
+ extern RTLIL::SigSpec ignoreThisSignalsInInitial;
extern AST::AstNode *current_top_block, *current_block, *current_block_child;
extern AST::AstModule *current_module;
struct ProcessGenerator;
}
+YOSYS_NAMESPACE_END
+
#endif
diff --git a/frontends/ast/dpicall.cc b/frontends/ast/dpicall.cc
new file mode 100644
index 00000000..2eb104fa
--- /dev/null
+++ b/frontends/ast/dpicall.cc
@@ -0,0 +1,140 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "ast.h"
+
+#ifdef YOSYS_ENABLE_PLUGINS
+
+#include <dlfcn.h>
+#include <ffi.h>
+
+typedef void (*ffi_fptr) ();
+
+static ffi_fptr resolve_fn (std::string symbol_name)
+{
+ if (symbol_name.find(':') != std::string::npos)
+ {
+ int pos = symbol_name.find(':');
+ std::string plugin_name = symbol_name.substr(0, pos);
+ std::string real_symbol_name = symbol_name.substr(pos+1);
+
+ while (loaded_plugin_aliases.count(plugin_name))
+ plugin_name = loaded_plugin_aliases.at(plugin_name);
+
+ if (loaded_plugins.count(plugin_name) == 0)
+ log_error("unable to resolve '%s': can't find plugin `%s'\n", symbol_name.c_str(), plugin_name.c_str());
+
+ void *symbol = dlsym(loaded_plugins.at(plugin_name), real_symbol_name.c_str());
+
+ if (symbol == nullptr)
+ log_error("unable to resolve '%s': can't find symbol `%s' in plugin `%s'\n",
+ symbol_name.c_str(), real_symbol_name.c_str(), plugin_name.c_str());
+
+ return (ffi_fptr) symbol;
+ }
+
+ for (auto &it : loaded_plugins) {
+ void *symbol = dlsym(it.second, symbol_name.c_str());
+ if (symbol != nullptr)
+ return (ffi_fptr) symbol;
+ }
+
+ void *symbol = dlsym(RTLD_DEFAULT, symbol_name.c_str());
+ if (symbol != nullptr)
+ return (ffi_fptr) symbol;
+
+ log_error("unable to resolve '%s'.\n", symbol_name.c_str());
+}
+
+AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args)
+{
+ AST::AstNode *newNode = nullptr;
+ union { double f64; float f32; int32_t i32; } value_store [args.size() + 1];
+ ffi_type *types [args.size() + 1];
+ void *values [args.size() + 1];
+ ffi_cif cif;
+ int status;
+
+ log("Calling DPI function `%s' and returning `%s':\n", fname.c_str(), rtype.c_str());
+
+ log_assert(SIZE(args) == SIZE(argtypes));
+ for (int i = 0; i < SIZE(args); i++) {
+ if (argtypes[i] == "real") {
+ log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
+ value_store[i].f64 = args[i]->asReal(args[i]->is_signed);
+ values[i] = &value_store[i].f64;
+ types[i] = &ffi_type_double;
+ } else if (argtypes[i] == "shortreal") {
+ log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
+ value_store[i].f32 = args[i]->asReal(args[i]->is_signed);
+ values[i] = &value_store[i].f32;
+ types[i] = &ffi_type_double;
+ } else if (argtypes[i] == "integer") {
+ log(" arg %d (%s): %lld\n", i, argtypes[i].c_str(), (long long)args[i]->asInt(args[i]->is_signed));
+ value_store[i].i32 = args[i]->asInt(args[i]->is_signed);
+ values[i] = &value_store[i].i32;
+ types[i] = &ffi_type_sint32;
+ } else {
+ log_error("invalid argtype '%s' for argument %d.\n", argtypes[i].c_str(), i);
+ }
+ }
+
+ if (rtype == "integer") {
+ types[args.size()] = &ffi_type_slong;
+ values[args.size()] = &value_store[args.size()].i32;
+ } else if (rtype == "shortreal") {
+ types[args.size()] = &ffi_type_float;
+ values[args.size()] = &value_store[args.size()].f32;
+ } else if (rtype == "real") {
+ types[args.size()] = &ffi_type_double;
+ values[args.size()] = &value_store[args.size()].f64;
+ } else {
+ log_error("invalid rtype '%s'.\n", rtype.c_str());
+ }
+
+ if ((status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, args.size(), types[args.size()], types)) != FFI_OK)
+ log_error("ffi_prep_cif failed: status %d.\n", status);
+
+ ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values);
+
+ if (rtype == "real") {
+ newNode = new AstNode(AST_REALVALUE);
+ newNode->realvalue = value_store[args.size()].f64;
+ log(" return realvalue: %g\n", newNode->asReal(true));
+ } else if (rtype == "shortreal") {
+ newNode = new AstNode(AST_REALVALUE);
+ newNode->realvalue = value_store[args.size()].f32;
+ log(" return realvalue: %g\n", newNode->asReal(true));
+ } else {
+ newNode = AstNode::mkconst_int(value_store[args.size()].i32, false);
+ log(" return integer: %lld\n", (long long)newNode->asInt(true));
+ }
+
+ return newNode;
+}
+
+#else /* YOSYS_ENABLE_PLUGINS */
+
+AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&)
+{
+ log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
+}
+
+#endif /* YOSYS_ENABLE_PLUGINS */
+
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 591d027c..f87a68f6 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -27,14 +27,16 @@
*/
#include "kernel/log.h"
+#include "kernel/utils.h"
#include "libs/sha1/sha1.h"
#include "ast.h"
#include <sstream>
#include <stdarg.h>
-#include <assert.h>
#include <algorithm>
+YOSYS_NAMESPACE_BEGIN
+
using namespace AST;
using namespace AST_INTERNAL;
@@ -42,28 +44,13 @@ using namespace AST_INTERNAL;
static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true)
{
std::stringstream sstr;
- sstr << type << "$" << that->filename << ":" << that->linenum << "$" << (RTLIL::autoidx++);
+ sstr << type << "$" << that->filename << ":" << that->linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = new RTLIL::Cell;
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), type);
cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum);
- cell->name = sstr.str();
- cell->type = type;
- current_module->cells[cell->name] = cell;
- RTLIL::Wire *wire = new RTLIL::Wire;
+ RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", result_width);
wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum);
- wire->name = cell->name + "_Y";
- wire->width = result_width;
- current_module->wires[wire->name] = wire;
-
- RTLIL::SigChunk chunk;
- chunk.wire = wire;
- chunk.width = wire->width;
- chunk.offset = 0;
-
- RTLIL::SigSpec sig;
- sig.chunks.push_back(chunk);
- sig.width = chunk.width;
if (gen_attributes)
for (auto &attr : that->attributes) {
@@ -74,45 +61,30 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_wi
}
cell->parameters["\\A_SIGNED"] = RTLIL::Const(that->children[0]->is_signed);
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(arg.width);
- cell->connections["\\A"] = arg;
+ cell->parameters["\\A_WIDTH"] = RTLIL::Const(arg.size());
+ cell->setPort("\\A", arg);
cell->parameters["\\Y_WIDTH"] = result_width;
- cell->connections["\\Y"] = sig;
- return sig;
+ cell->setPort("\\Y", wire);
+ return wire;
}
// helper function for extending bit width (preferred over SigSpec::extend() because of correct undef propagation in ConstEval)
static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_signed)
{
- if (width <= sig.width) {
+ if (width <= sig.size()) {
sig.extend(width, is_signed);
return;
}
std::stringstream sstr;
- sstr << "$extend" << "$" << that->filename << ":" << that->linenum << "$" << (RTLIL::autoidx++);
+ sstr << "$extend" << "$" << that->filename << ":" << that->linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = new RTLIL::Cell;
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$pos");
cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum);
- cell->name = sstr.str();
- cell->type = "$pos";
- current_module->cells[cell->name] = cell;
- RTLIL::Wire *wire = new RTLIL::Wire;
+ RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", width);
wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum);
- wire->name = cell->name + "_Y";
- wire->width = width;
- current_module->wires[wire->name] = wire;
-
- RTLIL::SigChunk chunk;
- chunk.wire = wire;
- chunk.width = wire->width;
- chunk.offset = 0;
-
- RTLIL::SigSpec new_sig;
- new_sig.chunks.push_back(chunk);
- new_sig.width = chunk.width;
if (that != NULL)
for (auto &attr : that->attributes) {
@@ -123,40 +95,25 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
}
cell->parameters["\\A_SIGNED"] = RTLIL::Const(is_signed);
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig.width);
- cell->connections["\\A"] = sig;
+ cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig.size());
+ cell->setPort("\\A", sig);
cell->parameters["\\Y_WIDTH"] = width;
- cell->connections["\\Y"] = new_sig;
- sig = new_sig;
+ cell->setPort("\\Y", wire);
+ sig = wire;
}
// helper function for creating RTLIL code for binary operations
static RTLIL::SigSpec binop2rtlil(AstNode *that, std::string type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
{
std::stringstream sstr;
- sstr << type << "$" << that->filename << ":" << that->linenum << "$" << (RTLIL::autoidx++);
+ sstr << type << "$" << that->filename << ":" << that->linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = new RTLIL::Cell;
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), type);
cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum);
- cell->name = sstr.str();
- cell->type = type;
- current_module->cells[cell->name] = cell;
- RTLIL::Wire *wire = new RTLIL::Wire;
+ RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", result_width);
wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum);
- wire->name = cell->name + "_Y";
- wire->width = result_width;
- current_module->wires[wire->name] = wire;
-
- RTLIL::SigChunk chunk;
- chunk.wire = wire;
- chunk.width = wire->width;
- chunk.offset = 0;
-
- RTLIL::SigSpec sig;
- sig.chunks.push_back(chunk);
- sig.width = chunk.width;
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
@@ -168,45 +125,30 @@ static RTLIL::SigSpec binop2rtlil(AstNode *that, std::string type, int result_wi
cell->parameters["\\A_SIGNED"] = RTLIL::Const(that->children[0]->is_signed);
cell->parameters["\\B_SIGNED"] = RTLIL::Const(that->children[1]->is_signed);
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(left.width);
- cell->parameters["\\B_WIDTH"] = RTLIL::Const(right.width);
+ cell->parameters["\\A_WIDTH"] = RTLIL::Const(left.size());
+ cell->parameters["\\B_WIDTH"] = RTLIL::Const(right.size());
- cell->connections["\\A"] = left;
- cell->connections["\\B"] = right;
+ cell->setPort("\\A", left);
+ cell->setPort("\\B", right);
cell->parameters["\\Y_WIDTH"] = result_width;
- cell->connections["\\Y"] = sig;
- return sig;
+ cell->setPort("\\Y", wire);
+ return wire;
}
// helper function for creating RTLIL code for multiplexers
static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
{
- assert(cond.width == 1);
+ log_assert(cond.size() == 1);
std::stringstream sstr;
- sstr << "$ternary$" << that->filename << ":" << that->linenum << "$" << (RTLIL::autoidx++);
+ sstr << "$ternary$" << that->filename << ":" << that->linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = new RTLIL::Cell;
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$mux");
cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum);
- cell->name = sstr.str();
- cell->type = "$mux";
- current_module->cells[cell->name] = cell;
- RTLIL::Wire *wire = new RTLIL::Wire;
+ RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", left.size());
wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum);
- wire->name = cell->name + "_Y";
- wire->width = left.width;
- current_module->wires[wire->name] = wire;
-
- RTLIL::SigChunk chunk;
- chunk.wire = wire;
- chunk.width = wire->width;
- chunk.offset = 0;
-
- RTLIL::SigSpec sig;
- sig.chunks.push_back(chunk);
- sig.width = chunk.width;
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
@@ -215,14 +157,14 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const
cell->attributes[attr.first] = attr.second->asAttrConst();
}
- cell->parameters["\\WIDTH"] = RTLIL::Const(left.width);
+ cell->parameters["\\WIDTH"] = RTLIL::Const(left.size());
- cell->connections["\\A"] = right;
- cell->connections["\\B"] = left;
- cell->connections["\\S"] = cond;
- cell->connections["\\Y"] = sig;
+ cell->setPort("\\A", right);
+ cell->setPort("\\B", left);
+ cell->setPort("\\S", cond);
+ cell->setPort("\\Y", wire);
- return sig;
+ return wire;
}
// helper class for converting AST always nodes to RTLIL processes
@@ -232,23 +174,23 @@ struct AST_INTERNAL::ProcessGenerator
AstNode *always;
RTLIL::SigSpec initSyncSignals;
RTLIL::Process *proc;
- const RTLIL::SigSpec &outputSignals;
+ RTLIL::SigSpec outputSignals;
// This always points to the RTLIL::CaseRule beeing filled at the moment
RTLIL::CaseRule *current_case;
- // This two variables contain the replacement pattern to be used in the right hand side
+ // This map contains the replacement pattern to be used in the right hand side
// of an assignment. E.g. in the code "foo = bar; foo = func(foo);" the foo in the right
// hand side of the 2nd assignment needs to be replace with the temporary signal holding
// the value assigned in the first assignment. So when the first assignement is processed
// the according information is appended to subst_rvalue_from and subst_rvalue_to.
- RTLIL::SigSpec subst_rvalue_from, subst_rvalue_to;
+ stackmap<RTLIL::SigBit, RTLIL::SigBit> subst_rvalue_map;
- // This two variables contain the replacement pattern to be used in the left hand side
+ // This map contains the replacement pattern to be used in the left hand side
// of an assignment. E.g. in the code "always @(posedge clk) foo <= bar" the signal bar
// should not be connected to the signal foo. Instead it must be connected to the temporary
// signal that is used as input for the register that drives the signal foo.
- RTLIL::SigSpec subst_lvalue_from, subst_lvalue_to;
+ stackmap<RTLIL::SigBit, RTLIL::SigBit> subst_lvalue_map;
// The code here generates a number of temprorary signal for each output register. This
// map helps generating nice numbered names for all this temporary signals.
@@ -257,12 +199,12 @@ struct AST_INTERNAL::ProcessGenerator
// Buffer for generating the init action
RTLIL::SigSpec init_lvalue, init_rvalue;
- ProcessGenerator(AstNode *always, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(always), initSyncSignals(initSyncSignalsArg), outputSignals(subst_lvalue_from)
+ ProcessGenerator(AstNode *always, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(always), initSyncSignals(initSyncSignalsArg)
{
// generate process and simple root case
proc = new RTLIL::Process;
proc->attributes["\\src"] = stringf("%s:%d", always->filename.c_str(), always->linenum);
- proc->name = stringf("$proc$%s:%d$%d", always->filename.c_str(), always->linenum, RTLIL::autoidx++);
+ proc->name = stringf("$proc$%s:%d$%d", always->filename.c_str(), always->linenum, autoidx++);
for (auto &attr : always->attributes) {
if (attr.second->type != AST_CONSTANT)
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
@@ -273,8 +215,10 @@ struct AST_INTERNAL::ProcessGenerator
current_case = &proc->root_case;
// create initial temporary signal for all output registers
+ RTLIL::SigSpec subst_lvalue_from, subst_lvalue_to;
collect_lvalues(subst_lvalue_from, always, true, true);
subst_lvalue_to = new_temp_signal(subst_lvalue_from);
+ subst_lvalue_map = subst_lvalue_from.to_sigbit_map(subst_lvalue_to);
bool found_anyedge_syncs = false;
for (auto child : always->children)
@@ -310,8 +254,7 @@ struct AST_INTERNAL::ProcessGenerator
// create initial assignments for the temporary signals
if ((flag_nolatches || always->get_bool_attribute("\\nolatches") || current_module->get_bool_attribute("\\nolatches")) && !found_clocked_sync) {
- subst_rvalue_from = subst_lvalue_from;
- subst_rvalue_to = RTLIL::SigSpec(RTLIL::State::Sx, subst_rvalue_from.width);
+ subst_rvalue_map = subst_lvalue_from.to_sigbit_map(RTLIL::SigSpec(RTLIL::State::Sx, SIZE(subst_lvalue_from)));
} else {
addChunkActions(current_case->actions, subst_lvalue_to, subst_lvalue_from);
}
@@ -321,51 +264,70 @@ struct AST_INTERNAL::ProcessGenerator
if (child->type == AST_BLOCK)
processAst(child);
- if (initSyncSignals.width > 0)
+ if (initSyncSignals.size() > 0)
{
RTLIL::SyncRule *sync = new RTLIL::SyncRule;
sync->type = RTLIL::SyncType::STi;
proc->syncs.push_back(sync);
- assert(init_lvalue.width == init_rvalue.width);
- init_lvalue.optimize();
- init_rvalue.optimize();
+ log_assert(init_lvalue.size() == init_rvalue.size());
int offset = 0;
- for (size_t i = 0; i < init_lvalue.chunks.size(); i++) {
- RTLIL::SigSpec lhs = init_lvalue.chunks[i];
- RTLIL::SigSpec rhs = init_rvalue.extract(offset, init_lvalue.chunks[i].width);
+ for (auto &init_lvalue_c : init_lvalue.chunks()) {
+ RTLIL::SigSpec lhs = init_lvalue_c;
+ RTLIL::SigSpec rhs = init_rvalue.extract(offset, init_lvalue_c.width);
+ remove_unwanted_lvalue_bits(lhs, rhs);
sync->actions.push_back(RTLIL::SigSig(lhs, rhs));
- offset += lhs.width;
+ offset += lhs.size();
}
}
+
+ outputSignals = RTLIL::SigSpec(subst_lvalue_from);
+ }
+
+ void remove_unwanted_lvalue_bits(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs)
+ {
+ RTLIL::SigSpec new_lhs, new_rhs;
+
+ log_assert(SIZE(lhs) == SIZE(rhs));
+ for (int i = 0; i < SIZE(lhs); i++) {
+ if (lhs[i].wire == nullptr)
+ continue;
+ new_lhs.append(lhs[i]);
+ new_rhs.append(rhs[i]);
+ }
+
+ lhs = new_lhs;
+ rhs = new_rhs;
}
// create new temporary signals
RTLIL::SigSpec new_temp_signal(RTLIL::SigSpec sig)
{
- sig.optimize();
- for (size_t i = 0; i < sig.chunks.size(); i++)
+ std::vector<RTLIL::SigChunk> chunks = sig.chunks();
+
+ for (int i = 0; i < SIZE(chunks); i++)
{
- RTLIL::SigChunk &chunk = sig.chunks[i];
+ RTLIL::SigChunk &chunk = chunks[i];
if (chunk.wire == NULL)
continue;
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->attributes["\\src"] = stringf("%s:%d", always->filename.c_str(), always->linenum);
+ std::string wire_name;
do {
- wire->name = stringf("$%d%s[%d:%d]", new_temp_count[chunk.wire]++,
+ wire_name = stringf("$%d%s[%d:%d]", new_temp_count[chunk.wire]++,
chunk.wire->name.c_str(), chunk.width+chunk.offset-1, chunk.offset);;
- if (chunk.wire->name.find('$') != std::string::npos)
- wire->name += stringf("$%d", RTLIL::autoidx++);
- } while (current_module->wires.count(wire->name) > 0);
- wire->width = chunk.width;
- current_module->wires[wire->name] = wire;
+ if (chunk.wire->name.str().find('$') != std::string::npos)
+ wire_name += stringf("$%d", autoidx++);
+ } while (current_module->wires_.count(wire_name) > 0);
+
+ RTLIL::Wire *wire = current_module->addWire(wire_name, chunk.width);
+ wire->attributes["\\src"] = stringf("%s:%d", always->filename.c_str(), always->linenum);
chunk.wire = wire;
chunk.offset = 0;
}
- return sig;
+
+ return chunks;
}
// recursively traverse the AST an collect all assigned signals
@@ -376,7 +338,7 @@ struct AST_INTERNAL::ProcessGenerator
case AST_CASE:
for (auto child : ast->children)
if (child != ast->children[0]) {
- assert(child->type == AST_COND);
+ log_assert(child->type == AST_COND);
collect_lvalues(reg, child, type_eq, type_le, false);
}
break;
@@ -401,18 +363,23 @@ struct AST_INTERNAL::ProcessGenerator
break;
default:
- assert(0);
+ log_abort();
}
- if (run_sort_and_unify)
- reg.sort_and_unify();
+ if (run_sort_and_unify) {
+ std::set<RTLIL::SigBit> sorted_reg;
+ for (auto bit : reg)
+ if (bit.wire)
+ sorted_reg.insert(bit);
+ reg = RTLIL::SigSpec(sorted_reg);
+ }
}
// remove all assignments to the given signal pattern in a case and all its children.
// e.g. when the last statement in the code "a = 23; if (b) a = 42; a = 0;" is processed this
// function is called to clean up the first two assignments as they are overwritten by
// the third assignment.
- void removeSignalFromCaseTree(RTLIL::SigSpec pattern, RTLIL::CaseRule *cs)
+ void removeSignalFromCaseTree(const std::set<RTLIL::SigBit> &pattern, RTLIL::CaseRule *cs)
{
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)
it->first.remove2(pattern, &it->second);
@@ -426,23 +393,22 @@ struct AST_INTERNAL::ProcessGenerator
// are avoided and the generated $mux cells have a more "natural" size.
void addChunkActions(std::vector<RTLIL::SigSig> &actions, RTLIL::SigSpec lvalue, RTLIL::SigSpec rvalue, bool inSyncRule = false)
{
- if (inSyncRule && initSyncSignals.width > 0) {
+ if (inSyncRule && initSyncSignals.size() > 0) {
init_lvalue.append(lvalue.extract(initSyncSignals));
init_rvalue.append(lvalue.extract(initSyncSignals, &rvalue));
lvalue.remove2(initSyncSignals, &rvalue);
}
- assert(lvalue.width == rvalue.width);
- lvalue.optimize();
- rvalue.optimize();
+ log_assert(lvalue.size() == rvalue.size());
int offset = 0;
- for (size_t i = 0; i < lvalue.chunks.size(); i++) {
- RTLIL::SigSpec lhs = lvalue.chunks[i];
- RTLIL::SigSpec rhs = rvalue.extract(offset, lvalue.chunks[i].width);
- if (inSyncRule && lvalue.chunks[i].wire && lvalue.chunks[i].wire->get_bool_attribute("\\nosync"))
- rhs = RTLIL::SigSpec(RTLIL::State::Sx, rhs.width);
+ for (auto &lvalue_c : lvalue.chunks()) {
+ RTLIL::SigSpec lhs = lvalue_c;
+ RTLIL::SigSpec rhs = rvalue.extract(offset, lvalue_c.width);
+ if (inSyncRule && lvalue_c.wire && lvalue_c.wire->get_bool_attribute("\\nosync"))
+ rhs = RTLIL::SigSpec(RTLIL::State::Sx, rhs.size());
+ remove_unwanted_lvalue_bits(lhs, rhs);
actions.push_back(RTLIL::SigSig(lhs, rhs));
- offset += lhs.width;
+ offset += lhs.size();
}
}
@@ -460,18 +426,16 @@ struct AST_INTERNAL::ProcessGenerator
case AST_ASSIGN_LE:
{
RTLIL::SigSpec unmapped_lvalue = ast->children[0]->genRTLIL(), lvalue = unmapped_lvalue;
- RTLIL::SigSpec rvalue = ast->children[1]->genWidthRTLIL(lvalue.width, &subst_rvalue_from, &subst_rvalue_to);
- lvalue.replace(subst_lvalue_from, subst_lvalue_to);
+ RTLIL::SigSpec rvalue = ast->children[1]->genWidthRTLIL(lvalue.size(), &subst_rvalue_map.stdmap());
+ lvalue.replace(subst_lvalue_map.stdmap());
if (ast->type == AST_ASSIGN_EQ) {
- subst_rvalue_from.remove2(unmapped_lvalue, &subst_rvalue_to);
- subst_rvalue_from.append(unmapped_lvalue);
- subst_rvalue_from.optimize();
- subst_rvalue_to.append(rvalue);
- subst_rvalue_to.optimize();
+ for (int i = 0; i < SIZE(unmapped_lvalue); i++)
+ subst_rvalue_map.set(unmapped_lvalue[i], rvalue[i]);
}
- removeSignalFromCaseTree(lvalue, current_case);
+ removeSignalFromCaseTree(lvalue.to_sigbit_set(), current_case);
+ remove_unwanted_lvalue_bits(lvalue, rvalue);
current_case->actions.push_back(RTLIL::SigSig(lvalue, rvalue));
}
break;
@@ -479,7 +443,7 @@ struct AST_INTERNAL::ProcessGenerator
case AST_CASE:
{
RTLIL::SwitchRule *sw = new RTLIL::SwitchRule;
- sw->signal = ast->children[0]->genWidthRTLIL(-1, &subst_rvalue_from, &subst_rvalue_to);
+ sw->signal = ast->children[0]->genWidthRTLIL(-1, &subst_rvalue_map.stdmap());
current_case->switches.push_back(sw);
for (auto &attr : ast->attributes) {
@@ -495,13 +459,7 @@ struct AST_INTERNAL::ProcessGenerator
RTLIL::SigSpec this_case_eq_ltemp = new_temp_signal(this_case_eq_lvalue);
RTLIL::SigSpec this_case_eq_rvalue = this_case_eq_lvalue;
- this_case_eq_rvalue.replace(subst_rvalue_from, subst_rvalue_to);
-
- RTLIL::SigSpec backup_subst_lvalue_from = subst_lvalue_from;
- RTLIL::SigSpec backup_subst_lvalue_to = subst_lvalue_to;
-
- RTLIL::SigSpec backup_subst_rvalue_from = subst_rvalue_from;
- RTLIL::SigSpec backup_subst_rvalue_to = subst_rvalue_to;
+ this_case_eq_rvalue.replace(subst_rvalue_map.stdmap());
RTLIL::CaseRule *default_case = NULL;
RTLIL::CaseRule *last_generated_case = NULL;
@@ -509,19 +467,13 @@ struct AST_INTERNAL::ProcessGenerator
{
if (child == ast->children[0])
continue;
- assert(child->type == AST_COND);
-
- subst_lvalue_from = backup_subst_lvalue_from;
- subst_lvalue_to = backup_subst_lvalue_to;
+ log_assert(child->type == AST_COND);
- subst_rvalue_from = backup_subst_rvalue_from;
- subst_rvalue_to = backup_subst_rvalue_to;
+ subst_lvalue_map.save();
+ subst_rvalue_map.save();
- subst_lvalue_from.remove2(this_case_eq_lvalue, &subst_lvalue_to);
- subst_lvalue_from.append(this_case_eq_lvalue);
- subst_lvalue_from.optimize();
- subst_lvalue_to.append(this_case_eq_ltemp);
- subst_lvalue_to.optimize();
+ for (int i = 0; i < SIZE(this_case_eq_lvalue); i++)
+ subst_lvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
RTLIL::CaseRule *backup_case = current_case;
current_case = new RTLIL::CaseRule;
@@ -533,13 +485,16 @@ struct AST_INTERNAL::ProcessGenerator
else if (node->type == AST_BLOCK)
processAst(node);
else
- current_case->compare.push_back(node->genWidthRTLIL(sw->signal.width, &subst_rvalue_from, &subst_rvalue_to));
+ current_case->compare.push_back(node->genWidthRTLIL(sw->signal.size(), &subst_rvalue_map.stdmap()));
}
if (default_case != current_case)
sw->cases.push_back(current_case);
else
log_assert(current_case->compare.size() == 0);
current_case = backup_case;
+
+ subst_lvalue_map.restore();
+ subst_rvalue_map.restore();
}
if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) {
@@ -552,20 +507,11 @@ struct AST_INTERNAL::ProcessGenerator
sw->cases.push_back(default_case);
}
- subst_lvalue_from = backup_subst_lvalue_from;
- subst_lvalue_to = backup_subst_lvalue_to;
-
- subst_rvalue_from = backup_subst_rvalue_from;
- subst_rvalue_to = backup_subst_rvalue_to;
+ for (int i = 0; i < SIZE(this_case_eq_lvalue); i++)
+ subst_rvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
- subst_rvalue_from.remove2(this_case_eq_lvalue, &subst_rvalue_to);
- subst_rvalue_from.append(this_case_eq_lvalue);
- subst_rvalue_from.optimize();
- subst_rvalue_to.append(this_case_eq_ltemp);
- subst_rvalue_to.optimize();
-
- this_case_eq_lvalue.replace(subst_lvalue_from, subst_lvalue_to);
- removeSignalFromCaseTree(this_case_eq_lvalue, current_case);
+ this_case_eq_lvalue.replace(subst_lvalue_map.stdmap());
+ removeSignalFromCaseTree(this_case_eq_lvalue.to_sigbit_set(), current_case);
addChunkActions(current_case->actions, this_case_eq_lvalue, this_case_eq_ltemp);
}
break;
@@ -579,13 +525,13 @@ struct AST_INTERNAL::ProcessGenerator
break;
default:
- assert(0);
+ log_abort();
}
}
};
// detect sign and width of an expression
-void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
+void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real)
{
std::string type_name;
bool sub_sign_hint = true;
@@ -594,6 +540,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
AstNode *range = NULL;
AstNode *id_ast = NULL;
+ bool local_found_real = false;
+ if (found_real == NULL)
+ found_real = &local_found_real;
+
switch (type)
{
case AST_CONSTANT:
@@ -602,6 +552,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
sign_hint = false;
break;
+ case AST_REALVALUE:
+ *found_real = true;
+ width_hint = std::max(width_hint, 32);
+ break;
+
case AST_IDENTIFIER:
id_ast = id2ast;
if (id_ast == NULL && current_scope.count(str))
@@ -623,10 +578,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
if (id_ast->type == AST_AUTOWIRE)
this_width = 1;
else {
- // current_ast_mod->dumpAst(stdout, "");
- // printf("---\n");
- // dumpAst(stdout, "");
- // fflush(stdout);
+ // current_ast_mod->dumpAst(NULL, "mod> ");
+ // log("---\n");
+ // id_ast->dumpAst(NULL, "decl> ");
+ // dumpAst(NULL, "ref> ");
log_error("Failed to detect with of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
}
} else {
@@ -648,8 +603,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
else if (!range->range_valid) {
AstNode *left_at_zero_ast = children[0]->children[0]->clone();
AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : left_at_zero_ast->clone();
- while (left_at_zero_ast->simplify(true, true, false, 1, -1, false)) { }
- while (right_at_zero_ast->simplify(true, true, false, 1, -1, false)) { }
+ while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
+ while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);
@@ -658,14 +613,15 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
delete right_at_zero_ast;
} else
this_width = range->range_left - range->range_right + 1;
- } else
- width_hint = std::max(width_hint, this_width);
+ sign_hint = false;
+ }
+ width_hint = std::max(width_hint, this_width);
if (!id_ast->is_signed)
sign_hint = false;
break;
case AST_TO_BITS:
- while (children[0]->simplify(true, false, false, 1, -1, false) == true) { }
+ while (children[0]->simplify(true, false, false, 1, -1, false, false) == true) { }
if (children[0]->type != AST_CONSTANT)
log_error("Left operand of tobits expression is not constant at %s:%d!\n", filename.c_str(), linenum);
children[1]->detectSignWidthWorker(sub_width_hint, sign_hint);
@@ -693,7 +649,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
break;
case AST_REPLICATE:
- while (children[0]->simplify(true, false, false, 1, -1, false) == true) { }
+ while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { }
if (children[0]->type != AST_CONSTANT)
log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);
children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
@@ -704,7 +660,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
case AST_NEG:
case AST_BIT_NOT:
case AST_POS:
- children[0]->detectSignWidthWorker(width_hint, sign_hint);
+ children[0]->detectSignWidthWorker(width_hint, sign_hint, found_real);
break;
case AST_BIT_AND:
@@ -712,7 +668,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
case AST_BIT_XOR:
case AST_BIT_XNOR:
for (auto child : children)
- child->detectSignWidthWorker(width_hint, sign_hint);
+ child->detectSignWidthWorker(width_hint, sign_hint, found_real);
break;
case AST_REDUCE_AND:
@@ -729,7 +685,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
case AST_SHIFT_SLEFT:
case AST_SHIFT_SRIGHT:
case AST_POW:
- children[0]->detectSignWidthWorker(width_hint, sign_hint);
+ children[0]->detectSignWidthWorker(width_hint, sign_hint, found_real);
break;
case AST_LT:
@@ -750,7 +706,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
case AST_DIV:
case AST_MOD:
for (auto child : children)
- child->detectSignWidthWorker(width_hint, sign_hint);
+ child->detectSignWidthWorker(width_hint, sign_hint, found_real);
break;
case AST_LOGIC_AND:
@@ -761,8 +717,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
break;
case AST_TERNARY:
- children.at(1)->detectSignWidthWorker(width_hint, sign_hint);
- children.at(2)->detectSignWidthWorker(width_hint, sign_hint);
+ children.at(1)->detectSignWidthWorker(width_hint, sign_hint, found_real);
+ children.at(2)->detectSignWidthWorker(width_hint, sign_hint, found_real);
break;
case AST_MEMRD:
@@ -781,13 +737,19 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
log_error("Don't know how to detect sign and width for %s node at %s:%d!\n",
type2str(type).c_str(), filename.c_str(), linenum);
}
+
+ if (*found_real)
+ sign_hint = true;
}
// detect sign and width of an expression
-void AstNode::detectSignWidth(int &width_hint, bool &sign_hint)
+void AstNode::detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real)
{
- width_hint = -1, sign_hint = true;
- detectSignWidthWorker(width_hint, sign_hint);
+ width_hint = -1;
+ sign_hint = true;
+ if (found_real)
+ *found_real = false;
+ detectSignWidthWorker(width_hint, sign_hint, found_real);
}
// create RTLIL from an AST node
@@ -815,6 +777,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// and are only accessed here thru this references
case AST_TASK:
case AST_FUNCTION:
+ case AST_DPI_FUNCTION:
case AST_AUTOWIRE:
case AST_LOCALPARAM:
case AST_DEFPARAM:
@@ -832,28 +795,22 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// create an RTLIL::Wire for an AST_WIRE node
case AST_WIRE: {
- if (current_module->wires.count(str) != 0)
+ if (current_module->wires_.count(str) != 0)
log_error("Re-definition of signal `%s' at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);
if (!range_valid)
log_error("Signal `%s' with non-constant width at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);
- if (range_left < range_right && (range_left != -1 || range_right != 0)) {
- int tmp = range_left;
- range_left = range_right;
- range_right = tmp;
- }
+ log_assert(range_left >= range_right || (range_left == -1 && range_right == 0));
- RTLIL::Wire *wire = new RTLIL::Wire;
+ RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1);
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
- wire->name = str;
- wire->width = range_left - range_right + 1;
wire->start_offset = range_right;
wire->port_id = port_id;
wire->port_input = is_input;
wire->port_output = is_output;
- current_module->wires[wire->name] = wire;
+ wire->upto = range_swapped;
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
@@ -870,9 +827,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
log_error("Re-definition of memory `%s' at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);
- assert(children.size() >= 2);
- assert(children[0]->type == AST_RANGE);
- assert(children[1]->type == AST_RANGE);
+ log_assert(children.size() >= 2);
+ log_assert(children[0]->type == AST_RANGE);
+ log_assert(children[1]->type == AST_RANGE);
if (!children[0]->range_valid || !children[1]->range_valid)
log_error("Memory `%s' with non-constant width or size at %s:%d!\n",
@@ -905,17 +862,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (width_hint < 0)
detectSignWidth(width_hint, sign_hint);
- RTLIL::SigChunk chunk;
- chunk.wire = NULL;
- chunk.data.bits = bits;
- chunk.width = bits.size();
- chunk.offset = 0;
-
- RTLIL::SigSpec sig;
- sig.chunks.push_back(chunk);
- sig.width = chunk.width;
-
is_signed = sign_hint;
+ return RTLIL::SigSpec(bitsAsConst());
+ }
+
+ case AST_REALVALUE:
+ {
+ RTLIL::SigSpec sig = realAsConst(width_hint);
+ log("Warning: converting real value %e to binary %s at %s:%d.\n",
+ realvalue, log_signal(sig), filename.c_str(), linenum);
return sig;
}
@@ -927,12 +882,17 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::Wire *wire = NULL;
RTLIL::SigChunk chunk;
- if (id2ast && id2ast->type == AST_AUTOWIRE && current_module->wires.count(str) == 0) {
- RTLIL::Wire *wire = new RTLIL::Wire;
+ int add_undef_bits_msb = 0;
+ int add_undef_bits_lsb = 0;
+
+ if (id2ast && id2ast->type == AST_AUTOWIRE && current_module->wires_.count(str) == 0) {
+ RTLIL::Wire *wire = current_module->addWire(str);
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
wire->name = str;
- log("Warning: Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
- current_module->wires[str] = wire;
+ if (flag_autowire)
+ log("Warning: Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ else
+ log_error("Identifier `%s' is implicitly declared at %s:%d and `default_nettype is set to none.\n", str.c_str(), filename.c_str(), linenum);
}
else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM) {
if (id2ast->children[0]->type != AST_CONSTANT)
@@ -942,7 +902,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
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)
+ id2ast->type != AST_MEMORY) || current_module->wires_.count(str) == 0)
log_error("Identifier `%s' doesn't map to any signal at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);
@@ -950,19 +910,21 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
log_error("Identifier `%s' does map to an unexpanded memory at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);
- wire = current_module->wires[str];
+ wire = current_module->wires_[str];
chunk.wire = wire;
chunk.width = wire->width;
chunk.offset = 0;
use_const_chunk:
if (children.size() != 0) {
- assert(children[0]->type == AST_RANGE);
+ log_assert(children[0]->type == AST_RANGE);
+ int source_width = id2ast->range_left - id2ast->range_right + 1;
+ int source_offset = id2ast->range_right;
if (!children[0]->range_valid) {
AstNode *left_at_zero_ast = children[0]->children[0]->clone();
AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : left_at_zero_ast->clone();
- while (left_at_zero_ast->simplify(true, true, false, 1, -1, false)) { }
- while (right_at_zero_ast->simplify(true, true, false, 1, -1, false)) { }
+ while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
+ while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);
@@ -970,27 +932,59 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
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();
- RTLIL::SigSpec sig = binop2rtlil(fake_ast, "$shr", width,
- fake_ast->children[0]->genRTLIL(), fake_ast->children[1]->genRTLIL());
+ RTLIL::SigSpec shift_val = fake_ast->children[1]->genRTLIL();
+ if (id2ast->range_right != 0) {
+ shift_val = current_module->Sub(NEW_ID, shift_val, id2ast->range_right, fake_ast->children[1]->is_signed);
+ fake_ast->children[1]->is_signed = true;
+ }
+ if (id2ast->range_swapped) {
+ shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast->children[1]->is_signed);
+ fake_ast->children[1]->is_signed = true;
+ }
+ if (SIZE(shift_val) >= 32)
+ fake_ast->children[1]->is_signed = true;
+ RTLIL::SigSpec sig = binop2rtlil(fake_ast, "$shiftx", width, fake_ast->children[0]->genRTLIL(), shift_val);
delete left_at_zero_ast;
delete right_at_zero_ast;
delete fake_ast;
return sig;
} else {
- chunk.offset = children[0]->range_right - id2ast->range_right;
chunk.width = children[0]->range_left - children[0]->range_right + 1;
- if (children[0]->range_left > id2ast->range_left || id2ast->range_right > children[0]->range_right)
- log_error("Range select out of bounds on signal `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ chunk.offset = children[0]->range_right - source_offset;
+ if (id2ast->range_swapped)
+ chunk.offset = (id2ast->range_left - id2ast->range_right + 1) - (chunk.offset + chunk.width);
+ if (chunk.offset >= source_width || chunk.offset + chunk.width < 0) {
+ if (chunk.width == 1)
+ log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting result bit to undef.\n",
+ str.c_str(), filename.c_str(), linenum);
+ else
+ log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting all %d result bits to undef.\n",
+ str.c_str(), filename.c_str(), linenum, chunk.width);
+ chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
+ } else {
+ if (chunk.width + chunk.offset > source_width) {
+ add_undef_bits_msb = (chunk.width + chunk.offset) - source_width;
+ chunk.width -= add_undef_bits_msb;
+ }
+ if (chunk.offset < 0) {
+ add_undef_bits_lsb = -chunk.offset;
+ chunk.width -= add_undef_bits_lsb;
+ chunk.offset += add_undef_bits_lsb;
+ }
+ if (add_undef_bits_lsb)
+ log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting %d LSB bits to undef.\n",
+ str.c_str(), filename.c_str(), linenum, add_undef_bits_lsb);
+ if (add_undef_bits_msb)
+ log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting %d MSB bits to undef.\n",
+ str.c_str(), filename.c_str(), linenum, add_undef_bits_msb);
+ }
}
}
- RTLIL::SigSpec sig;
- sig.chunks.push_back(chunk);
- sig.width = chunk.width;
+ RTLIL::SigSpec sig = { RTLIL::SigSpec(RTLIL::State::Sx, add_undef_bits_msb), chunk, RTLIL::SigSpec(RTLIL::State::Sx, add_undef_bits_lsb) };
- if (genRTLIL_subst_from && genRTLIL_subst_to)
- sig.replace(*genRTLIL_subst_from, *genRTLIL_subst_to);
+ if (genRTLIL_subst_ptr)
+ sig.replace(*genRTLIL_subst_ptr);
is_signed = children.size() > 0 ? false : id2ast->is_signed && sign_hint;
return sig;
@@ -1000,7 +994,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_TO_SIGNED:
case AST_TO_UNSIGNED: {
RTLIL::SigSpec sig = children[0]->genRTLIL();
- if (sig.width < width_hint)
+ if (sig.size() < width_hint)
sig.extend_u0(width_hint, sign_hint);
is_signed = sign_hint;
return sig;
@@ -1009,15 +1003,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// concatenation of signals can be done directly using RTLIL::SigSpec
case AST_CONCAT: {
RTLIL::SigSpec sig;
- sig.width = 0;
- for (auto it = children.begin(); it != children.end(); it++) {
- RTLIL::SigSpec s = (*it)->genRTLIL();
- for (size_t i = 0; i < s.chunks.size(); i++) {
- sig.chunks.push_back(s.chunks[i]);
- sig.width += s.chunks[i].width;
- }
- }
- if (sig.width < width_hint)
+ for (auto it = children.begin(); it != children.end(); it++)
+ sig.append((*it)->genRTLIL());
+ if (sig.size() < width_hint)
sig.extend_u0(width_hint, false);
return sig;
}
@@ -1032,7 +1020,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::SigSpec sig;
for (int i = 0; i < count; i++)
sig.append(right);
- if (sig.width < width_hint)
+ if (sig.size() < width_hint)
sig.extend_u0(width_hint, false);
is_signed = false;
return sig;
@@ -1045,7 +1033,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
{
RTLIL::SigSpec arg = children[0]->genRTLIL(width_hint, sign_hint);
is_signed = children[0]->is_signed;
- int width = arg.width;
+ int width = arg.size();
if (width_hint > 0) {
width = width_hint;
widthExtend(this, arg, width, is_signed);
@@ -1063,7 +1051,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
detectSignWidth(width_hint, sign_hint);
RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint);
RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint);
- int width = std::max(left.width, right.width);
+ int width = std::max(left.size(), right.size());
if (width_hint > 0)
width = width_hint;
is_signed = children[0]->is_signed && children[1]->is_signed;
@@ -1086,7 +1074,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (0) { case AST_REDUCE_BOOL: type_name = "$reduce_bool"; }
{
RTLIL::SigSpec arg = children[0]->genRTLIL();
- RTLIL::SigSpec sig = arg.width > 1 ? uniop2rtlil(this, type_name, std::max(width_hint, 1), arg) : arg;
+ RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, std::max(width_hint, 1), arg) : arg;
return sig;
}
@@ -1100,7 +1088,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
detectSignWidth(width_hint, sign_hint);
RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint);
RTLIL::SigSpec right = children[1]->genRTLIL();
- int width = width_hint > 0 ? width_hint : left.width;
+ int width = width_hint > 0 ? width_hint : left.size();
is_signed = children[0]->is_signed;
return binop2rtlil(this, type_name, width, left, right);
}
@@ -1115,10 +1103,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
detectSignWidth(width_hint, sign_hint);
RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint);
RTLIL::SigSpec right = children[1]->genRTLIL(right_width, right_signed);
- int width = width_hint > 0 ? width_hint : left.width;
+ int width = width_hint > 0 ? width_hint : left.size();
is_signed = children[0]->is_signed;
if (!flag_noopt && left.is_fully_const() && left.as_int() == 2 && !right_signed)
- return binop2rtlil(this, "$shl", width, RTLIL::SigSpec(1, left.width), right);
+ return binop2rtlil(this, "$shl", width, RTLIL::SigSpec(1, left.size()), right);
return binop2rtlil(this, "$pow", width, left, right);
}
@@ -1154,7 +1142,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint);
RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint);
#if 0
- int width = std::max(left.width, right.width);
+ int width = std::max(left.size(), right.size());
if (width > width_hint && width_hint > 0)
width = width_hint;
if (width < width_hint) {
@@ -1163,10 +1151,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (type == AST_SUB && (!children[0]->is_signed || !children[1]->is_signed))
width = width_hint;
if (type == AST_MUL)
- width = std::min(left.width + right.width, width_hint);
+ width = std::min(left.size() + right.size(), width_hint);
}
#else
- int width = std::max(std::max(left.width, right.width), width_hint);
+ int width = std::max(std::max(left.size(), right.size()), width_hint);
#endif
is_signed = children[0]->is_signed && children[1]->is_signed;
return binop2rtlil(this, type_name, width, left, right);
@@ -1198,17 +1186,17 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::SigSpec val1 = children[1]->genRTLIL(width_hint, sign_hint);
RTLIL::SigSpec val2 = children[2]->genRTLIL(width_hint, sign_hint);
- if (cond.width > 1)
+ if (cond.size() > 1)
cond = uniop2rtlil(this, "$reduce_bool", 1, cond, false);
- int width = std::max(val1.width, val2.width);
+ int width = std::max(val1.size(), val2.size());
is_signed = children[1]->is_signed && children[2]->is_signed;
widthExtend(this, val1, width, is_signed);
widthExtend(this, val2, width, is_signed);
RTLIL::SigSpec sig = mux2rtlil(this, cond, val1, val2);
- if (sig.width < width_hint)
+ if (sig.size() < width_hint)
sig.extend_u0(width_hint, sign_hint);
return sig;
}
@@ -1217,27 +1205,21 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_MEMRD:
{
std::stringstream sstr;
- sstr << "$memrd$" << str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+ sstr << "$memrd$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = new RTLIL::Cell;
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$memrd");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
- cell->name = sstr.str();
- cell->type = "$memrd";
- current_module->cells[cell->name] = cell;
- RTLIL::Wire *wire = new RTLIL::Wire;
+ RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_DATA", current_module->memories[str]->width);
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
- wire->name = cell->name + "_DATA";
- wire->width = current_module->memories[str]->width;
- current_module->wires[wire->name] = wire;
int addr_bits = 1;
while ((1 << addr_bits) < current_module->memories[str]->size)
addr_bits++;
- cell->connections["\\CLK"] = RTLIL::SigSpec(RTLIL::State::Sx, 1);
- cell->connections["\\ADDR"] = children[0]->genWidthRTLIL(addr_bits);
- cell->connections["\\DATA"] = RTLIL::SigSpec(wire);
+ cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
+ cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
+ cell->setPort("\\DATA", RTLIL::SigSpec(wire));
cell->parameters["\\MEMID"] = RTLIL::Const(str);
cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
@@ -1254,25 +1236,19 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_MEMWR:
{
std::stringstream sstr;
- sstr << "$memwr$" << str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+ sstr << "$memwr$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = new RTLIL::Cell;
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$memwr");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
- cell->name = sstr.str();
- cell->type = "$memwr";
- current_module->cells[cell->name] = cell;
int addr_bits = 1;
while ((1 << addr_bits) < current_module->memories[str]->size)
addr_bits++;
- cell->connections["\\CLK"] = RTLIL::SigSpec(RTLIL::State::Sx, 1);
- cell->connections["\\ADDR"] = children[0]->genWidthRTLIL(addr_bits);
- cell->connections["\\DATA"] = children[1]->genWidthRTLIL(current_module->memories[str]->width);
- cell->connections["\\EN"] = children[2]->genRTLIL();
-
- if (cell->connections["\\EN"].width > 1)
- cell->connections["\\EN"] = uniop2rtlil(this, "$reduce_bool", 1, cell->connections["\\EN"], false);
+ cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
+ cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
+ cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width));
+ cell->setPort("\\EN", children[2]->genRTLIL());
cell->parameters["\\MEMID"] = RTLIL::Const(str);
cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
@@ -1281,7 +1257,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
- cell->parameters["\\PRIORITY"] = RTLIL::Const(RTLIL::autoidx-1);
+ cell->parameters["\\PRIORITY"] = RTLIL::Const(autoidx-1);
}
break;
@@ -1291,19 +1267,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
log_assert(children.size() == 2);
RTLIL::SigSpec check = children[0]->genRTLIL();
- log_assert(check.width == 1);
+ log_assert(check.size() == 1);
RTLIL::SigSpec en = children[1]->genRTLIL();
- log_assert(en.width == 1);
+ log_assert(en.size() == 1);
std::stringstream sstr;
- sstr << "$assert$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+ sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = new RTLIL::Cell;
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$assert");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
- cell->name = sstr.str();
- cell->type = "$assert";
- current_module->cells[cell->name] = cell;
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
@@ -1312,8 +1285,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
cell->attributes[attr.first] = attr.second->asAttrConst();
}
- cell->connections["\\A"] = check;
- cell->connections["\\EN"] = en;
+ cell->setPort("\\A", check);
+ cell->setPort("\\EN", en);
}
break;
@@ -1322,12 +1295,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
{
if (children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_AUTOWIRE) {
RTLIL::SigSpec right = children[1]->genRTLIL();
- RTLIL::SigSpec left = children[0]->genWidthRTLIL(right.width);
- current_module->connections.push_back(RTLIL::SigSig(left, right));
+ RTLIL::SigSpec left = children[0]->genWidthRTLIL(right.size());
+ current_module->connect(RTLIL::SigSig(left, right));
} else {
RTLIL::SigSpec left = children[0]->genRTLIL();
- RTLIL::SigSpec right = children[1]->genWidthRTLIL(left.width);
- current_module->connections.push_back(RTLIL::SigSig(left, right));
+ RTLIL::SigSpec right = children[1]->genWidthRTLIL(left.size());
+ current_module->connect(RTLIL::SigSig(left, right));
}
}
break;
@@ -1336,9 +1309,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_CELL:
{
int port_counter = 0, para_counter = 0;
- RTLIL::Cell *cell = new RTLIL::Cell;
+
+ if (current_module->count_id(str) != 0)
+ log_error("Re-definition of cell `%s' at %s:%d!\n",
+ str.c_str(), filename.c_str(), linenum);
+
+ RTLIL::Cell *cell = current_module->addCell(str, "");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
- cell->name = str;
+
for (auto it = children.begin(); it != children.end(); it++) {
AstNode *child = *it;
if (child->type == AST_CELLTYPE) {
@@ -1367,13 +1345,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (child->str.size() == 0) {
char buf[100];
snprintf(buf, 100, "$%d", ++port_counter);
- cell->connections[buf] = sig;
+ cell->setPort(buf, sig);
} else {
- cell->connections[child->str] = sig;
+ cell->setPort(child->str, sig);
}
continue;
}
- assert(0);
+ log_abort();
}
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
@@ -1381,10 +1359,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
attr.first.c_str(), filename.c_str(), linenum);
cell->attributes[attr.first] = attr.second->asAttrConst();
}
- if (current_module->cells.count(cell->name) != 0)
- log_error("Re-definition of cell `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
- current_module->cells[str] = cell;
}
break;
@@ -1417,23 +1391,19 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// this is a wrapper for AstNode::genRTLIL() when a specific signal width is requested and/or
// signals must be substituted before beeing used as input values (used by ProcessGenerator)
// note that this is using some global variables to communicate this special settings to AstNode::genRTLIL().
-RTLIL::SigSpec AstNode::genWidthRTLIL(int width, RTLIL::SigSpec *subst_from, RTLIL::SigSpec *subst_to)
+RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const std::map<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr)
{
- RTLIL::SigSpec *backup_subst_from = genRTLIL_subst_from;
- RTLIL::SigSpec *backup_subst_to = genRTLIL_subst_to;
+ const std::map<RTLIL::SigBit, RTLIL::SigBit> *backup_subst_ptr = genRTLIL_subst_ptr;
- if (subst_from)
- genRTLIL_subst_from = subst_from;
- if (subst_to)
- genRTLIL_subst_to = subst_to;
+ if (new_subst_ptr)
+ genRTLIL_subst_ptr = new_subst_ptr;
bool sign_hint = true;
int width_hint = width;
detectSignWidthWorker(width_hint, sign_hint);
RTLIL::SigSpec sig = genRTLIL(width_hint, sign_hint);
- genRTLIL_subst_from = backup_subst_from;
- genRTLIL_subst_to = backup_subst_to;
+ genRTLIL_subst_ptr = backup_subst_ptr;
if (width >= 0)
sig.extend_u0(width, is_signed);
@@ -1441,3 +1411,5 @@ RTLIL::SigSpec AstNode::genWidthRTLIL(int width, RTLIL::SigSpec *subst_from, RT
return sig;
}
+YOSYS_NAMESPACE_END
+
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index b51079ce..969cc230 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -32,7 +32,9 @@
#include <sstream>
#include <stdarg.h>
-#include <assert.h>
+#include <math.h>
+
+YOSYS_NAMESPACE_BEGIN
using namespace AST;
using namespace AST_INTERNAL;
@@ -43,16 +45,23 @@ using namespace AST_INTERNAL;
//
// this function also does all name resolving and sets the id2ast member of all
// nodes that link to a different node using names and lexical scoping.
-bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint)
+bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
{
AstNode *newNode = NULL;
bool did_something = false;
+#if 0
+ log("-------------\n");
+ log("const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n",
+ int(const_fold), int(at_zero), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param));
+ dumpAst(NULL, "> ");
+#endif
+
if (stage == 0)
{
- assert(type == AST_MODULE);
+ log_assert(type == AST_MODULE);
- while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint)) { }
+ while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
if (!flag_nomem2reg && !get_bool_attribute("\\nomem2reg"))
{
@@ -66,7 +75,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
AstNode *mem = it.first;
uint32_t memflags = it.second;
- assert((memflags & ~0x00ffff00) == 0);
+ log_assert((memflags & ~0x00ffff00) == 0);
if (mem->get_bool_attribute("\\nomem2reg"))
continue;
@@ -83,6 +92,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE))
goto verbose_activate;
+ if (memflags & AstNode::MEM2REG_FL_CMPLX_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;
@@ -114,7 +126,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
reg->is_reg = true;
reg->is_signed = node->is_signed;
children.push_back(reg);
- while (reg->simplify(true, false, false, 1, -1, false)) { }
+ while (reg->simplify(true, false, false, 1, -1, false, false)) { }
}
}
@@ -128,7 +140,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
- while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint)) { }
+ while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { }
return false;
}
@@ -140,7 +152,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_FUNCTION || type == AST_TASK)
return false;
- // deactivate all calls non-synthesis system taks
+ // deactivate all calls to non-synthesis system taks
if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$stop" || str == "$finish")) {
delete_children();
str = std::string();
@@ -152,6 +164,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM))
const_fold = true;
+ // in certain cases a function must be evaluated constant. this is what in_param controls.
+ if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_PREFIX)
+ in_param = true;
+
std::map<std::string, AstNode*> backup_scope;
// create name resolution entries for all objects with names
@@ -202,12 +218,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
did_something = true;
delete node;
continue;
+ wires_are_incompatible:
+ if (stage > 1)
+ log_error("Incompatible re-declaration of wire %s at %s:%d.\n", node->str.c_str(), filename.c_str(), linenum);
+ continue;
}
this_wire_scope[node->str] = node;
}
- wires_are_incompatible:
if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR ||
- node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_CELL) {
+ node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION || node->type == AST_CELL) {
backup_scope[node->str] = current_scope[node->str];
current_scope[node->str] = node;
}
@@ -215,7 +234,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
for (size_t i = 0; i < children.size(); i++) {
AstNode *node = children[i];
if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE)
- while (node->simplify(true, false, false, 1, -1, false)) { }
+ while (node->simplify(true, false, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM))
+ did_something = true;
}
}
@@ -229,6 +249,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
bool detect_width_simple = false;
bool child_0_is_self_determined = false;
bool child_1_is_self_determined = false;
+ bool child_2_is_self_determined = false;
bool children_are_self_determined = false;
bool reset_width_after_children = false;
@@ -237,8 +258,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
case AST_ASSIGN_EQ:
case AST_ASSIGN_LE:
case AST_ASSIGN:
- while (!children[0]->basic_prep && children[0]->simplify(false, false, true, stage, -1, false) == true) { }
- while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false) == true) { }
+ while (!children[0]->basic_prep && children[0]->simplify(false, false, true, stage, -1, false, in_param) == true)
+ did_something = true;
+ while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, in_param) == true)
+ did_something = true;
children[0]->detectSignWidth(backup_width_hint, backup_sign_hint);
children[1]->detectSignWidth(width_hint, sign_hint);
width_hint = std::max(width_hint, backup_width_hint);
@@ -247,11 +270,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
case AST_PARAMETER:
case AST_LOCALPARAM:
- while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false) == true) { }
+ while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false, true) == true)
+ did_something = true;
children[0]->detectSignWidth(width_hint, sign_hint);
- if (children.size() > 1) {
- assert(children[1]->type == AST_RANGE);
- while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false) == true) { }
+ if (children.size() > 1 && children[1]->type == AST_RANGE) {
+ while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, true) == true)
+ did_something = true;
if (!children[1]->range_valid)
log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum);
width_hint = std::max(width_hint, children[1]->range_left - children[1]->range_right + 1);
@@ -307,7 +331,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
width_hint = -1;
sign_hint = true;
for (auto child : children) {
- while (!child->basic_prep && child->simplify(false, false, in_lvalue, stage, -1, false) == true) { }
+ while (!child->basic_prep && child->simplify(false, false, in_lvalue, stage, -1, false, in_param) == true)
+ did_something = true;
child->detectSignWidthWorker(width_hint, sign_hint);
}
reset_width_after_children = true;
@@ -336,13 +361,27 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
if (detect_width_simple && width_hint < 0) {
- for (auto child : children)
- while (!child->basic_prep && child->simplify(false, false, in_lvalue, stage, -1, false) == true) { }
if (type == AST_REPLICATE)
- while (children[0]->simplify(true, false, in_lvalue, stage, -1, false) == true) { }
+ while (children[0]->simplify(true, false, in_lvalue, stage, -1, false, true) == true)
+ did_something = true;
+ for (auto child : children)
+ while (!child->basic_prep && child->simplify(false, false, in_lvalue, stage, -1, false, in_param) == true)
+ did_something = true;
detectSignWidth(width_hint, sign_hint);
}
+ if (type == AST_TERNARY) {
+ int width_hint_left, width_hint_right;
+ bool sign_hint_left, sign_hint_right;
+ bool found_real_left, found_real_right;
+ children[1]->detectSignWidth(width_hint_left, sign_hint_left, &found_real_left);
+ children[2]->detectSignWidth(width_hint_right, sign_hint_right, &found_real_right);
+ if (found_real_left || found_real_right) {
+ child_1_is_self_determined = true;
+ child_2_is_self_determined = true;
+ }
+ }
+
// simplify all children first
// (iterate by index as e.g. auto wires can add new children in the process)
for (size_t i = 0; i < children.size(); i++) {
@@ -361,8 +400,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
bool const_fold_here = const_fold, in_lvalue_here = in_lvalue;
int width_hint_here = width_hint;
bool sign_hint_here = sign_hint;
- if (i == 0 && type == AST_REPLICATE)
- const_fold_here = true;
+ bool in_param_here = in_param;
+ if (i == 0 && (type == AST_REPLICATE || type == AST_WIRE))
+ const_fold_here = true, in_param_here = true;
if (type == AST_PARAMETER || type == AST_LOCALPARAM)
const_fold_here = true;
if (i == 0 && (type == AST_ASSIGN || type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE))
@@ -377,15 +417,23 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
width_hint_here = -1, sign_hint_here = false;
if (i == 1 && child_1_is_self_determined)
width_hint_here = -1, sign_hint_here = false;
+ if (i == 2 && child_2_is_self_determined)
+ width_hint_here = -1, sign_hint_here = false;
if (children_are_self_determined)
width_hint_here = -1, sign_hint_here = false;
- did_something_here = children[i]->simplify(const_fold_here, at_zero, in_lvalue_here, stage, width_hint_here, sign_hint_here);
+ did_something_here = children[i]->simplify(const_fold_here, at_zero, in_lvalue_here, stage, width_hint_here, sign_hint_here, in_param_here);
if (did_something_here)
did_something = true;
}
+ if (stage == 2 && children[i]->type == AST_INITIAL && current_ast_mod != this) {
+ current_ast_mod->children.push_back(children[i]);
+ children.erase(children.begin() + (i--));
+ did_something = true;
+ }
}
for (auto &attr : attributes) {
- while (attr.second->simplify(true, false, false, stage, -1, false)) { }
+ while (attr.second->simplify(true, false, false, stage, -1, false, true))
+ did_something = true;
}
if (reset_width_after_children) {
@@ -416,11 +464,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_DEFPARAM && !str.empty()) {
size_t pos = str.rfind('.');
if (pos == std::string::npos)
- log_error("Defparam `%s' does not contain a dot (module/parameter seperator) at %s:%d!\n",
- RTLIL::id2cstr(str.c_str()), filename.c_str(), linenum);
+ log_error("Defparam `%s' does not contain a dot (module/parameter separator) at %s:%d!\n",
+ RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
std::string modname = str.substr(0, pos), paraname = "\\" + str.substr(pos+1);
if (current_scope.count(modname) == 0 || current_scope.at(modname)->type != AST_CELL)
- log_error("Can't find cell for defparam `%s . %s` at %s:%d!\n", RTLIL::id2cstr(modname), RTLIL::id2cstr(paraname), filename.c_str(), linenum);
+ log_error("Can't find cell for defparam `%s . %s` at %s:%d!\n", RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paraname).c_str(), filename.c_str(), linenum);
AstNode *cell = current_scope.at(modname), *paraset = clone();
cell->children.insert(cell->children.begin() + 1, paraset);
paraset->type = AST_PARASET;
@@ -434,7 +482,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// dumpAst(NULL, "> ");
log_error("Index in generate block prefix syntax at %s:%d is not constant!\n", filename.c_str(), linenum);
}
- assert(children[1]->type == AST_IDENTIFIER);
+ log_assert(children[1]->type == AST_IDENTIFIER);
newNode = children[1]->clone();
const char *second_part = children[1]->str.c_str();
if (second_part[0] == '\\')
@@ -458,9 +506,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_RANGE) {
bool old_range_valid = range_valid;
range_valid = false;
+ range_swapped = false;
range_left = -1;
range_right = 0;
- assert(children.size() >= 1);
+ log_assert(children.size() >= 1);
if (children[0]->type == AST_CONSTANT) {
range_valid = true;
range_left = children[0]->integer;
@@ -479,6 +528,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int tmp = range_right;
range_right = range_left;
range_left = tmp;
+ range_swapped = true;
}
}
@@ -489,6 +539,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (!range_valid)
did_something = true;
range_valid = true;
+ range_swapped = children[0]->range_swapped;
range_left = children[0]->range_left;
range_right = children[0]->range_right;
}
@@ -496,24 +547,98 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (!range_valid)
did_something = true;
range_valid = true;
+ range_swapped = false;
range_left = 0;
range_right = 0;
}
}
+ // resolve multiranges on memory decl
+ if (type == AST_MEMORY && children.size() > 1 && children[1]->type == AST_MULTIRANGE)
+ {
+ int total_size = 1;
+ multirange_dimensions.clear();
+ for (auto range : children[1]->children) {
+ if (!range->range_valid)
+ log_error("Non-constant range on memory decl at %s:%d.\n", filename.c_str(), linenum);
+ multirange_dimensions.push_back(std::min(range->range_left, range->range_right));
+ multirange_dimensions.push_back(std::max(range->range_left, range->range_right) - std::min(range->range_left, range->range_right) + 1);
+ total_size *= multirange_dimensions.back();
+ }
+ delete children[1];
+ children[1] = new AstNode(AST_RANGE, AstNode::mkconst_int(0, true), AstNode::mkconst_int(total_size-1, true));
+ did_something = true;
+ }
+
+ // resolve multiranges on memory access
+ if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY && children.size() > 0 && children[0]->type == AST_MULTIRANGE)
+ {
+ AstNode *index_expr = nullptr;
+
+ for (int i = 0; 2*i < SIZE(id2ast->multirange_dimensions); i++)
+ {
+ if (SIZE(children[0]->children) < i)
+ log_error("Insufficient number of array indices for %s at %s:%d.\n", log_id(str), filename.c_str(), linenum);
+
+ AstNode *new_index_expr = children[0]->children[i]->children.at(0)->clone();
+
+ if (id2ast->multirange_dimensions[2*i])
+ new_index_expr = new AstNode(AST_SUB, new_index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i], true));
+
+ if (i == 0)
+ index_expr = new_index_expr;
+ else
+ index_expr = new AstNode(AST_ADD, new AstNode(AST_MUL, index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i-1], true)), new_index_expr);
+ }
+
+ for (int i = SIZE(id2ast->multirange_dimensions)/1; i < SIZE(children[0]->children); i++)
+ children.push_back(children[0]->children[i]->clone());
+
+ delete children[0];
+ if (index_expr == nullptr)
+ children.erase(children.begin());
+ else
+ children[0] = new AstNode(AST_RANGE, index_expr);
+
+ did_something = true;
+ }
+
// trim/extend parameters
- if ((type == AST_PARAMETER || type == AST_LOCALPARAM) && children[0]->type == AST_CONSTANT && children.size() > 1) {
- if (!children[1]->range_valid)
- log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum);
- int width = children[1]->range_left - children[1]->range_right + 1;
- if (width != int(children[0]->bits.size())) {
- RTLIL::SigSpec sig(children[0]->bits);
- sig.extend_u0(width, children[0]->is_signed);
- AstNode *old_child_0 = children[0];
- children[0] = mkconst_bits(sig.as_const().bits, children[0]->is_signed);
- delete old_child_0;
+ if (type == AST_PARAMETER || type == AST_LOCALPARAM) {
+ if (children.size() > 1 && children[1]->type == AST_RANGE) {
+ if (!children[1]->range_valid)
+ log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum);
+ int width = children[1]->range_left - children[1]->range_right + 1;
+ if (children[0]->type == AST_REALVALUE) {
+ RTLIL::Const constvalue = children[0]->realAsConst(width);
+ log("Warning: converting real value %e to binary %s at %s:%d.\n",
+ children[0]->realvalue, log_signal(constvalue), filename.c_str(), linenum);
+ delete children[0];
+ children[0] = mkconst_bits(constvalue.bits, sign_hint);
+ did_something = true;
+ }
+ if (children[0]->type == AST_CONSTANT) {
+ if (width != int(children[0]->bits.size())) {
+ RTLIL::SigSpec sig(children[0]->bits);
+ sig.extend_u0(width, children[0]->is_signed);
+ AstNode *old_child_0 = children[0];
+ children[0] = mkconst_bits(sig.as_const().bits, children[0]->is_signed);
+ delete old_child_0;
+ }
+ children[0]->is_signed = is_signed;
+ }
+ range_valid = true;
+ range_swapped = children[1]->range_swapped;
+ range_left = children[1]->range_left;
+ range_right = children[1]->range_right;
+ } else
+ if (children.size() > 1 && children[1]->type == AST_REALVALUE && children[0]->type == AST_CONSTANT) {
+ double as_realvalue = children[0]->asReal(sign_hint);
+ delete children[0];
+ children[0] = new AstNode(AST_REALVALUE);
+ children[0]->realvalue = as_realvalue;
+ did_something = true;
}
- children[0]->is_signed = is_signed;
}
// annotate identifiers using scope resolution and create auto-wires as needed
@@ -521,7 +646,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (current_scope.count(str) == 0) {
for (auto node : current_ast_mod->children) {
if ((node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR ||
- node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK) && str == node->str) {
+ node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION) && str == node->str) {
current_scope[node->str] = node;
break;
}
@@ -535,20 +660,23 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
current_scope[str] = auto_wire;
did_something = true;
}
- id2ast = current_scope[str];
+ if (id2ast != current_scope[str]) {
+ id2ast = current_scope[str];
+ did_something = true;
+ }
}
// split memory access with bit select to individual statements
- if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE)
+ if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue)
{
- if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1 || in_lvalue)
+ if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1)
log_error("Invalid bit-select on memory access at %s:%d!\n", filename.c_str(), linenum);
int mem_width, mem_size, addr_bits;
id2ast->meminfo(mem_width, mem_size, addr_bits);
std::stringstream sstr;
- sstr << "$mem2bits$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+ sstr << "$mem2bits$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string wire_id = sstr.str();
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
@@ -556,7 +684,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (current_block)
wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
current_ast_mod->children.push_back(wire);
- while (wire->simplify(true, false, false, 1, -1, false)) { }
+ while (wire->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *data = clone();
delete data->children[1];
@@ -587,6 +715,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
goto apply_newNode;
}
+ if (type == AST_WHILE)
+ log_error("While loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum);
+
+ if (type == AST_REPEAT)
+ log_error("Repeat loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum);
+
// unroll for loops and generate-for blocks
if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0)
{
@@ -621,7 +755,7 @@ 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, width_hint, sign_hint)) { }
+ while (varbuf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (varbuf->type != AST_CONSTANT)
log_error("Right hand side of 1st expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
@@ -643,7 +777,7 @@ 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)) { }
+ while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT)
log_error("2nd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
@@ -662,7 +796,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
buf = new AstNode(AST_GENBLOCK, body_ast->clone());
if (buf->str.empty()) {
std::stringstream sstr;
- sstr << "$genblock$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+ sstr << "$genblock$" << filename << ":" << linenum << "$" << (autoidx++);
buf->str = sstr.str();
}
std::map<std::string, std::string> name_map;
@@ -672,7 +806,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_GENFOR) {
for (size_t i = 0; i < buf->children.size(); i++) {
- buf->children[i]->simplify(false, false, false, stage, -1, false);
+ buf->children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(buf->children[i]);
}
} else {
@@ -684,7 +818,7 @@ 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, width_hint, sign_hint)) { }
+ while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT)
log_error("Right hand side of 3rd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
@@ -708,8 +842,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
std::vector<AstNode*> new_children;
for (size_t i = 0; i < children.size(); i++)
if (children[i]->type == AST_WIRE) {
- children[i]->simplify(false, false, false, stage, -1, false);
+ children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(children[i]);
+ current_scope[children[i]->str] = children[i];
} else
new_children.push_back(children[i]);
@@ -727,7 +862,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
for (size_t i = 0; i < children.size(); i++) {
- children[i]->simplify(false, false, false, stage, -1, false);
+ children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(children[i]);
}
@@ -739,7 +874,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_GENIF && children.size() != 0)
{
AstNode *buf = children[0]->clone();
- while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
+ while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
@@ -764,7 +899,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
for (size_t i = 0; i < buf->children.size(); i++) {
- buf->children[i]->simplify(false, false, false, stage, -1, false);
+ buf->children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(buf->children[i]);
}
@@ -780,7 +915,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_GENCASE && children.size() != 0)
{
AstNode *buf = children[0]->clone();
- while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
+ while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
@@ -814,14 +949,17 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
continue;
buf = child->clone();
- while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
+ while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
log_error("Expression in generate case at %s:%d is not constant!\n", filename.c_str(), linenum);
}
- if (RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool()) {
+ bool is_selected = RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool();
+ delete buf;
+
+ if (is_selected) {
selected_case = this_genblock;
i = children.size();
break;
@@ -840,7 +978,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
for (size_t i = 0; i < buf->children.size(); i++) {
- buf->children[i]->simplify(false, false, false, stage, -1, false);
+ buf->children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(buf->children[i]);
}
@@ -852,6 +990,31 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
did_something = true;
}
+ // unroll cell arrays
+ if (type == AST_CELLARRAY)
+ {
+ if (!children.at(0)->range_valid)
+ log_error("Non-constant array range on cell array at %s:%d.\n", filename.c_str(), linenum);
+
+ newNode = new AstNode(AST_GENBLOCK);
+ int num = std::max(children.at(0)->range_left, children.at(0)->range_right) - std::min(children.at(0)->range_left, children.at(0)->range_right) + 1;
+
+ for (int i = 0; i < num; i++) {
+ int idx = children.at(0)->range_left > children.at(0)->range_right ? children.at(0)->range_right + i : children.at(0)->range_right - i;
+ AstNode *new_cell = children.at(1)->clone();
+ newNode->children.push_back(new_cell);
+ new_cell->str += stringf("[%d]", idx);
+ if (new_cell->type == AST_PRIMITIVE) {
+ log_error("Cell arrays of primitives are currently not supported at %s:%d.\n", filename.c_str(), linenum);
+ } else {
+ log_assert(new_cell->children.at(0)->type == AST_CELLTYPE);
+ new_cell->children.at(0)->str = stringf("$array:%d:%d:%s", i, num, new_cell->children.at(0)->str.c_str());
+ }
+ }
+
+ goto apply_newNode;
+ }
+
// replace primitives with assignmens
if (type == AST_PRIMITIVE)
{
@@ -861,8 +1024,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
std::vector<AstNode*> children_list;
for (auto child : children) {
- assert(child->type == AST_ARGUMENT);
- assert(child->children.size() == 1);
+ log_assert(child->type == AST_ARGUMENT);
+ log_assert(child->children.size() == 1);
children_list.push_back(child->children[0]);
child->children.clear();
delete child;
@@ -917,7 +1080,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
op_type = AST_POS;
if (str == "not")
op_type = AST_POS, invert_results = true;
- assert(op_type != AST_NONE);
+ log_assert(op_type != AST_NONE);
AstNode *node = children_list[1];
if (op_type != AST_POS)
@@ -955,12 +1118,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
shift_expr = range->children[1]->clone();
AstNode *left_at_zero_ast = range->children[0]->clone();
AstNode *right_at_zero_ast = range->children[1]->clone();
- while (left_at_zero_ast->simplify(true, true, false, stage, -1, false)) { }
- while (right_at_zero_ast->simplify(true, true, false, stage, -1, false)) { }
+ while (left_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }
+ while (right_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);
- result_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
+ result_width = abs(left_at_zero_ast->integer - right_at_zero_ast->integer) + 1;
}
did_something = true;
newNode = new AstNode(AST_CASE, shift_expr);
@@ -981,14 +1144,14 @@ skip_dynamic_range_lvalue_expansion:;
if (stage > 1 && type == AST_ASSERT && current_block != NULL)
{
std::stringstream sstr;
- sstr << "$assert$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+ sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++);
std::string id_check = sstr.str() + "_CHECK", id_en = sstr.str() + "_EN";
AstNode *wire_check = new AstNode(AST_WIRE);
wire_check->str = id_check;
current_ast_mod->children.push_back(wire_check);
current_scope[wire_check->str] = wire_check;
- while (wire_check->simplify(true, false, false, 1, -1, false)) { }
+ while (wire_check->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *wire_en = new AstNode(AST_WIRE);
wire_en->str = id_en;
@@ -996,7 +1159,7 @@ skip_dynamic_range_lvalue_expansion:;
current_ast_mod->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1)))));
current_ast_mod->children.back()->children[0]->children[0]->children[0]->str = id_en;
current_scope[wire_en->str] = wire_en;
- while (wire_en->simplify(true, false, false, 1, -1, false)) { }
+ while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
std::vector<RTLIL::State> x_bit;
x_bit.push_back(RTLIL::State::Sx);
@@ -1051,16 +1214,16 @@ skip_dynamic_range_lvalue_expansion:;
// assignment with memory in left-hand side expression -> replace with memory write port
if (stage > 1 && (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) && children[0]->type == AST_IDENTIFIER &&
- children[0]->children.size() == 1 && children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY &&
- children[0]->id2ast->children.size() >= 2 && children[0]->id2ast->children[0]->range_valid &&
- children[0]->id2ast->children[1]->range_valid)
+ children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY && children[0]->id2ast->children.size() >= 2 &&
+ children[0]->id2ast->children[0]->range_valid && children[0]->id2ast->children[1]->range_valid &&
+ (children[0]->children.size() == 1 || children[0]->children.size() == 2) && children[0]->children[0]->type == AST_RANGE)
{
std::stringstream sstr;
- sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+ sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
if (type == AST_ASSIGN_EQ)
- log("Warining: Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
+ log("Warning: Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
filename.c_str(), linenum);
int mem_width, mem_size, addr_bits;
@@ -1070,31 +1233,35 @@ skip_dynamic_range_lvalue_expansion:;
wire_addr->str = id_addr;
current_ast_mod->children.push_back(wire_addr);
current_scope[wire_addr->str] = wire_addr;
- while (wire_addr->simplify(true, false, false, 1, -1, false)) { }
+ while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
wire_data->str = id_data;
current_ast_mod->children.push_back(wire_data);
current_scope[wire_data->str] = wire_data;
- while (wire_data->simplify(true, false, false, 1, -1, false)) { }
+ while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
- AstNode *wire_en = new AstNode(AST_WIRE);
+ AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
wire_en->str = id_en;
current_ast_mod->children.push_back(wire_en);
current_scope[wire_en->str] = wire_en;
- while (wire_en->simplify(true, false, false, 1, -1, false)) { }
+ while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
- std::vector<RTLIL::State> x_bits;
+ std::vector<RTLIL::State> x_bits_addr, x_bits_data, set_bits_en;
+ for (int i = 0; i < addr_bits; i++)
+ x_bits_addr.push_back(RTLIL::State::Sx);
for (int i = 0; i < mem_width; i++)
- x_bits.push_back(RTLIL::State::Sx);
+ x_bits_data.push_back(RTLIL::State::Sx);
+ for (int i = 0; i < mem_width; i++)
+ set_bits_en.push_back(RTLIL::State::S1);
- AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits, false));
+ AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false));
assign_addr->children[0]->str = id_addr;
- AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits, false));
+ AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false));
assign_data->children[0]->str = id_data;
- AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, 1));
+ AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width));
assign_en->children[0]->str = id_en;
AstNode *default_signals = new AstNode(AST_BLOCK);
@@ -1106,11 +1273,62 @@ skip_dynamic_range_lvalue_expansion:;
assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone());
assign_addr->children[0]->str = id_addr;
- assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone());
- assign_data->children[0]->str = id_data;
+ if (children[0]->children.size() == 2)
+ {
+ if (children[0]->children[1]->range_valid)
+ {
+ int offset = children[0]->children[1]->range_right;
+ int width = children[0]->children[1]->range_left - offset + 1;
- assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1));
- assign_en->children[0]->str = id_en;
+ std::vector<RTLIL::State> padding_x(offset, RTLIL::State::Sx);
+
+ for (int i = 0; i < mem_width; i++)
+ set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0;
+
+ assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
+ new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone()));
+ assign_data->children[0]->str = id_data;
+
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
+ assign_en->children[0]->str = id_en;
+ }
+ else
+ {
+ AstNode *the_range = children[0]->children[1];
+ AstNode *left_at_zero_ast = the_range->children[0]->clone();
+ AstNode *right_at_zero_ast = the_range->children.size() >= 2 ? the_range->children[1]->clone() : left_at_zero_ast->clone();
+ AstNode *offset_ast = right_at_zero_ast->clone();
+
+ while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
+ while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
+ if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
+ log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
+
+ for (int i = 0; i < mem_width; i++)
+ set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0;
+
+ assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
+ new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));
+ assign_data->children[0]->str = id_data;
+
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
+ new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone()));
+ assign_en->children[0]->str = id_en;
+
+ delete left_at_zero_ast;
+ delete right_at_zero_ast;
+ delete offset_ast;
+ }
+ }
+ else
+ {
+ assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone());
+ assign_data->children[0]->str = id_data;
+
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
+ assign_en->children[0]->str = id_en;
+ }
newNode = new AstNode(AST_BLOCK);
newNode->children.push_back(assign_addr);
@@ -1137,21 +1355,127 @@ skip_dynamic_range_lvalue_expansion:;
{
if (str == "\\$clog2")
{
+ if (children.size() != 1)
+ log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+
AstNode *buf = children[0]->clone();
- while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
+ while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT)
log_error("Failed to evaluate system function `%s' with non-constant value at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
RTLIL::Const arg_value = buf->bitsAsConst();
+ if (arg_value.as_bool())
+ arg_value = const_sub(arg_value, 1, false, false, SIZE(arg_value));
+ delete buf;
+
uint32_t result = 0;
for (size_t i = 0; i < arg_value.bits.size(); i++)
if (arg_value.bits.at(i) == RTLIL::State::S1)
- result = i;
+ result = i + 1;
newNode = mkconst_int(result, false);
goto apply_newNode;
}
+ if (str == "\\$ln" || str == "\\$log10" || str == "\\$exp" || str == "\\$sqrt" || str == "\\$pow" ||
+ str == "\\$floor" || str == "\\$ceil" || str == "\\$sin" || str == "\\$cos" || str == "\\$tan" ||
+ str == "\\$asin" || str == "\\$acos" || str == "\\$atan" || str == "\\$atan2" || str == "\\$hypot" ||
+ str == "\\$sinh" || str == "\\$cosh" || str == "\\$tanh" || str == "\\$asinh" || str == "\\$acosh" || str == "\\$atanh")
+ {
+ bool func_with_two_arguments = str == "\\$pow" || str == "\\$atan2" || str == "\\$hypot";
+ double x = 0, y = 0;
+
+ if (func_with_two_arguments) {
+ if (children.size() != 2)
+ log_error("System function %s got %d arguments, expected 2 at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ } else {
+ if (children.size() != 1)
+ log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ }
+
+ if (children.size() >= 1) {
+ while (children[0]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (!children[0]->isConst())
+ log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ int child_width_hint = width_hint;
+ bool child_sign_hint = sign_hint;
+ children[0]->detectSignWidth(child_width_hint, child_sign_hint);
+ x = children[0]->asReal(child_sign_hint);
+ }
+
+ if (children.size() >= 2) {
+ while (children[1]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (!children[1]->isConst())
+ log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ int child_width_hint = width_hint;
+ bool child_sign_hint = sign_hint;
+ children[1]->detectSignWidth(child_width_hint, child_sign_hint);
+ y = children[1]->asReal(child_sign_hint);
+ }
+
+ newNode = new AstNode(AST_REALVALUE);
+ if (str == "\\$ln") newNode->realvalue = ::log(x);
+ else if (str == "\\$log10") newNode->realvalue = ::log10(x);
+ else if (str == "\\$exp") newNode->realvalue = ::exp(x);
+ else if (str == "\\$sqrt") newNode->realvalue = ::sqrt(x);
+ else if (str == "\\$pow") newNode->realvalue = ::pow(x, y);
+ else if (str == "\\$floor") newNode->realvalue = ::floor(x);
+ else if (str == "\\$ceil") newNode->realvalue = ::ceil(x);
+ else if (str == "\\$sin") newNode->realvalue = ::sin(x);
+ else if (str == "\\$cos") newNode->realvalue = ::cos(x);
+ else if (str == "\\$tan") newNode->realvalue = ::tan(x);
+ else if (str == "\\$asin") newNode->realvalue = ::asin(x);
+ else if (str == "\\$acos") newNode->realvalue = ::acos(x);
+ else if (str == "\\$atan") newNode->realvalue = ::atan(x);
+ else if (str == "\\$atan2") newNode->realvalue = ::atan2(x, y);
+ else if (str == "\\$hypot") newNode->realvalue = ::hypot(x, y);
+ else if (str == "\\$sinh") newNode->realvalue = ::sinh(x);
+ else if (str == "\\$cosh") newNode->realvalue = ::cosh(x);
+ else if (str == "\\$tanh") newNode->realvalue = ::tanh(x);
+ else if (str == "\\$asinh") newNode->realvalue = ::asinh(x);
+ else if (str == "\\$acosh") newNode->realvalue = ::acosh(x);
+ else if (str == "\\$atanh") newNode->realvalue = ::atanh(x);
+ else log_abort();
+ goto apply_newNode;
+ }
+
+ if (current_scope.count(str) != 0 && current_scope[str]->type == AST_DPI_FUNCTION)
+ {
+ AstNode *dpi_decl = current_scope[str];
+
+ std::string rtype, fname;
+ std::vector<std::string> argtypes;
+ std::vector<AstNode*> args;
+
+ rtype = RTLIL::unescape_id(dpi_decl->children.at(0)->str);
+ fname = RTLIL::unescape_id(dpi_decl->children.at(1)->str);
+
+ for (int i = 2; i < SIZE(dpi_decl->children); i++)
+ {
+ if (i-2 >= SIZE(children))
+ log_error("Insufficient number of arguments in DPI function call at %s:%d.\n", filename.c_str(), linenum);
+
+ argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str));
+ args.push_back(children.at(i-2)->clone());
+ while (args.back()->simplify(true, false, false, stage, -1, false, true)) { }
+
+ if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE)
+ log_error("Failed to evaluate DPI function with non-constant argument at %s:%d.\n", filename.c_str(), linenum);
+ }
+
+ newNode = dpi_call(rtype, fname, argtypes, args);
+
+ for (auto arg : args)
+ delete arg;
+
+ goto apply_newNode;
+ }
+
if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION)
log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
}
@@ -1161,22 +1485,47 @@ skip_dynamic_range_lvalue_expansion:;
}
AstNode *decl = current_scope[str];
+
std::stringstream sstr;
- sstr << "$func$" << str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++) << "$";
+ sstr << "$func$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++) << "$";
std::string prefix = sstr.str();
+ bool recommend_const_eval = false;
+ bool require_const_eval = in_param ? false : has_const_only_constructs(recommend_const_eval);
+ if ((in_param || recommend_const_eval || require_const_eval) && !decl->attributes.count("\\via_celltype"))
+ {
+ bool all_args_const = true;
+ for (auto child : children) {
+ while (child->simplify(true, false, false, 1, -1, false, true)) { }
+ if (child->type != AST_CONSTANT)
+ all_args_const = false;
+ }
+
+ if (all_args_const) {
+ AstNode *func_workspace = current_scope[str]->clone();
+ newNode = func_workspace->eval_const_function(this);
+ delete func_workspace;
+ goto apply_newNode;
+ }
+
+ if (in_param)
+ log_error("Non-constant function call in constant expression at %s:%d.\n", filename.c_str(), linenum);
+ if (require_const_eval)
+ log_error("Function %s can only be called with constant arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ }
+
size_t arg_count = 0;
std::map<std::string, std::string> replace_rules;
if (current_block == NULL)
{
- assert(type == AST_FCALL);
+ log_assert(type == AST_FCALL);
AstNode *wire = NULL;
for (auto child : decl->children)
if (child->type == AST_WIRE && child->str == str)
wire = child->clone();
- assert(wire != NULL);
+ log_assert(wire != NULL);
wire->str = prefix + str;
wire->port_id = 0;
@@ -1184,7 +1533,7 @@ skip_dynamic_range_lvalue_expansion:;
wire->is_output = false;
current_ast_mod->children.push_back(wire);
- while (wire->simplify(true, false, false, 1, -1, false)) { }
+ while (wire->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *lvalue = new AstNode(AST_IDENTIFIER);
lvalue->str = wire->str;
@@ -1196,8 +1545,69 @@ skip_dynamic_range_lvalue_expansion:;
goto replace_fcall_with_id;
}
- for (auto child : decl->children)
+ if (decl->attributes.count("\\via_celltype"))
{
+ std::string celltype = decl->attributes.at("\\via_celltype")->asAttrConst().decode_string();
+ std::string outport = str;
+
+ if (celltype.find(' ') != std::string::npos) {
+ int pos = celltype.find(' ');
+ outport = RTLIL::escape_id(celltype.substr(pos+1));
+ celltype = RTLIL::escape_id(celltype.substr(0, pos));
+ } else
+ celltype = RTLIL::escape_id(celltype);
+
+ AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE));
+ cell->str = prefix.substr(0, SIZE(prefix)-1);
+ cell->children[0]->str = celltype;
+
+ for (auto attr : decl->attributes)
+ if (attr.first.str().rfind("\\via_celltype_defparam_", 0) == 0)
+ {
+ AstNode *cell_arg = new AstNode(AST_PARASET, attr.second->clone());
+ cell_arg->str = RTLIL::escape_id(attr.first.str().substr(strlen("\\via_celltype_defparam_")));
+ cell->children.push_back(cell_arg);
+ }
+
+ for (auto child : decl->children)
+ if (child->type == AST_WIRE && (child->is_input || child->is_output || (type == AST_FCALL && child->str == str)))
+ {
+ AstNode *wire = child->clone();
+ wire->str = prefix + wire->str;
+ wire->port_id = 0;
+ wire->is_input = false;
+ wire->is_output = false;
+ current_ast_mod->children.push_back(wire);
+ while (wire->simplify(true, false, false, 1, -1, false, false)) { }
+
+ AstNode *wire_id = new AstNode(AST_IDENTIFIER);
+ wire_id->str = wire->str;
+
+ if ((child->is_input || child->is_output) && arg_count < children.size())
+ {
+ AstNode *arg = children[arg_count++]->clone();
+ AstNode *assign = child->is_input ?
+ new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg) :
+ new AstNode(AST_ASSIGN_EQ, arg, wire_id->clone());
+
+ 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;
+ }
+ }
+
+ AstNode *cell_arg = new AstNode(AST_ARGUMENT, wire_id);
+ cell_arg->str = child->str == str ? outport : child->str;
+ cell->children.push_back(cell_arg);
+ }
+
+ current_ast_mod->children.push_back(cell);
+ goto replace_fcall_with_id;
+ }
+
+ for (auto child : decl->children)
if (child->type == AST_WIRE)
{
AstNode *wire = child->clone();
@@ -1206,16 +1616,18 @@ skip_dynamic_range_lvalue_expansion:;
wire->is_input = false;
wire->is_output = false;
current_ast_mod->children.push_back(wire);
- while (wire->simplify(true, false, false, 1, -1, false)) { }
+ while (wire->simplify(true, false, false, 1, -1, false, false)) { }
replace_rules[child->str] = wire->str;
- if (child->is_input && arg_count < children.size())
+ if ((child->is_input || child->is_output) && arg_count < children.size())
{
AstNode *arg = children[arg_count++]->clone();
AstNode *wire_id = new AstNode(AST_IDENTIFIER);
wire_id->str = wire->str;
- AstNode *assign = new AstNode(AST_ASSIGN_EQ, wire_id, arg);
+ 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)
@@ -1225,10 +1637,12 @@ skip_dynamic_range_lvalue_expansion:;
}
}
}
- else
+
+ for (auto child : decl->children)
+ if (child->type != AST_WIRE)
{
AstNode *stmt = child->clone();
- stmt->replace_ids(replace_rules);
+ stmt->replace_ids(prefix, replace_rules);
for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
if (*it != current_block_child)
@@ -1237,7 +1651,6 @@ skip_dynamic_range_lvalue_expansion:;
break;
}
}
- }
replace_fcall_with_id:
if (type == AST_FCALL) {
@@ -1251,7 +1664,7 @@ skip_dynamic_range_lvalue_expansion:;
}
// perform const folding when activated
- if (const_fold && newNode == NULL)
+ if (const_fold)
{
bool string_op;
std::vector<RTLIL::State> tmp_bits;
@@ -1265,13 +1678,29 @@ skip_dynamic_range_lvalue_expansion:;
if (current_scope[str]->children[0]->type == AST_CONSTANT) {
if (children.size() != 0 && children[0]->type == AST_RANGE && children[0]->range_valid) {
std::vector<RTLIL::State> data;
- for (int i = children[0]->range_right; i <= children[0]->range_left; i++)
- data.push_back(current_scope[str]->children[0]->bits[i]);
+ bool param_upto = current_scope[str]->range_valid && current_scope[str]->range_swapped;
+ int param_offset = current_scope[str]->range_valid ? current_scope[str]->range_right : 0;
+ int param_width = current_scope[str]->range_valid ? current_scope[str]->range_left - current_scope[str]->range_right + 1 :
+ SIZE(current_scope[str]->children[0]->bits);
+ int tmp_range_left = children[0]->range_left, tmp_range_right = children[0]->range_right;
+ if (param_upto) {
+ tmp_range_left = (param_width + 2*param_offset) - children[0]->range_right - 1;
+ tmp_range_right = (param_width + 2*param_offset) - children[0]->range_left - 1;
+ }
+ for (int i = tmp_range_right; i <= tmp_range_left; i++) {
+ int index = i - param_offset;
+ if (0 <= index && index < param_width)
+ data.push_back(current_scope[str]->children[0]->bits[index]);
+ else
+ data.push_back(RTLIL::State::Sx);
+ }
newNode = mkconst_bits(data, false);
} else
if (children.size() == 0)
newNode = current_scope[str]->children[0]->clone();
- }
+ } else
+ if (current_scope[str]->children[0]->isConst())
+ newNode = current_scope[str]->children[0]->clone();
}
else if (at_zero && current_scope.count(str) > 0 && (current_scope[str]->type == AST_WIRE || current_scope[str]->type == AST_AUTOWIRE)) {
newNode = mkconst_int(0, sign_hint, width_hint);
@@ -1314,6 +1743,9 @@ skip_dynamic_range_lvalue_expansion:;
if (children[0]->type == AST_CONSTANT) {
RTLIL::Const y = RTLIL::const_logic_not(RTLIL::Const(children[0]->bits), dummy_arg, children[0]->is_signed, false, -1);
newNode = mkconst_bits(y.bits, false);
+ } else
+ if (children[0]->isConst()) {
+ newNode = mkconst_int(children[0]->asReal(sign_hint) == 0, false, 1);
}
break;
if (0) { case AST_LOGIC_AND: const_func = RTLIL::const_logic_and; }
@@ -1322,6 +1754,12 @@ skip_dynamic_range_lvalue_expansion:;
RTLIL::Const y = const_func(RTLIL::Const(children[0]->bits), RTLIL::Const(children[1]->bits),
children[0]->is_signed, children[1]->is_signed, -1);
newNode = mkconst_bits(y.bits, false);
+ } else
+ if (children[0]->isConst() && children[1]->isConst()) {
+ if (type == AST_LOGIC_AND)
+ newNode = mkconst_int((children[0]->asReal(sign_hint) != 0) && (children[1]->asReal(sign_hint) != 0), false, 1);
+ else
+ newNode = mkconst_int((children[0]->asReal(sign_hint) != 0) || (children[1]->asReal(sign_hint) != 0), false, 1);
}
break;
if (0) { case AST_SHIFT_LEFT: const_func = RTLIL::const_shl; }
@@ -1333,6 +1771,10 @@ skip_dynamic_range_lvalue_expansion:;
RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint),
RTLIL::Const(children[1]->bits), sign_hint, type == AST_POW ? children[1]->is_signed : false, width_hint);
newNode = mkconst_bits(y.bits, sign_hint);
+ } else
+ if (type == AST_POW && children[0]->isConst() && children[1]->isConst()) {
+ newNode = new AstNode(AST_REALVALUE);
+ newNode->realvalue = pow(children[0]->asReal(sign_hint), children[1]->asReal(sign_hint));
}
break;
if (0) { case AST_LT: const_func = RTLIL::const_lt; }
@@ -1349,6 +1791,20 @@ skip_dynamic_range_lvalue_expansion:;
RTLIL::Const y = const_func(children[0]->bitsAsConst(cmp_width, cmp_signed),
children[1]->bitsAsConst(cmp_width, cmp_signed), cmp_signed, cmp_signed, 1);
newNode = mkconst_bits(y.bits, false);
+ } else
+ if (children[0]->isConst() && children[1]->isConst()) {
+ bool cmp_signed = (children[0]->type == AST_REALVALUE || children[0]->is_signed) && (children[1]->type == AST_REALVALUE || children[1]->is_signed);
+ switch (type) {
+ case AST_LT: newNode = mkconst_int(children[0]->asReal(cmp_signed) < children[1]->asReal(cmp_signed), false, 1); break;
+ case AST_LE: newNode = mkconst_int(children[0]->asReal(cmp_signed) <= children[1]->asReal(cmp_signed), false, 1); break;
+ case AST_EQ: newNode = mkconst_int(children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break;
+ case AST_NE: newNode = mkconst_int(children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break;
+ case AST_EQX: newNode = mkconst_int(children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break;
+ case AST_NEX: newNode = mkconst_int(children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break;
+ case AST_GE: newNode = mkconst_int(children[0]->asReal(cmp_signed) >= children[1]->asReal(cmp_signed), false, 1); break;
+ case AST_GT: newNode = mkconst_int(children[0]->asReal(cmp_signed) > children[1]->asReal(cmp_signed), false, 1); break;
+ default: log_abort();
+ }
}
break;
if (0) { case AST_ADD: const_func = RTLIL::const_add; }
@@ -1360,6 +1816,17 @@ skip_dynamic_range_lvalue_expansion:;
RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint),
children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint);
newNode = mkconst_bits(y.bits, sign_hint);
+ } else
+ if (children[0]->isConst() && children[1]->isConst()) {
+ newNode = new AstNode(AST_REALVALUE);
+ switch (type) {
+ case AST_ADD: newNode->realvalue = children[0]->asReal(sign_hint) + children[1]->asReal(sign_hint); break;
+ case AST_SUB: newNode->realvalue = children[0]->asReal(sign_hint) - children[1]->asReal(sign_hint); break;
+ case AST_MUL: newNode->realvalue = children[0]->asReal(sign_hint) * children[1]->asReal(sign_hint); break;
+ case AST_DIV: newNode->realvalue = children[0]->asReal(sign_hint) / children[1]->asReal(sign_hint); break;
+ case AST_MOD: newNode->realvalue = fmod(children[0]->asReal(sign_hint), children[1]->asReal(sign_hint)); break;
+ default: log_abort();
+ }
}
break;
if (0) { case AST_POS: const_func = RTLIL::const_pos; }
@@ -1367,37 +1834,105 @@ skip_dynamic_range_lvalue_expansion:;
if (children[0]->type == AST_CONSTANT) {
RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), dummy_arg, sign_hint, false, width_hint);
newNode = mkconst_bits(y.bits, sign_hint);
+ } else
+ if (children[0]->isConst()) {
+ newNode = new AstNode(AST_REALVALUE);
+ if (type == AST_POS)
+ newNode->realvalue = +children[0]->asReal(sign_hint);
+ else
+ newNode->realvalue = -children[0]->asReal(sign_hint);
+ }
+ break;
+ case AST_CASE:
+ if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) {
+ std::vector<AstNode*> new_children;
+ new_children.push_back(children[0]);
+ for (int i = 1; i < SIZE(children); i++) {
+ AstNode *child = children[i];
+ log_assert(child->type == AST_COND);
+ for (auto v : child->children) {
+ if (v->type == AST_DEFAULT)
+ goto keep_const_cond;
+ if (v->type == AST_BLOCK)
+ continue;
+ if (v->type == AST_CONSTANT && v->bits_only_01()) {
+ if (v->bits == children[0]->bits) {
+ while (i+1 < SIZE(children))
+ delete children[++i];
+ goto keep_const_cond;
+ }
+ continue;
+ }
+ goto keep_const_cond;
+ }
+ if (0)
+ keep_const_cond:
+ new_children.push_back(child);
+ else
+ delete child;
+ }
+ new_children.swap(children);
}
break;
case AST_TERNARY:
- if (children[0]->type == AST_CONSTANT) {
+ if (children[0]->isConst())
+ {
bool found_sure_true = false;
bool found_maybe_true = false;
- for (auto &bit : children[0]->bits) {
- if (bit == RTLIL::State::S1)
- found_sure_true = true;
- if (bit > RTLIL::State::S1)
- found_maybe_true = true;
- }
- AstNode *choice = NULL;
+
+ if (children[0]->type == AST_CONSTANT)
+ for (auto &bit : children[0]->bits) {
+ if (bit == RTLIL::State::S1)
+ found_sure_true = true;
+ if (bit > RTLIL::State::S1)
+ found_maybe_true = true;
+ }
+ else
+ found_sure_true = children[0]->asReal(sign_hint) != 0;
+
+ AstNode *choice = NULL, *not_choice = NULL;
if (found_sure_true)
- choice = children[1];
+ choice = children[1], not_choice = children[2];
else if (!found_maybe_true)
- choice = children[2];
- if (choice != NULL && choice->type == AST_CONSTANT) {
- RTLIL::Const y = choice->bitsAsConst(width_hint, sign_hint);
- if (choice->is_string && y.bits.size() % 8 == 0 && sign_hint == false)
- newNode = mkconst_str(y.bits);
- else
- newNode = mkconst_bits(y.bits, sign_hint);
+ choice = children[2], not_choice = children[1];
+
+ if (choice != NULL) {
+ if (choice->type == AST_CONSTANT) {
+ int other_width_hint = width_hint;
+ bool other_sign_hint = sign_hint, other_real = false;
+ not_choice->detectSignWidth(other_width_hint, other_sign_hint, &other_real);
+ if (other_real) {
+ newNode = new AstNode(AST_REALVALUE);
+ choice->detectSignWidth(width_hint, sign_hint);
+ newNode->realvalue = choice->asReal(sign_hint);
+ } else {
+ RTLIL::Const y = choice->bitsAsConst(width_hint, sign_hint);
+ if (choice->is_string && y.bits.size() % 8 == 0 && sign_hint == false)
+ newNode = mkconst_str(y.bits);
+ else
+ newNode = mkconst_bits(y.bits, sign_hint);
+ }
+ } else
+ if (choice->isConst()) {
+ newNode = choice->clone();
+ }
} else if (children[1]->type == AST_CONSTANT && children[2]->type == AST_CONSTANT) {
RTLIL::Const a = children[1]->bitsAsConst(width_hint, sign_hint);
RTLIL::Const b = children[2]->bitsAsConst(width_hint, sign_hint);
- assert(a.bits.size() == b.bits.size());
+ log_assert(a.bits.size() == b.bits.size());
for (size_t i = 0; i < a.bits.size(); i++)
if (a.bits[i] != b.bits[i])
a.bits[i] = RTLIL::State::Sx;
newNode = mkconst_bits(a.bits, sign_hint);
+ } else if (children[1]->isConst() && children[2]->isConst()) {
+ newNode = new AstNode(AST_REALVALUE);
+ if (children[1]->asReal(sign_hint) == children[2]->asReal(sign_hint))
+ newNode->realvalue = children[1]->asReal(sign_hint);
+ else
+ // IEEE Std 1800-2012 Sec. 11.4.11 states that the entry in Table 7-1 for
+ // the data type in question should be returned if the ?: is ambiguous. The
+ // value in Table 7-1 for the 'real' type is 0.0.
+ newNode->realvalue = 0.0;
}
}
break;
@@ -1431,7 +1966,7 @@ apply_newNode:
// fprintf(stderr, "----\n");
// dumpAst(stderr, "- ");
// newNode->dumpAst(stderr, "+ ");
- assert(newNode != NULL);
+ log_assert(newNode != NULL);
newNode->filename = filename;
newNode->linenum = linenum;
newNode->cloneInto(this);
@@ -1501,12 +2036,45 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
}
// rename stuff (used when tasks of functions are instanciated)
-void AstNode::replace_ids(std::map<std::string, std::string> &rules)
+void AstNode::replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules)
{
- if (type == AST_IDENTIFIER && rules.count(str) > 0)
- str = rules[str];
- for (auto child : children)
- child->replace_ids(rules);
+ if (type == AST_BLOCK)
+ {
+ std::map<std::string, std::string> new_rules = rules;
+ std::string new_prefix = prefix + str;
+
+ for (auto child : children)
+ if (child->type == AST_WIRE) {
+ new_rules[child->str] = new_prefix + child->str;
+ child->str = new_prefix + child->str;
+ }
+
+ for (auto child : children)
+ if (child->type != AST_WIRE)
+ child->replace_ids(new_prefix, new_rules);
+ }
+ else
+ {
+ if (type == AST_IDENTIFIER && rules.count(str) > 0)
+ str = rules.at(str);
+ for (auto child : children)
+ child->replace_ids(prefix, rules);
+ }
+}
+
+// helper function for mem2reg_as_needed_pass1
+static void mark_memories_assign_lhs_complex(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
+ std::map<AstNode*, uint32_t> &mem2reg_candidates, AstNode *that)
+{
+ for (auto &child : that->children)
+ mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, child);
+
+ if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) {
+ AstNode *mem = that->id2ast;
+ if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_CMPLX_LHS))
+ mem2reg_places[mem].insert(stringf("%s:%d", that->filename.c_str(), that->linenum));
+ mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CMPLX_LHS;
+ }
}
// find memories that should be replaced by registers
@@ -1518,6 +2086,10 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)
{
+ // mark all memories that are used in a complex expression on the left side of an assignment
+ for (auto &lhs_child : children[0]->children)
+ mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, lhs_child);
+
if (children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY)
{
AstNode *mem = children[0]->id2ast;
@@ -1588,7 +2160,7 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
uint32_t backup_flags = flags;
flags |= children_flags;
- assert((flags & ~0x000000ff) == 0);
+ log_assert((flags & ~0x000000ff) == 0);
for (auto child : children)
if (ignore_children_counter > 0)
@@ -1617,7 +2189,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
mem2reg_set.count(children[0]->id2ast) > 0 && children[0]->children[0]->children[0]->type != AST_CONSTANT)
{
std::stringstream sstr;
- sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+ sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA";
int mem_width, mem_size, addr_bits;
@@ -1628,20 +2200,20 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
wire_addr->is_reg = true;
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
mod->children.push_back(wire_addr);
- while (wire_addr->simplify(true, false, false, 1, -1, false)) { }
+ while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
wire_data->str = id_data;
wire_data->is_reg = true;
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
mod->children.push_back(wire_data);
- while (wire_data->simplify(true, false, false, 1, -1, false)) { }
+ while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
- assert(block != NULL);
+ log_assert(block != NULL);
size_t assign_idx = 0;
while (assign_idx < block->children.size() && block->children[assign_idx] != this)
assign_idx++;
- assert(assign_idx < block->children.size());
+ log_assert(assign_idx < block->children.size());
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;
@@ -1654,6 +2226,8 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
continue;
AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK));
AstNode *assign_reg = new AstNode(type, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER));
+ if (children[0]->children.size() == 2)
+ assign_reg->children[0]->children.push_back(children[0]->children[1]->clone());
assign_reg->children[0]->str = stringf("%s[%d]", children[0]->str.c_str(), i);
assign_reg->children[1]->str = id_data;
cond_node->children[1]->children.push_back(assign_reg);
@@ -1670,6 +2244,10 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
if (type == AST_IDENTIFIER && id2ast && mem2reg_set.count(id2ast) > 0)
{
+ AstNode *bit_part_sel = NULL;
+ if (children.size() == 2)
+ bit_part_sel = children[1]->clone();
+
if (children[0]->children[0]->type == AST_CONSTANT)
{
int id = children[0]->children[0]->integer;
@@ -1682,7 +2260,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
else
{
std::stringstream sstr;
- sstr << "$mem2reg_rd$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+ sstr << "$mem2reg_rd$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA";
int mem_width, mem_size, addr_bits;
@@ -1694,7 +2272,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
if (block)
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
mod->children.push_back(wire_addr);
- while (wire_addr->simplify(true, false, false, 1, -1, false)) { }
+ while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
wire_data->str = id_data;
@@ -1702,7 +2280,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
if (block)
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
mod->children.push_back(wire_data);
- while (wire_data->simplify(true, false, false, 1, -1, false)) { }
+ while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone());
assign_addr->children[0]->str = id_addr;
@@ -1736,7 +2314,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
size_t assign_idx = 0;
while (assign_idx < block->children.size() && !block->children[assign_idx]->contains(this))
assign_idx++;
- assert(assign_idx < block->children.size());
+ log_assert(assign_idx < block->children.size());
block->children.insert(block->children.begin()+assign_idx, case_node);
block->children.insert(block->children.begin()+assign_idx, assign_addr);
}
@@ -1753,9 +2331,12 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
id2ast = NULL;
str = id_data;
}
+
+ if (bit_part_sel)
+ children.push_back(bit_part_sel);
}
- assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0);
+ log_assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0);
auto children_list = children;
for (size_t i = 0; i < children_list.size(); i++)
@@ -1765,7 +2346,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
// calulate memory dimensions
void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits)
{
- assert(type == AST_MEMORY);
+ log_assert(type == AST_MEMORY);
mem_width = children[0]->range_left - children[0]->range_right + 1;
mem_size = children[1]->range_left - children[1]->range_right;
@@ -1779,3 +2360,267 @@ void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits)
addr_bits++;
}
+bool AstNode::has_const_only_constructs(bool &recommend_const_eval)
+{
+ if (type == AST_FOR)
+ recommend_const_eval = true;
+ if (type == AST_WHILE || type == AST_REPEAT)
+ return true;
+ if (type == AST_FCALL && current_scope.count(str))
+ if (current_scope[str]->has_const_only_constructs(recommend_const_eval))
+ return true;
+ for (auto child : children)
+ if (child->AstNode::has_const_only_constructs(recommend_const_eval))
+ return true;
+ return false;
+}
+
+// helper function for AstNode::eval_const_function()
+void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall)
+{
+ if (type == AST_IDENTIFIER && variables.count(str)) {
+ int offset = variables.at(str).offset, width = variables.at(str).val.bits.size();
+ if (!children.empty()) {
+ if (children.size() != 1 || children.at(0)->type != AST_RANGE)
+ log_error("Memory access in constant function is not supported in %s:%d (called from %s:%d).\n",
+ filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum);
+ children.at(0)->replace_variables(variables, fcall);
+ while (simplify(true, false, false, 1, -1, false, true)) { }
+ if (!children.at(0)->range_valid)
+ log_error("Non-constant range in %s:%d (called from %s:%d).\n",
+ filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum);
+ offset = std::min(children.at(0)->range_left, children.at(0)->range_right);
+ width = std::min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
+ }
+ offset -= variables.at(str).offset;
+ std::vector<RTLIL::State> &var_bits = variables.at(str).val.bits;
+ std::vector<RTLIL::State> new_bits(var_bits.begin() + offset, var_bits.begin() + offset + width);
+ AstNode *newNode = mkconst_bits(new_bits, variables.at(str).is_signed);
+ newNode->cloneInto(this);
+ delete newNode;
+ return;
+ }
+
+ for (auto &child : children)
+ child->replace_variables(variables, fcall);
+}
+
+// evaluate functions with all-const arguments
+AstNode *AstNode::eval_const_function(AstNode *fcall)
+{
+ std::map<std::string, AstNode*> backup_scope;
+ std::map<std::string, AstNode::varinfo_t> variables;
+ bool delete_temp_block = false;
+ AstNode *block = NULL;
+
+ size_t argidx = 0;
+ for (auto child : children)
+ {
+ if (child->type == AST_BLOCK)
+ {
+ log_assert(block == NULL);
+ block = child;
+ continue;
+ }
+
+ if (child->type == AST_WIRE)
+ {
+ while (child->simplify(true, false, false, 1, -1, false, true)) { }
+ if (!child->range_valid)
+ log_error("Can't determine size of variable %s in %s:%d (called from %s:%d).\n",
+ child->str.c_str(), child->filename.c_str(), child->linenum, fcall->filename.c_str(), fcall->linenum);
+ variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1);
+ variables[child->str].offset = std::min(child->range_left, child->range_right);
+ variables[child->str].is_signed = child->is_signed;
+ if (child->is_input && argidx < fcall->children.size())
+ variables[child->str].val = fcall->children.at(argidx++)->bitsAsConst(variables[child->str].val.bits.size());
+ backup_scope[child->str] = current_scope[child->str];
+ current_scope[child->str] = child;
+ continue;
+ }
+
+ log_assert(block == NULL);
+ delete_temp_block = true;
+ block = new AstNode(AST_BLOCK);
+ block->children.push_back(child->clone());
+ }
+
+ log_assert(block != NULL);
+ log_assert(variables.count(str));
+
+ while (!block->children.empty())
+ {
+ AstNode *stmt = block->children.front();
+
+#if 0
+ log("-----------------------------------\n");
+ for (auto &it : variables)
+ log("%20s %40s\n", it.first.c_str(), log_signal(it.second.val));
+ stmt->dumpAst(NULL, "stmt> ");
+#endif
+
+ if (stmt->type == AST_ASSIGN_EQ)
+ {
+ stmt->children.at(1)->replace_variables(variables, fcall);
+ while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
+
+ if (stmt->type != AST_ASSIGN_EQ)
+ continue;
+
+ if (stmt->children.at(1)->type != AST_CONSTANT)
+ log_error("Non-constant expression in constant function at %s:%d (called from %s:%d). X\n",
+ stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+
+ if (stmt->children.at(0)->type != AST_IDENTIFIER)
+ log_error("Unsupported composite left hand side in constant function at %s:%d (called from %s:%d).\n",
+ stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+
+ if (!variables.count(stmt->children.at(0)->str))
+ log_error("Assignment to non-local variable in constant function at %s:%d (called from %s:%d).\n",
+ stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+
+ if (stmt->children.at(0)->children.empty()) {
+ variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size());
+ } else {
+ AstNode *range = stmt->children.at(0)->children.at(0);
+ if (!range->range_valid)
+ log_error("Non-constant range in %s:%d (called from %s:%d).\n",
+ range->filename.c_str(), range->linenum, fcall->filename.c_str(), fcall->linenum);
+ int offset = std::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];
+ RTLIL::Const r = stmt->children.at(1)->bitsAsConst(v.val.bits.size());
+ for (int i = 0; i < width; i++)
+ v.val.bits.at(i+offset-v.offset) = r.bits.at(i);
+ }
+
+ delete block->children.front();
+ block->children.erase(block->children.begin());
+ continue;
+ }
+
+ if (stmt->type == AST_FOR)
+ {
+ block->children.insert(block->children.begin(), stmt->children.at(0));
+ stmt->children.at(3)->children.push_back(stmt->children.at(2));
+ stmt->children.erase(stmt->children.begin() + 2);
+ stmt->children.erase(stmt->children.begin());
+ stmt->type = AST_WHILE;
+ continue;
+ }
+
+ if (stmt->type == AST_WHILE)
+ {
+ AstNode *cond = stmt->children.at(0)->clone();
+ cond->replace_variables(variables, fcall);
+ while (cond->simplify(true, false, false, 1, -1, false, true)) { }
+
+ if (cond->type != AST_CONSTANT)
+ log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n",
+ stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+
+ if (cond->asBool()) {
+ block->children.insert(block->children.begin(), stmt->children.at(1)->clone());
+ } else {
+ delete block->children.front();
+ block->children.erase(block->children.begin());
+ }
+
+ delete cond;
+ continue;
+ }
+
+ if (stmt->type == AST_REPEAT)
+ {
+ AstNode *num = stmt->children.at(0)->clone();
+ num->replace_variables(variables, fcall);
+ while (num->simplify(true, false, false, 1, -1, false, true)) { }
+
+ if (num->type != AST_CONSTANT)
+ log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n",
+ stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+
+ block->children.erase(block->children.begin());
+ for (int i = 0; i < num->bitsAsConst().as_int(); i++)
+ block->children.insert(block->children.begin(), stmt->children.at(1)->clone());
+
+ delete stmt;
+ delete num;
+ continue;
+ }
+
+ if (stmt->type == AST_CASE)
+ {
+ AstNode *expr = stmt->children.at(0)->clone();
+ expr->replace_variables(variables, fcall);
+ while (expr->simplify(true, false, false, 1, -1, false, true)) { }
+
+ AstNode *sel_case = NULL;
+ for (size_t i = 1; i < stmt->children.size(); i++)
+ {
+ bool found_match = false;
+ log_assert(stmt->children.at(i)->type == AST_COND);
+
+ if (stmt->children.at(i)->children.front()->type == AST_DEFAULT) {
+ sel_case = stmt->children.at(i)->children.back();
+ continue;
+ }
+
+ for (size_t j = 0; j+1 < stmt->children.at(i)->children.size() && !found_match; j++)
+ {
+ AstNode *cond = stmt->children.at(i)->children.at(j)->clone();
+ cond->replace_variables(variables, fcall);
+
+ cond = new AstNode(AST_EQ, expr->clone(), cond);
+ while (cond->simplify(true, false, false, 1, -1, false, true)) { }
+
+ if (cond->type != AST_CONSTANT)
+ log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n",
+ stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+
+ found_match = cond->asBool();
+ delete cond;
+ }
+
+ if (found_match) {
+ sel_case = stmt->children.at(i)->children.back();
+ break;
+ }
+ }
+
+ block->children.erase(block->children.begin());
+ if (sel_case)
+ block->children.insert(block->children.begin(), sel_case->clone());
+ delete stmt;
+ delete expr;
+ continue;
+ }
+
+ if (stmt->type == AST_BLOCK)
+ {
+ block->children.erase(block->children.begin());
+ block->children.insert(block->children.begin(), stmt->children.begin(), stmt->children.end());
+ stmt->children.clear();
+ delete stmt;
+ continue;
+ }
+
+ log_error("Unsupported language construct in constant function at %s:%d (called from %s:%d).\n",
+ stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_abort();
+ }
+
+ if (delete_temp_block)
+ delete block;
+
+ for (auto &it : backup_scope)
+ if (it.second == NULL)
+ current_scope.erase(it.first);
+ else
+ current_scope[it.first] = it.second;
+
+ return AstNode::mkconst_bits(variables.at(str).val.bits, variables.at(str).is_signed);
+}
+
+YOSYS_NAMESPACE_END
+
diff --git a/frontends/ilang/Makefile.inc b/frontends/ilang/Makefile.inc
index 07ebf085..e832cfed 100644
--- a/frontends/ilang/Makefile.inc
+++ b/frontends/ilang/Makefile.inc
@@ -4,12 +4,14 @@ GENFILES += frontends/ilang/parser.tab.h
GENFILES += frontends/ilang/parser.output
GENFILES += frontends/ilang/lexer.cc
-frontends/ilang/parser.tab.cc frontends/ilang/parser.tab.h: frontends/ilang/parser.y
- bison -d -r all -b frontends/ilang/parser frontends/ilang/parser.y
- mv frontends/ilang/parser.tab.c frontends/ilang/parser.tab.cc
+frontends/ilang/parser.tab.cc: frontends/ilang/parser.y
+ $(P) bison -d -r all -b frontends/ilang/parser frontends/ilang/parser.y
+ $(Q) mv frontends/ilang/parser.tab.c frontends/ilang/parser.tab.cc
+
+frontends/ilang/parser.tab.h: frontends/ilang/parser.tab.cc
frontends/ilang/lexer.cc: frontends/ilang/lexer.l
- flex -o frontends/ilang/lexer.cc frontends/ilang/lexer.l
+ $(P) flex -o frontends/ilang/lexer.cc frontends/ilang/lexer.l
OBJS += frontends/ilang/parser.tab.o frontends/ilang/lexer.o
OBJS += frontends/ilang/ilang_frontend.o
diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc
index 572a3572..f6f926db 100644
--- a/frontends/ilang/ilang_frontend.cc
+++ b/frontends/ilang/ilang_frontend.cc
@@ -26,6 +26,8 @@
#include "kernel/register.h"
#include "kernel/log.h"
+YOSYS_NAMESPACE_BEGIN
+
void rtlil_frontend_ilang_yyerror(char const *s)
{
log_error("Parser error in line %d: %s\n", rtlil_frontend_ilang_yyget_lineno(), s);
@@ -43,17 +45,20 @@ struct IlangFrontend : public Frontend {
log("representation of a design in yosys's internal format.)\n");
log("\n");
}
- virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing ILANG frontend.\n");
extra_args(f, filename, args, 1);
log("Input filename: %s\n", filename.c_str());
+ ILANG_FRONTEND::lexin = f;
ILANG_FRONTEND::current_design = design;
rtlil_frontend_ilang_yydebug = false;
- rtlil_frontend_ilang_yyrestart(f);
+ rtlil_frontend_ilang_yyrestart(NULL);
rtlil_frontend_ilang_yyparse();
rtlil_frontend_ilang_yylex_destroy();
}
} IlangFrontend;
+YOSYS_NAMESPACE_END
+
diff --git a/frontends/ilang/ilang_frontend.h b/frontends/ilang/ilang_frontend.h
index 5e768c3b..b04d6c51 100644
--- a/frontends/ilang/ilang_frontend.h
+++ b/frontends/ilang/ilang_frontend.h
@@ -25,20 +25,23 @@
#ifndef ILANG_FRONTEND_H
#define ILANG_FRONTEND_H
-#include "kernel/rtlil.h"
-#include <stdio.h>
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
namespace ILANG_FRONTEND {
- void ilang_frontend(FILE *f, RTLIL::Design *design);
+ extern std::istream *lexin;
extern RTLIL::Design *current_design;
}
+YOSYS_NAMESPACE_END
+
extern int rtlil_frontend_ilang_yydebug;
int rtlil_frontend_ilang_yylex(void);
void rtlil_frontend_ilang_yyerror(char const *s);
void rtlil_frontend_ilang_yyrestart(FILE *f);
int rtlil_frontend_ilang_yyparse(void);
-void rtlil_frontend_ilang_yylex_destroy(void);
+int rtlil_frontend_ilang_yylex_destroy(void);
int rtlil_frontend_ilang_yyget_lineno(void);
#endif
diff --git a/frontends/ilang/lexer.l b/frontends/ilang/lexer.l
index 5da8ce67..4109cd4b 100644
--- a/frontends/ilang/lexer.l
+++ b/frontends/ilang/lexer.l
@@ -23,9 +23,18 @@
*/
%{
-#include "kernel/rtlil.h"
+
+#ifdef __clang__
+// bison generates code using the 'register' storage class specifier
+#pragma clang diagnostic ignored "-Wdeprecated-register"
+#endif
+
+#include "ilang_frontend.h"
#include "parser.tab.h"
-void update_autoidx(const char *p);
+
+#define YY_INPUT(buf,result,max_size) \
+ result = ILANG_FRONTEND::lexin->readsome(buf, max_size);
+
%}
%option yylineno
@@ -37,6 +46,7 @@ void update_autoidx(const char *p);
%%
+"autoidx" { return TOK_AUTOIDX; }
"module" { return TOK_MODULE; }
"attribute" { return TOK_ATTRIBUTE; }
"parameter" { return TOK_PARAMETER; }
@@ -44,6 +54,7 @@ void update_autoidx(const char *p);
"wire" { return TOK_WIRE; }
"memory" { return TOK_MEMORY; }
"width" { return TOK_WIDTH; }
+"upto" { return TOK_UPTO; }
"offset" { return TOK_OFFSET; }
"size" { return TOK_SIZE; }
"input" { return TOK_INPUT; }
@@ -69,11 +80,11 @@ void update_autoidx(const char *p);
[a-z]+ { return TOK_INVALID; }
"\\"[^ \t\r\n]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; }
-"$"[^ \t\r\n]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); update_autoidx(yytext); return TOK_ID; }
+"$"[^ \t\r\n]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; }
"."[0-9]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; }
[0-9]+'[01xzm-]* { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_VALUE; }
-[0-9]+ { rtlil_frontend_ilang_yylval.integer = atoi(yytext); return TOK_INT; }
+-?[0-9]+ { rtlil_frontend_ilang_yylval.integer = atoi(yytext); return TOK_INT; }
\" { BEGIN(STRING); }
<STRING>\\. { yymore(); }
@@ -117,27 +128,6 @@ void update_autoidx(const char *p);
%%
-void update_autoidx(const char *p)
-{
- if (*p != '$')
- return;
-
- while (*p) {
- if (*(p++) != '$')
- continue;
- if ('0' <= *p && *p <= '9') {
- const char *q = p;
- while ('0' <= *q && *q <= '9')
- q++;
- if ((q - p) < 10) {
- int idx = atoi(p);
- if (idx > RTLIL::autoidx)
- RTLIL::autoidx = idx;
- }
- }
- }
-}
-
// this is a hack to avoid the 'yyinput defined but not used' error msgs
void *rtlil_frontend_ilang_avoid_input_warnings() {
return (void*)&yyinput;
diff --git a/frontends/ilang/parser.y b/frontends/ilang/parser.y
index c2e09022..a5cc0689 100644
--- a/frontends/ilang/parser.y
+++ b/frontends/ilang/parser.y
@@ -25,7 +25,9 @@
%{
#include <list>
#include "ilang_frontend.h"
+YOSYS_NAMESPACE_BEGIN
namespace ILANG_FRONTEND {
+ std::istream *lexin;
RTLIL::Design *current_design;
RTLIL::Module *current_module;
RTLIL::Wire *current_wire;
@@ -37,24 +39,26 @@ namespace ILANG_FRONTEND {
std::map<RTLIL::IdString, RTLIL::Const> attrbuf;
}
using namespace ILANG_FRONTEND;
+YOSYS_NAMESPACE_END
+USING_YOSYS_NAMESPACE
%}
-%name-prefix="rtlil_frontend_ilang_yy"
+%name-prefix "rtlil_frontend_ilang_yy"
%union {
char *string;
int integer;
- RTLIL::Const *data;
- RTLIL::SigSpec *sigspec;
+ YOSYS_NAMESPACE_PREFIX RTLIL::Const *data;
+ YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec;
}
%token <string> TOK_ID TOK_VALUE TOK_STRING
%token <integer> TOK_INT
-%token TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT
+%token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT
%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_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
+%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO
%type <sigspec> sigspec sigspec_list
%type <integer> sync_type
@@ -82,21 +86,23 @@ optional_eol:
design:
design module |
design attr_stmt |
+ design autoidx_stmt |
/* empty */;
module:
TOK_MODULE TOK_ID EOL {
- if (current_design->modules.count($2) != 0)
- rtlil_frontend_ilang_yyerror(stringf("scope error: redefinition of module %s.", $2).c_str());
+ if (current_design->has($2))
+ rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str());
current_module = new RTLIL::Module;
current_module->name = $2;
current_module->attributes = attrbuf;
- current_design->modules[$2] = 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();
} EOL;
module_body:
@@ -113,16 +119,20 @@ attr_stmt:
free($2);
};
+autoidx_stmt:
+ TOK_AUTOIDX TOK_INT EOL {
+ autoidx = std::max(autoidx, $2);
+ };
+
wire_stmt:
TOK_WIRE {
- current_wire = new RTLIL::Wire;
+ current_wire = current_module->addWire("$__ilang_frontend_tmp__");
current_wire->attributes = attrbuf;
attrbuf.clear();
} wire_options TOK_ID EOL {
- if (current_module->wires.count($4) != 0)
- rtlil_frontend_ilang_yyerror(stringf("scope error: redefinition of wire %s.", $4).c_str());
- current_wire->name = $4;
- current_module->wires[$4] = current_wire;
+ if (current_module->wires_.count($4) != 0)
+ rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of wire %s.", $4).c_str());
+ current_module->rename(current_wire, $4);
free($4);
};
@@ -130,6 +140,9 @@ wire_options:
wire_options TOK_WIDTH TOK_INT {
current_wire->width = $3;
} |
+ wire_options TOK_UPTO {
+ current_wire->upto = true;
+ } |
wire_options TOK_OFFSET TOK_INT {
current_wire->start_offset = $3;
} |
@@ -157,7 +170,7 @@ memory_stmt:
attrbuf.clear();
} memory_options TOK_ID EOL {
if (current_module->memories.count($4) != 0)
- rtlil_frontend_ilang_yyerror(stringf("scope error: redefinition of memory %s.", $4).c_str());
+ rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of memory %s.", $4).c_str());
current_memory->name = $4;
current_module->memories[$4] = current_memory;
free($4);
@@ -174,13 +187,10 @@ memory_options:
cell_stmt:
TOK_CELL TOK_ID TOK_ID EOL {
- if (current_module->cells.count($3) != 0)
- rtlil_frontend_ilang_yyerror(stringf("scope error: redefinition of cell %s.", $3).c_str());
- current_cell = new RTLIL::Cell;
- current_cell->type = $2;
- current_cell->name = $3;
+ if (current_module->cells_.count($3) != 0)
+ rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell %s.", $3).c_str());
+ current_cell = current_module->addCell($3, $2);
current_cell->attributes = attrbuf;
- current_module->cells[$3] = current_cell;
attrbuf.clear();
free($2);
free($3);
@@ -199,9 +209,9 @@ cell_body:
delete $5;
} |
cell_body TOK_CONNECT TOK_ID sigspec EOL {
- if (current_cell->connections.count($3) != 0)
- rtlil_frontend_ilang_yyerror(stringf("scope error: redefinition of cell port %s.", $3).c_str());
- current_cell->connections[$3] = *$4;
+ if (current_cell->hasPort($3))
+ rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
+ current_cell->setPort($3, *$4);
delete $4;
free($3);
} |
@@ -210,7 +220,7 @@ cell_body:
proc_stmt:
TOK_PROCESS TOK_ID EOL {
if (current_module->processes.count($2) != 0)
- rtlil_frontend_ilang_yyerror(stringf("scope error: redefinition of process %s.", $2).c_str());
+ rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of process %s.", $2).c_str());
current_process = new RTLIL::Process;
current_process->name = $2;
current_process->attributes = attrbuf;
@@ -219,6 +229,7 @@ proc_stmt:
switch_stack.push_back(&current_process->root_case.switches);
case_stack.clear();
case_stack.push_back(&current_process->root_case);
+ attrbuf.clear();
free($2);
} case_body sync_list TOK_END EOL;
@@ -350,50 +361,25 @@ constant:
sigspec:
constant {
- RTLIL::SigChunk chunk;
- chunk.wire = NULL;
- chunk.width = $1->bits.size();
- chunk.offset = 0;
- chunk.data = *$1;
- $$ = new RTLIL::SigSpec;
- $$->chunks.push_back(chunk);
- $$->width = chunk.width;
+ $$ = new RTLIL::SigSpec(*$1);
delete $1;
} |
TOK_ID {
- if (current_module->wires.count($1) == 0)
- rtlil_frontend_ilang_yyerror(stringf("scope error: wire %s not found", $1).c_str());
- RTLIL::SigChunk chunk;
- chunk.wire = current_module->wires[$1];
- chunk.width = current_module->wires[$1]->width;
- chunk.offset = 0;
- $$ = new RTLIL::SigSpec;
- $$->chunks.push_back(chunk);
- $$->width = chunk.width;
+ 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]);
free($1);
} |
TOK_ID '[' TOK_INT ']' {
- if (current_module->wires.count($1) == 0)
- rtlil_frontend_ilang_yyerror(stringf("scope error: wire %s not found", $1).c_str());
- RTLIL::SigChunk chunk;
- chunk.wire = current_module->wires[$1];
- chunk.offset = $3;
- chunk.width = 1;
- $$ = new RTLIL::SigSpec;
- $$->chunks.push_back(chunk);
- $$->width = 1;
+ 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);
} |
TOK_ID '[' TOK_INT ':' TOK_INT ']' {
- if (current_module->wires.count($1) == 0)
- rtlil_frontend_ilang_yyerror(stringf("scope error: wire %s not found", $1).c_str());
- RTLIL::SigChunk chunk;
- chunk.wire = current_module->wires[$1];
- chunk.width = $3 - $5 + 1;
- chunk.offset = $5;
- $$ = new RTLIL::SigSpec;
- $$->chunks.push_back(chunk);
- $$->width = chunk.width;
+ 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_list '}' {
@@ -403,14 +389,8 @@ sigspec:
sigspec_list:
sigspec_list sigspec {
$$ = new RTLIL::SigSpec;
- for (auto it = $2->chunks.begin(); it != $2->chunks.end(); it++) {
- $$->chunks.push_back(*it);
- $$->width += it->width;
- }
- for (auto it = $1->chunks.begin(); it != $1->chunks.end(); it++) {
- $$->chunks.push_back(*it);
- $$->width += it->width;
- }
+ $$->append(*$2);
+ $$->append(*$1);
delete $1;
delete $2;
} |
@@ -422,7 +402,7 @@ conn_stmt:
TOK_CONNECT sigspec sigspec EOL {
if (attrbuf.size() != 0)
rtlil_frontend_ilang_yyerror("dangling attribute");
- current_module->connections.push_back(RTLIL::SigSig(*$2, *$3));
+ current_module->connect(*$2, *$3);
delete $2;
delete $3;
};
diff --git a/frontends/liberty/Makefile.inc b/frontends/liberty/Makefile.inc
new file mode 100644
index 00000000..a02ef5e4
--- /dev/null
+++ b/frontends/liberty/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += frontends/liberty/liberty.o
+
diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc
new file mode 100644
index 00000000..a9ab022a
--- /dev/null
+++ b/frontends/liberty/liberty.cc
@@ -0,0 +1,578 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "passes/techmap/libparse.h"
+#include "kernel/register.h"
+#include "kernel/log.h"
+
+YOSYS_NAMESPACE_BEGIN
+using namespace PASS_DFFLIBMAP;
+
+struct token_t {
+ char type;
+ RTLIL::SigSpec sig;
+ token_t (char t) : type(t) { }
+ token_t (char t, RTLIL::SigSpec s) : type(t), sig(s) { }
+};
+
+static RTLIL::SigSpec parse_func_identifier(RTLIL::Module *module, const char *&expr)
+{
+ log_assert(*expr != 0);
+
+ 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++;
+
+ if (id_len == 0)
+ log_error("Expected identifier at `%s'.\n", expr);
+
+ if (id_len == 1 && (*expr == '0' || *expr == '1'))
+ return *(expr++) == '0' ? RTLIL::State::S0 : RTLIL::State::S1;
+
+ std::string id = RTLIL::escape_id(std::string(expr, id_len));
+ if (!module->wires_.count(id))
+ log_error("Can't resolve wire name %s.\n", RTLIL::unescape_id(id).c_str());
+
+ expr += id_len;
+ return module->wires_.at(id);
+}
+
+static RTLIL::SigSpec create_inv_cell(RTLIL::Module *module, RTLIL::SigSpec A)
+{
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_");
+ cell->setPort("\\A", A);
+ cell->setPort("\\Y", module->addWire(NEW_ID));
+ return cell->getPort("\\Y");
+}
+
+static RTLIL::SigSpec create_xor_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B)
+{
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$_XOR_");
+ cell->setPort("\\A", A);
+ cell->setPort("\\B", B);
+ cell->setPort("\\Y", module->addWire(NEW_ID));
+ return cell->getPort("\\Y");
+}
+
+static RTLIL::SigSpec create_and_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B)
+{
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$_AND_");
+ cell->setPort("\\A", A);
+ cell->setPort("\\B", B);
+ cell->setPort("\\Y", module->addWire(NEW_ID));
+ return cell->getPort("\\Y");
+}
+
+static RTLIL::SigSpec create_or_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B)
+{
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$_OR_");
+ cell->setPort("\\A", A);
+ cell->setPort("\\B", B);
+ cell->setPort("\\Y", module->addWire(NEW_ID));
+ return cell->getPort("\\Y");
+}
+
+static bool parse_func_reduce(RTLIL::Module *module, std::vector<token_t> &stack, token_t next_token)
+{
+ int top = int(stack.size())-1;
+
+ if (0 <= top-1 && stack[top].type == 0 && stack[top-1].type == '!') {
+ token_t t = token_t(0, create_inv_cell(module, stack[top].sig));
+ stack.pop_back();
+ stack.pop_back();
+ stack.push_back(t);
+ return true;
+ }
+
+ if (0 <= top-1 && stack[top].type == '\'' && stack[top-1].type == 0) {
+ token_t t = token_t(0, create_inv_cell(module, stack[top-1].sig));
+ stack.pop_back();
+ stack.pop_back();
+ stack.push_back(t);
+ return true;
+ }
+
+ if (0 <= top && stack[top].type == 0) {
+ if (next_token.type == '\'')
+ return false;
+ stack[top].type = 1;
+ return true;
+ }
+
+ if (0 <= top-2 && stack[top-2].type == 1 && stack[top-1].type == '^' && stack[top].type == 1) {
+ token_t t = token_t(1, create_xor_cell(module, stack[top-2].sig, stack[top].sig));
+ stack.pop_back();
+ stack.pop_back();
+ stack.pop_back();
+ stack.push_back(t);
+ return true;
+ }
+
+ if (0 <= top && stack[top].type == 1) {
+ if (next_token.type == '^')
+ return false;
+ stack[top].type = 2;
+ return true;
+ }
+
+ if (0 <= top-1 && stack[top-1].type == 2 && stack[top].type == 2) {
+ token_t t = token_t(2, create_and_cell(module, stack[top-1].sig, stack[top].sig));
+ stack.pop_back();
+ stack.pop_back();
+ stack.push_back(t);
+ return true;
+ }
+
+ if (0 <= top-2 && stack[top-2].type == 2 && (stack[top-1].type == '*' || stack[top-1].type == '&') && stack[top].type == 2) {
+ token_t t = token_t(2, create_and_cell(module, stack[top-2].sig, stack[top].sig));
+ stack.pop_back();
+ stack.pop_back();
+ stack.pop_back();
+ stack.push_back(t);
+ return true;
+ }
+
+ if (0 <= top && stack[top].type == 2) {
+ if (next_token.type == '*' || next_token.type == '&' || next_token.type == 0 || next_token.type == '(')
+ return false;
+ stack[top].type = 3;
+ return true;
+ }
+
+ if (0 <= top-2 && stack[top-2].type == 3 && (stack[top-1].type == '+' || stack[top-1].type == '|') && stack[top].type == 3) {
+ token_t t = token_t(3, create_or_cell(module, stack[top-2].sig, stack[top].sig));
+ stack.pop_back();
+ stack.pop_back();
+ stack.pop_back();
+ stack.push_back(t);
+ return true;
+ }
+
+ if (0 <= top-2 && stack[top-2].type == '(' && stack[top-1].type == 3 && stack[top].type == ')') {
+ token_t t = token_t(0, stack[top-1].sig);
+ stack.pop_back();
+ stack.pop_back();
+ stack.pop_back();
+ stack.push_back(t);
+ return true;
+ }
+
+ return false;
+}
+
+static RTLIL::SigSpec parse_func_expr(RTLIL::Module *module, const char *expr)
+{
+ const char *orig_expr = expr;
+ std::vector<token_t> stack;
+
+ while (*expr)
+ {
+ if (*expr == ' ' || *expr == '\t' || *expr == '\r' || *expr == '\n' || *expr == '"') {
+ expr++;
+ continue;
+ }
+
+ token_t next_token(0);
+ if (*expr == '(' || *expr == ')' || *expr == '\'' || *expr == '!' || *expr == '^' || *expr == '*' || *expr == '+' || *expr == '|')
+ next_token = token_t(*(expr++));
+ else
+ next_token = token_t(0, parse_func_identifier(module, expr));
+
+ while (parse_func_reduce(module, stack, next_token)) {}
+ stack.push_back(next_token);
+ }
+
+ while (parse_func_reduce(module, stack, token_t('.'))) {}
+
+#if 0
+ for (size_t i = 0; i < stack.size(); i++)
+ if (stack[i].type < 16)
+ log("%3d: %d %s\n", int(i), stack[i].type, log_signal(stack[i].sig));
+ else
+ log("%3d: %c\n", int(i), stack[i].type);
+#endif
+
+ if (stack.size() != 1 || stack.back().type != 3)
+ log_error("Parser error in function expr `%s'.\n", orig_expr);
+
+ return stack.back().sig;
+}
+
+static void create_ff(RTLIL::Module *module, LibertyAst *node)
+{
+ RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0))));
+ RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1))));
+
+ RTLIL::SigSpec clk_sig, data_sig, clear_sig, preset_sig;
+ bool clk_polarity = true, clear_polarity = true, preset_polarity = true;
+
+ for (auto child : node->children) {
+ if (child->id == "clocked_on")
+ clk_sig = parse_func_expr(module, child->value.c_str());
+ if (child->id == "next_state")
+ data_sig = parse_func_expr(module, child->value.c_str());
+ if (child->id == "clear")
+ clear_sig = parse_func_expr(module, child->value.c_str());
+ if (child->id == "preset")
+ preset_sig = parse_func_expr(module, child->value.c_str());
+ }
+
+ if (clk_sig.size() == 0 || data_sig.size() == 0)
+ log_error("FF cell %s has no next_state and/or clocked_on attribute.\n", log_id(module->name));
+
+ for (bool rerun_invert_rollback = true; rerun_invert_rollback;)
+ {
+ rerun_invert_rollback = false;
+
+ for (auto &it : module->cells_) {
+ if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clk_sig) {
+ clk_sig = it.second->getPort("\\A");
+ clk_polarity = !clk_polarity;
+ rerun_invert_rollback = true;
+ }
+ if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clear_sig) {
+ clear_sig = it.second->getPort("\\A");
+ clear_polarity = !clear_polarity;
+ rerun_invert_rollback = true;
+ }
+ if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == preset_sig) {
+ preset_sig = it.second->getPort("\\A");
+ preset_polarity = !preset_polarity;
+ rerun_invert_rollback = true;
+ }
+ }
+ }
+
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_");
+ cell->setPort("\\A", iq_sig);
+ cell->setPort("\\Y", iqn_sig);
+
+ cell = module->addCell(NEW_ID, "");
+ cell->setPort("\\D", data_sig);
+ cell->setPort("\\Q", iq_sig);
+ cell->setPort("\\C", clk_sig);
+
+ if (clear_sig.size() == 0 && preset_sig.size() == 0) {
+ cell->type = stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N');
+ }
+
+ if (clear_sig.size() == 1 && preset_sig.size() == 0) {
+ cell->type = stringf("$_DFF_%c%c0_", clk_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N');
+ cell->setPort("\\R", clear_sig);
+ }
+
+ if (clear_sig.size() == 0 && preset_sig.size() == 1) {
+ cell->type = stringf("$_DFF_%c%c1_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N');
+ cell->setPort("\\R", preset_sig);
+ }
+
+ if (clear_sig.size() == 1 && preset_sig.size() == 1) {
+ cell->type = stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N');
+ cell->setPort("\\S", preset_sig);
+ cell->setPort("\\R", clear_sig);
+ }
+
+ log_assert(!cell->type.empty());
+}
+
+static void create_latch(RTLIL::Module *module, LibertyAst *node)
+{
+ RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0))));
+ RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1))));
+
+ RTLIL::SigSpec enable_sig, data_sig, clear_sig, preset_sig;
+ bool enable_polarity = true, clear_polarity = true, preset_polarity = true;
+
+ for (auto child : node->children) {
+ if (child->id == "enable")
+ enable_sig = parse_func_expr(module, child->value.c_str());
+ if (child->id == "data_in")
+ data_sig = parse_func_expr(module, child->value.c_str());
+ if (child->id == "clear")
+ clear_sig = parse_func_expr(module, child->value.c_str());
+ if (child->id == "preset")
+ preset_sig = parse_func_expr(module, child->value.c_str());
+ }
+
+ if (enable_sig.size() == 0 || data_sig.size() == 0)
+ log_error("Latch cell %s has no data_in and/or enable attribute.\n", log_id(module->name));
+
+ for (bool rerun_invert_rollback = true; rerun_invert_rollback;)
+ {
+ rerun_invert_rollback = false;
+
+ for (auto &it : module->cells_) {
+ if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == enable_sig) {
+ enable_sig = it.second->getPort("\\A");
+ enable_polarity = !enable_polarity;
+ rerun_invert_rollback = true;
+ }
+ if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clear_sig) {
+ clear_sig = it.second->getPort("\\A");
+ clear_polarity = !clear_polarity;
+ rerun_invert_rollback = true;
+ }
+ if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == preset_sig) {
+ preset_sig = it.second->getPort("\\A");
+ preset_polarity = !preset_polarity;
+ rerun_invert_rollback = true;
+ }
+ }
+ }
+
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_");
+ cell->setPort("\\A", iq_sig);
+ cell->setPort("\\Y", iqn_sig);
+
+ if (clear_sig.size() == 1)
+ {
+ RTLIL::SigSpec clear_negative = clear_sig;
+ RTLIL::SigSpec clear_enable = clear_sig;
+
+ if (clear_polarity == true || clear_polarity != enable_polarity)
+ {
+ RTLIL::Cell *inv = module->addCell(NEW_ID, "$_NOT_");
+ inv->setPort("\\A", clear_sig);
+ inv->setPort("\\Y", module->addWire(NEW_ID));
+
+ if (clear_polarity == true)
+ clear_negative = inv->getPort("\\Y");
+ if (clear_polarity != enable_polarity)
+ clear_enable = inv->getPort("\\Y");
+ }
+
+ RTLIL::Cell *data_gate = module->addCell(NEW_ID, "$_AND_");
+ data_gate->setPort("\\A", data_sig);
+ data_gate->setPort("\\B", clear_negative);
+ data_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
+
+ RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? "$_OR_" : "$_AND_");
+ enable_gate->setPort("\\A", enable_sig);
+ enable_gate->setPort("\\B", clear_enable);
+ enable_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
+ }
+
+ if (preset_sig.size() == 1)
+ {
+ RTLIL::SigSpec preset_positive = preset_sig;
+ RTLIL::SigSpec preset_enable = preset_sig;
+
+ if (preset_polarity == false || preset_polarity != enable_polarity)
+ {
+ RTLIL::Cell *inv = module->addCell(NEW_ID, "$_NOT_");
+ inv->setPort("\\A", preset_sig);
+ inv->setPort("\\Y", module->addWire(NEW_ID));
+
+ if (preset_polarity == false)
+ preset_positive = inv->getPort("\\Y");
+ if (preset_polarity != enable_polarity)
+ preset_enable = inv->getPort("\\Y");
+ }
+
+ RTLIL::Cell *data_gate = module->addCell(NEW_ID, "$_OR_");
+ data_gate->setPort("\\A", data_sig);
+ data_gate->setPort("\\B", preset_positive);
+ data_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
+
+ RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? "$_OR_" : "$_AND_");
+ enable_gate->setPort("\\A", enable_sig);
+ enable_gate->setPort("\\B", preset_enable);
+ enable_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
+ }
+
+ cell = module->addCell(NEW_ID, stringf("$_DLATCH_%c_", enable_polarity ? 'P' : 'N'));
+ cell->setPort("\\D", data_sig);
+ cell->setPort("\\Q", iq_sig);
+ cell->setPort("\\E", enable_sig);
+}
+
+struct LibertyFrontend : public Frontend {
+ LibertyFrontend() : Frontend("liberty", "read cells from liberty file") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" read_liberty [filename]\n");
+ log("\n");
+ log("Read cells from liberty file as modules into current design.\n");
+ log("\n");
+ log(" -lib\n");
+ log(" only create empty blackbox modules\n");
+ log("\n");
+ log(" -ignore_redef\n");
+ log(" ignore re-definitions of modules. (the default behavior is to\n");
+ log(" create an error message.)\n");
+ log("\n");
+ log(" -ignore_miss_func\n");
+ log(" ignore cells with missing function specification of outputs\n");
+ log("\n");
+ log(" -ignore_miss_dir\n");
+ log(" ignore cells with a missing or invalid direction\n");
+ log(" specification on a pin\n");
+ log("\n");
+ log(" -setattr <attribute_name>\n");
+ log(" set the specified attribute (to the value 1) on all loaded modules\n");
+ log("\n");
+ }
+ virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ {
+ bool flag_lib = false;
+ bool flag_ignore_redef = false;
+ bool flag_ignore_miss_func = false;
+ bool flag_ignore_miss_dir = false;
+ std::vector<std::string> attributes;
+
+ log_header("Executing Liberty frontend.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ std::string arg = args[argidx];
+ if (arg == "-lib") {
+ flag_lib = true;
+ continue;
+ }
+ if (arg == "-ignore_redef") {
+ flag_ignore_redef = true;
+ continue;
+ }
+ if (arg == "-ignore_miss_func") {
+ flag_ignore_miss_func = true;
+ continue;
+ }
+ if (arg == "-ignore_miss_dir") {
+ flag_ignore_miss_dir = true;
+ continue;
+ }
+ if (arg == "-setattr" && argidx+1 < args.size()) {
+ attributes.push_back(RTLIL::escape_id(args[++argidx]));
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ LibertyParser parser(*f);
+ int cell_count = 0;
+
+ for (auto cell : parser.ast->children)
+ {
+ if (cell->id != "cell" || cell->args.size() != 1)
+ continue;
+
+ std::string cell_name = RTLIL::escape_id(cell->args.at(0));
+
+ if (design->has(cell_name)) {
+ if (flag_ignore_redef)
+ continue;
+ log_error("Duplicate definition of cell/module %s.\n", RTLIL::unescape_id(cell_name).c_str());
+ }
+
+ // log("Processing cell type %s.\n", RTLIL::unescape_id(cell_name).c_str());
+
+ RTLIL::Module *module = new RTLIL::Module;
+ module->name = cell_name;
+
+ if (flag_lib)
+ module->set_bool_attribute("\\blackbox");
+
+ for (auto &attr : attributes)
+ module->attributes[attr] = 1;
+
+ for (auto node : cell->children)
+ if (node->id == "pin" && node->args.size() == 1) {
+ LibertyAst *dir = node->find("direction");
+ if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal"))
+ {
+ if (!flag_ignore_miss_dir)
+ {
+ log_error("Missing or invalid direction for pin %s of cell %s.\n", node->args.at(0).c_str(), log_id(module->name));
+ } else {
+ log("Ignoring cell %s with missing or invalid direction for pin %s.\n", log_id(module->name), node->args.at(0).c_str());
+ delete module;
+ goto skip_cell;
+ }
+ }
+ if (!flag_lib || dir->value != "internal")
+ module->addWire(RTLIL::escape_id(node->args.at(0)));
+ }
+
+ for (auto node : cell->children)
+ {
+ if (!flag_lib) {
+ if (node->id == "ff" && node->args.size() == 2)
+ create_ff(module, node);
+ if (node->id == "latch" && node->args.size() == 2)
+ create_latch(module, node);
+ }
+
+ if (node->id == "pin" && node->args.size() == 1)
+ {
+ LibertyAst *dir = node->find("direction");
+
+ if (flag_lib && dir->value == "internal")
+ continue;
+
+ RTLIL::Wire *wire = module->wires_.at(RTLIL::escape_id(node->args.at(0)));
+
+ if (dir && dir->value == "inout") {
+ wire->port_input = true;
+ wire->port_output = true;
+ }
+
+ if (dir && dir->value == "input") {
+ wire->port_input = true;
+ continue;
+ }
+
+ if (dir && dir->value == "output")
+ wire->port_output = true;
+
+ if (flag_lib)
+ continue;
+
+ LibertyAst *func = node->find("function");
+ if (func == NULL)
+ {
+ if (!flag_ignore_miss_func)
+ {
+ log_error("Missing function on output %s of cell %s.\n", log_id(wire->name), log_id(module->name));
+ } else {
+ log("Ignoring cell %s with missing function on output %s.\n", log_id(module->name), log_id(wire->name));
+ delete module;
+ goto skip_cell;
+ }
+ }
+
+ RTLIL::SigSpec out_sig = parse_func_expr(module, func->value.c_str());
+ module->connect(RTLIL::SigSig(wire, out_sig));
+ }
+ }
+
+ module->fixup_ports();
+ design->add(module);
+ cell_count++;
+skip_cell:;
+ }
+
+ log("Imported %d cell types from liberty file.\n", cell_count);
+ }
+} LibertyFrontend;
+
+YOSYS_NAMESPACE_END
+
diff --git a/frontends/verific/Makefile.inc b/frontends/verific/Makefile.inc
new file mode 100644
index 00000000..13f242c4
--- /dev/null
+++ b/frontends/verific/Makefile.inc
@@ -0,0 +1,16 @@
+
+OBJS += frontends/verific/verific.o
+
+ifeq ($(ENABLE_VERIFIC),1)
+
+EXTRA_TARGETS += share/verific
+
+share/verific:
+ $(P) rm -rf share/verific.new
+ $(Q) mkdir -p share/verific.new
+ $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs share/verific.new/vhdl_vdbs_1993
+ $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008 share/verific.new/vhdl_vdbs_2008
+ $(Q) mv share/verific.new share/verific
+
+endif
+
diff --git a/frontends/verific/build_amd64.txt b/frontends/verific/build_amd64.txt
new file mode 100644
index 00000000..94615d38
--- /dev/null
+++ b/frontends/verific/build_amd64.txt
@@ -0,0 +1,31 @@
+
+Notes on building yosys with verific support on amd64 when you
+only have the i386 eval version of Verific:
+
+
+1.) Use a Makefile.conf like the following one:
+
+--snip--
+CONFIG := clang
+ENABLE_TCL := 0
+ENABLE_QT4 := 0
+ENABLE_ABC := 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:amd64 or lib32readline6-dev, depending on the
+exact version of debian/ubuntu you are working with.
+
+
+3.) Build and test
+
+make -j8
+./yosys frontends/verific/test_navre.ys
+
diff --git a/frontends/verific/test_navre.ys b/frontends/verific/test_navre.ys
new file mode 100644
index 00000000..a56b725a
--- /dev/null
+++ b/frontends/verific/test_navre.ys
@@ -0,0 +1,18 @@
+verific -vlog2k ../yosys-bigsim/softusb_navre/rtl/softusb_navre.v
+verific -import softusb_navre
+
+memory softusb_navre
+flatten softusb_navre
+rename softusb_navre gate
+
+read_verilog ../yosys-bigsim/softusb_navre/rtl/softusb_navre.v
+cd softusb_navre; proc; opt; memory; opt; cd ..
+rename softusb_navre gold
+
+expose -dff -shared gold gate
+miter -equiv -ignore_gold_x -make_assert -make_outputs -make_outcmp gold gate miter
+
+cd miter
+flatten; opt -undriven
+sat -verify -maxsteps 5 -set-init-undef -set-def-inputs -prove-asserts -tempinduct-def \
+ -seq 1 -set-at 1 in_rst 1 # -show-inputs -show-outputs
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
new file mode 100644
index 00000000..d0f14838
--- /dev/null
+++ b/frontends/verific/verific.cc
@@ -0,0 +1,949 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+
+USING_YOSYS_NAMESPACE
+
+#ifdef YOSYS_ENABLE_VERIFIC
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Woverloaded-virtual"
+
+#include "veri_file.h"
+#include "vhdl_file.h"
+#include "VeriModule.h"
+#include "VhdlUnits.h"
+#include "DataBase.h"
+#include "Message.h"
+
+#pragma clang diagnostic pop
+
+#ifdef VERIFIC_NAMESPACE
+using namespace Verific ;
+#endif
+
+static void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefile, const char *msg, va_list args)
+{
+ log("VERIFIC-%s [%s] ",
+ msg_type == VERIFIC_NONE ? "NONE" :
+ msg_type == VERIFIC_ERROR ? "ERROR" :
+ msg_type == VERIFIC_WARNING ? "WARNING" :
+ msg_type == VERIFIC_IGNORE ? "IGNORE" :
+ msg_type == VERIFIC_INFO ? "INFO" :
+ msg_type == VERIFIC_COMMENT ? "COMMENT" :
+ msg_type == VERIFIC_PROGRAM_ERROR ? "PROGRAM_ERROR" : "UNKNOWN", message_id);
+ if (linefile)
+ log("%s:%d: ", LineFile::GetFileName(linefile), LineFile::GetLineNo(linefile));
+ logv(msg, args);
+ log("\n");
+}
+
+static void import_attributes(std::map<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj)
+{
+ MapIter mi;
+ Att *attr;
+
+ if (obj->Linefile())
+ attributes["\\src"] = stringf("%s:%d", LineFile::GetFileName(obj->Linefile()), LineFile::GetLineNo(obj->Linefile()));
+
+ // FIXME: Parse numeric attributes
+ FOREACH_ATTRIBUTE(obj, mi, attr)
+ attributes[RTLIL::escape_id(attr->Key())] = RTLIL::Const(std::string(attr->Value()));
+}
+
+static RTLIL::SigSpec operatorInput(Instance *inst, std::map<Net*, RTLIL::SigBit> &net_map)
+{
+ RTLIL::SigSpec sig;
+ for (int i = int(inst->InputSize())-1; i >= 0; i--)
+ if (inst->GetInputBit(i))
+ sig.append(net_map.at(inst->GetInputBit(i)));
+ else
+ sig.append(RTLIL::State::Sz);
+ return sig;
+}
+
+static RTLIL::SigSpec operatorInput1(Instance *inst, std::map<Net*, RTLIL::SigBit> &net_map)
+{
+ RTLIL::SigSpec sig;
+ for (int i = int(inst->Input1Size())-1; i >= 0; i--)
+ if (inst->GetInput1Bit(i))
+ sig.append(net_map.at(inst->GetInput1Bit(i)));
+ else
+ sig.append(RTLIL::State::Sz);
+ return sig;
+}
+
+static RTLIL::SigSpec operatorInput2(Instance *inst, std::map<Net*, RTLIL::SigBit> &net_map)
+{
+ RTLIL::SigSpec sig;
+ for (int i = int(inst->Input2Size())-1; i >= 0; i--)
+ if (inst->GetInput2Bit(i))
+ sig.append(net_map.at(inst->GetInput2Bit(i)));
+ else
+ sig.append(RTLIL::State::Sz);
+ return sig;
+}
+
+static RTLIL::SigSpec operatorInport(Instance *inst, const char *portname, std::map<Net*, RTLIL::SigBit> &net_map)
+{
+ PortBus *portbus = inst->View()->GetPortBus(portname);
+ if (portbus) {
+ RTLIL::SigSpec sig;
+ for (unsigned i = 0; i < portbus->Size(); i++) {
+ Net *net = inst->GetNet(portbus->ElementAtIndex(i));
+ if (net) {
+ if (net->IsGnd())
+ sig.append(RTLIL::State::S0);
+ else if (net->IsPwr())
+ sig.append(RTLIL::State::S1);
+ else
+ sig.append(net_map.at(net));
+ } else
+ sig.append(RTLIL::State::Sz);
+ }
+ return sig;
+ } else {
+ Port *port = inst->View()->GetPort(portname);
+ log_assert(port != NULL);
+ Net *net = inst->GetNet(port);
+ return net_map.at(net);
+ }
+}
+
+static RTLIL::SigSpec operatorOutput(Instance *inst, std::map<Net*, RTLIL::SigBit> &net_map, RTLIL::Module *module)
+{
+ RTLIL::SigSpec sig;
+ RTLIL::Wire *dummy_wire = NULL;
+ for (int i = int(inst->OutputSize())-1; i >= 0; i--)
+ if (inst->GetOutputBit(i)) {
+ sig.append(net_map.at(inst->GetOutputBit(i)));
+ dummy_wire = NULL;
+ } else {
+ if (dummy_wire == NULL)
+ dummy_wire = module->addWire(NEW_ID);
+ else
+ dummy_wire->width++;
+ sig.append(RTLIL::SigSpec(dummy_wire, dummy_wire->width - 1));
+ }
+ return sig;
+}
+
+static bool import_netlist_instance_gates(RTLIL::Module *module, std::map<Net*, RTLIL::SigBit> &net_map, Instance *inst)
+{
+ if (inst->Type() == PRIM_AND) {
+ module->addAndGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_NAND) {
+ RTLIL::SigSpec tmp = module->addWire(NEW_ID);
+ module->addAndGate(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), tmp);
+ module->addNotGate(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_OR) {
+ module->addOrGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_NOR) {
+ RTLIL::SigSpec tmp = module->addWire(NEW_ID);
+ module->addOrGate(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), tmp);
+ module->addNotGate(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_XOR) {
+ module->addXorGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_INV) {
+ module->addNotGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_MUX) {
+ module->addMuxGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetControl()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_TRI) {
+ module->addMuxGate(RTLIL::escape_id(inst->Name()), RTLIL::State::Sz, net_map.at(inst->GetInput()), net_map.at(inst->GetControl()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_FADD)
+ {
+ RTLIL::SigSpec a = net_map.at(inst->GetInput1()), b = net_map.at(inst->GetInput2()), c = net_map.at(inst->GetCin());
+ RTLIL::SigSpec x = inst->GetCout() ? net_map.at(inst->GetCout()) : module->addWire(NEW_ID);
+ RTLIL::SigSpec y = inst->GetOutput() ? net_map.at(inst->GetOutput()) : module->addWire(NEW_ID);
+ RTLIL::SigSpec tmp1 = module->addWire(NEW_ID);
+ RTLIL::SigSpec tmp2 = module->addWire(NEW_ID);
+ RTLIL::SigSpec tmp3 = module->addWire(NEW_ID);
+ module->addXorGate(NEW_ID, a, b, tmp1);
+ module->addXorGate(RTLIL::escape_id(inst->Name()), tmp1, c, y);
+ module->addAndGate(NEW_ID, tmp1, c, tmp2);
+ module->addAndGate(NEW_ID, a, b, tmp3);
+ module->addOrGate(NEW_ID, tmp2, tmp3, x);
+ return true;
+ }
+
+ if (inst->Type() == PRIM_DFFRS)
+ {
+ if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd())
+ module->addDffGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ else if (inst->GetSet()->IsGnd())
+ module->addAdffGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetReset()),
+ net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()), false);
+ else if (inst->GetReset()->IsGnd())
+ module->addAdffGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetSet()),
+ net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()), true);
+ else
+ module->addDffsrGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetSet()), net_map.at(inst->GetReset()),
+ net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ return false;
+}
+
+static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*, RTLIL::SigBit> &net_map, Instance *inst)
+{
+ if (inst->Type() == PRIM_AND) {
+ module->addAnd(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_NAND) {
+ RTLIL::SigSpec tmp = module->addWire(NEW_ID);
+ module->addAnd(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), tmp);
+ module->addNot(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_OR) {
+ module->addOr(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_NOR) {
+ RTLIL::SigSpec tmp = module->addWire(NEW_ID);
+ module->addOr(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), tmp);
+ module->addNot(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_XOR) {
+ module->addXor(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_XNOR) {
+ module->addXnor(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_INV) {
+ module->addNot(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_MUX) {
+ module->addMux(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetControl()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_TRI) {
+ module->addMux(RTLIL::escape_id(inst->Name()), RTLIL::State::Sz, net_map.at(inst->GetInput()), net_map.at(inst->GetControl()), net_map.at(inst->GetOutput()));
+ 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);
+ if (inst->GetCout())
+ y.append(net_map.at(inst->GetCout()));
+ module->addAdd(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), a_plus_b);
+ module->addAdd(RTLIL::escape_id(inst->Name()), a_plus_b, net_map.at(inst->GetCin()), y);
+ return true;
+ }
+
+ if (inst->Type() == PRIM_DFFRS)
+ {
+ if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd())
+ module->addDff(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ else if (inst->GetSet()->IsGnd())
+ module->addAdff(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetReset()),
+ net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()), RTLIL::State::S0);
+ else if (inst->GetReset()->IsGnd())
+ module->addAdff(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetSet()),
+ net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()), RTLIL::State::S1);
+ else
+ module->addDffsr(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetSet()), net_map.at(inst->GetReset()),
+ net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ #define IN operatorInput(inst, net_map)
+ #define IN1 operatorInput1(inst, net_map)
+ #define IN2 operatorInput2(inst, net_map)
+ #define OUT operatorOutput(inst, net_map, module)
+ #define SIGNED inst->View()->IsSigned()
+
+ if (inst->Type() == OPER_ADDER) {
+ RTLIL::SigSpec out = OUT;
+ if (inst->GetCout() != NULL)
+ out.append(net_map.at(inst->GetCout()));
+ if (inst->GetCin()->IsGnd()) {
+ module->addAdd(RTLIL::escape_id(inst->Name()), IN1, IN2, out, SIGNED);
+ } else {
+ RTLIL::SigSpec tmp = module->addWire(NEW_ID, SIZE(out));
+ module->addAdd(NEW_ID, IN1, IN2, tmp, SIGNED);
+ module->addAdd(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetCin()), out, false);
+ }
+ return true;
+ }
+
+ if (inst->Type() == OPER_MULTIPLIER) {
+ module->addMul(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_DIVIDER) {
+ module->addDiv(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_MODULO) {
+ module->addMod(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_REMAINDER) {
+ module->addMod(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_SHIFT_LEFT) {
+ module->addShl(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, false);
+ return true;
+ }
+
+ if (inst->Type() == OPER_SHIFT_RIGHT) {
+ Net *net_cin = inst->GetCin();
+ Net *net_a_msb = inst->GetInput1Bit(0);
+ if (net_cin->IsGnd())
+ module->addShr(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, false);
+ else if (net_cin == net_a_msb)
+ module->addSshr(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, true);
+ else
+ log_error("Can't import Verific OPER_SHIFT_RIGHT instance %s: carry_in is neither 0 nor msb of left input\n", inst->Name());
+ return true;
+ }
+
+ if (inst->Type() == OPER_REDUCE_AND) {
+ module->addReduceAnd(RTLIL::escape_id(inst->Name()), IN, net_map.at(inst->GetOutput()), SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_REDUCE_OR) {
+ module->addReduceOr(RTLIL::escape_id(inst->Name()), IN, net_map.at(inst->GetOutput()), SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_REDUCE_XOR) {
+ module->addReduceXor(RTLIL::escape_id(inst->Name()), IN, net_map.at(inst->GetOutput()), SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_REDUCE_XNOR) {
+ module->addReduceXnor(RTLIL::escape_id(inst->Name()), IN, net_map.at(inst->GetOutput()), SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_LESSTHAN) {
+ Net *net_cin = inst->GetCin();
+ if (net_cin->IsGnd())
+ module->addLt(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetOutput()), SIGNED);
+ else if (net_cin->IsPwr())
+ module->addLe(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetOutput()), SIGNED);
+ else
+ log_error("Can't import Verific OPER_LESSTHAN instance %s: carry_in is neither 0 nor 1\n", inst->Name());
+ return true;
+ }
+
+ if (inst->Type() == OPER_WIDE_AND) {
+ module->addAnd(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_WIDE_OR) {
+ module->addOr(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_WIDE_XOR) {
+ module->addXor(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_WIDE_XNOR) {
+ module->addXnor(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_WIDE_BUF) {
+ module->addPos(RTLIL::escape_id(inst->Name()), IN, OUT, SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_WIDE_INV) {
+ module->addNot(RTLIL::escape_id(inst->Name()), IN, OUT, SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_MINUS) {
+ module->addSub(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_UMINUS) {
+ module->addNeg(RTLIL::escape_id(inst->Name()), IN, OUT, SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_EQUAL) {
+ module->addEq(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetOutput()), SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_NEQUAL) {
+ module->addNe(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetOutput()), SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_WIDE_MUX) {
+ module->addMux(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetControl()), OUT);
+ return true;
+ }
+
+ if (inst->Type() == OPER_WIDE_TRI) {
+ module->addMux(RTLIL::escape_id(inst->Name()), RTLIL::SigSpec(RTLIL::State::Sz, inst->OutputSize()), IN, net_map.at(inst->GetControl()), OUT);
+ return true;
+ }
+
+ if (inst->Type() == OPER_WIDE_DFFRS) {
+ RTLIL::SigSpec sig_set = operatorInport(inst, "set", net_map);
+ RTLIL::SigSpec sig_reset = operatorInport(inst, "reset", net_map);
+ if (sig_set.is_fully_const() && !sig_set.as_bool() && sig_reset.is_fully_const() && !sig_reset.as_bool())
+ module->addDff(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), IN, OUT);
+ else
+ module->addDffsr(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), sig_set, sig_reset, IN, OUT);
+ return true;
+ }
+
+ #undef IN
+ #undef IN1
+ #undef IN2
+ #undef OUT
+ #undef SIGNED
+
+ return false;
+}
+
+static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo, bool mode_gates)
+{
+ std::string module_name = nl->IsOperator() ? std::string("$verific$") + nl->Owner()->Name() : RTLIL::escape_id(nl->Owner()->Name());
+
+ if (design->has(module_name)) {
+ if (!nl->IsOperator())
+ log_cmd_error("Re-definition of module `%s'.\n", nl->Owner()->Name());
+ return;
+ }
+
+ RTLIL::Module *module = new RTLIL::Module;
+ module->name = module_name;
+ design->add(module);
+
+ log("Importing module %s.\n", RTLIL::id2cstr(module->name));
+
+ std::map<Net*, RTLIL::SigBit> net_map;
+
+ SetIter si;
+ MapIter mi, mi2;
+ Port *port;
+ PortBus *portbus;
+ Net *net;
+ NetBus *netbus;
+ Instance *inst;
+ PortRef *pr;
+
+ FOREACH_PORT_OF_NETLIST(nl, mi, port)
+ {
+ if (port->Bus())
+ continue;
+
+ // log(" importing port %s.\n", port->Name());
+
+ RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(port->Name()));
+ import_attributes(wire->attributes, port);
+
+ wire->port_id = nl->IndexOf(port) + 1;
+
+ if (port->GetDir() == DIR_INOUT || port->GetDir() == DIR_IN)
+ wire->port_input = true;
+ if (port->GetDir() == DIR_INOUT || port->GetDir() == DIR_OUT)
+ wire->port_output = true;
+
+ if (port->GetNet()) {
+ net = port->GetNet();
+ if (net_map.count(net) == 0)
+ net_map[net] = wire;
+ else if (wire->port_input)
+ module->connect(net_map.at(net), wire);
+ else
+ module->connect(wire, net_map.at(net));
+ }
+ }
+
+ FOREACH_PORTBUS_OF_NETLIST(nl, mi, portbus)
+ {
+ // log(" importing portbus %s.\n", portbus->Name());
+
+ RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size());
+ wire->start_offset = std::min(portbus->LeftIndex(), portbus->RightIndex());
+ import_attributes(wire->attributes, portbus);
+
+ if (portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN)
+ wire->port_input = true;
+ if (portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_OUT)
+ wire->port_output = true;
+
+ for (int i = portbus->LeftIndex();; i += portbus->IsUp() ? +1 : -1) {
+ if (portbus->ElementAtIndex(i) && portbus->ElementAtIndex(i)->GetNet()) {
+ net = portbus->ElementAtIndex(i)->GetNet();
+ RTLIL::SigBit bit(wire, i - wire->start_offset);
+ if (net_map.count(net) == 0)
+ net_map[net] = bit;
+ else if (wire->port_input)
+ module->connect(net_map.at(net), bit);
+ else
+ module->connect(bit, net_map.at(net));
+ }
+ if (i == portbus->RightIndex())
+ break;
+ }
+ }
+
+ module->fixup_ports();
+
+ FOREACH_NET_OF_NETLIST(nl, mi, net)
+ {
+ if (net->IsRamNet())
+ {
+ RTLIL::Memory *memory = new RTLIL::Memory;
+ memory->name = RTLIL::escape_id(net->Name());
+ log_assert(module->count_id(memory->name) == 0);
+ module->memories[memory->name] = memory;
+
+ int number_of_bits = net->Size();
+ int bits_in_word = number_of_bits;
+ FOREACH_PORTREF_OF_NET(net, si, pr) {
+ if (pr->GetInst()->Type() == OPER_READ_PORT) {
+ bits_in_word = std::min<int>(bits_in_word, pr->GetInst()->OutputSize());
+ continue;
+ }
+ if (pr->GetInst()->Type() == OPER_WRITE_PORT || pr->GetInst()->Type() == OPER_CLOCKED_WRITE_PORT) {
+ bits_in_word = std::min<int>(bits_in_word, pr->GetInst()->Input2Size());
+ continue;
+ }
+ log_error("Verific RamNet %s is connected to unsupported instance type %s (%s).\n",
+ net->Name(), pr->GetInst()->View()->Owner()->Name(), pr->GetInst()->Name());
+ }
+
+ memory->width = bits_in_word;
+ memory->size = number_of_bits / bits_in_word;
+ continue;
+ }
+
+ if (net_map.count(net)) {
+ // log(" skipping net %s.\n", net->Name());
+ continue;
+ }
+
+ if (net->Bus())
+ continue;
+
+ // log(" importing net %s.\n", net->Name());
+
+ RTLIL::IdString wire_name = module->uniquify(RTLIL::escape_id(net->Name()));
+ RTLIL::Wire *wire = module->addWire(wire_name);
+ import_attributes(wire->attributes, net);
+
+ net_map[net] = wire;
+ }
+
+ FOREACH_NETBUS_OF_NETLIST(nl, mi, netbus)
+ {
+ bool found_new_net = false;
+ for (int i = netbus->LeftIndex();; i += netbus->IsUp() ? +1 : -1) {
+ net = netbus->ElementAtIndex(i);
+ if (net_map.count(net) == 0)
+ found_new_net = true;
+ if (i == netbus->RightIndex())
+ break;
+ }
+
+ if (found_new_net)
+ {
+ // log(" importing netbus %s.\n", netbus->Name());
+
+ RTLIL::IdString wire_name = module->uniquify(RTLIL::escape_id(netbus->Name()));
+ RTLIL::Wire *wire = module->addWire(wire_name, netbus->Size());
+ wire->start_offset = std::min(netbus->LeftIndex(), netbus->RightIndex());
+ import_attributes(wire->attributes, netbus);
+
+ for (int i = netbus->LeftIndex();; i += netbus->IsUp() ? +1 : -1) {
+ if (netbus->ElementAtIndex(i)) {
+ net = netbus->ElementAtIndex(i);
+ RTLIL::SigBit bit(wire, i - wire->start_offset);
+ if (net_map.count(net) == 0)
+ net_map[net] = bit;
+ else
+ module->connect(bit, net_map.at(net));
+ }
+ if (i == netbus->RightIndex())
+ break;
+ }
+ }
+ else
+ {
+ // log(" skipping netbus %s.\n", netbus->Name());
+ }
+ }
+
+ FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst)
+ {
+ // log(" importing cell %s (%s).\n", inst->Name(), inst->View()->Owner()->Name());
+
+ if (inst->Type() == PRIM_PWR) {
+ module->connect(net_map.at(inst->GetOutput()), RTLIL::State::S1);
+ continue;
+ }
+
+ if (inst->Type() == PRIM_GND) {
+ module->connect(net_map.at(inst->GetOutput()), RTLIL::State::S0);
+ continue;
+ }
+
+ if (inst->Type() == PRIM_X) {
+ module->connect(net_map.at(inst->GetOutput()), RTLIL::State::Sx);
+ continue;
+ }
+
+ if (inst->Type() == PRIM_Z) {
+ module->connect(net_map.at(inst->GetOutput()), RTLIL::State::Sz);
+ continue;
+ }
+
+ if (inst->Type() == OPER_READ_PORT)
+ {
+ RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetInput()->Name()));
+ if (memory->width != int(inst->OutputSize()))
+ log_error("Import of asymetric memories from Verific is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
+
+ RTLIL::SigSpec addr = operatorInput1(inst, net_map);
+ RTLIL::SigSpec data = operatorOutput(inst, net_map, module);
+
+ RTLIL::Cell *cell = module->addCell(RTLIL::escape_id(inst->Name()), "$memrd");
+ cell->parameters["\\MEMID"] = memory->name.str();
+ cell->parameters["\\CLK_ENABLE"] = false;
+ cell->parameters["\\CLK_POLARITY"] = true;
+ cell->parameters["\\TRANSPARENT"] = false;
+ cell->parameters["\\ABITS"] = SIZE(addr);
+ cell->parameters["\\WIDTH"] = SIZE(data);
+ cell->setPort("\\CLK", RTLIL::State::S0);
+ cell->setPort("\\ADDR", addr);
+ cell->setPort("\\DATA", data);
+ continue;
+ }
+
+ 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 asymetric memories from Verific is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
+
+ RTLIL::SigSpec addr = operatorInput1(inst, net_map);
+ RTLIL::SigSpec data = operatorInput2(inst, net_map);
+
+ RTLIL::Cell *cell = module->addCell(RTLIL::escape_id(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"] = SIZE(addr);
+ cell->parameters["\\WIDTH"] = SIZE(data);
+ cell->setPort("\\EN", RTLIL::SigSpec(net_map.at(inst->GetControl())).repeat(SIZE(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;
+ }
+
+ if (!mode_gates) {
+ if (import_netlist_instance_cells(module, net_map, inst))
+ continue;
+ if (inst->IsOperator())
+ log("Warning: Unsupported Verific operator: %s (fallback to gate level implementation provided by verific)\n", inst->View()->Owner()->Name());
+ } else {
+ if (import_netlist_instance_gates(module, net_map, inst))
+ continue;
+ }
+
+ if (inst->IsPrimitive())
+ log_error("Unsupported Verific primitive: %s\n", inst->View()->Owner()->Name());
+
+ nl_todo.insert(inst->View());
+
+ RTLIL::Cell *cell = module->addCell(RTLIL::escape_id(inst->Name()), inst->IsOperator() ?
+ std::string("$verific$") + inst->View()->Owner()->Name() : RTLIL::escape_id(inst->View()->Owner()->Name()));
+
+ FOREACH_PORTREF_OF_INST(inst, mi2, pr) {
+ // log(" .%s(%s)\n", pr->GetPort()->Name(), pr->GetNet()->Name());
+ const char *port_name = pr->GetPort()->Name();
+ int port_offset = 0;
+ if (pr->GetPort()->Bus()) {
+ port_name = pr->GetPort()->Bus()->Name();
+ port_offset = pr->GetPort()->Bus()->IndexOf(pr->GetPort()) -
+ std::min(pr->GetPort()->Bus()->LeftIndex(), pr->GetPort()->Bus()->RightIndex());
+ }
+ RTLIL::SigSpec conn;
+ if (cell->hasPort(RTLIL::escape_id(port_name)))
+ conn = cell->getPort(RTLIL::escape_id(port_name));
+ while (SIZE(conn) <= port_offset) {
+ if (pr->GetPort()->GetDir() != DIR_IN)
+ conn.append(module->addWire(NEW_ID, port_offset - SIZE(conn)));
+ conn.append(RTLIL::State::Sz);
+ }
+ conn.replace(port_offset, net_map.at(pr->GetNet()));
+ cell->setPort(RTLIL::escape_id(port_name), conn);
+ }
+ }
+}
+
+#endif /* YOSYS_ENABLE_VERIFIC */
+
+YOSYS_NAMESPACE_BEGIN
+
+struct VerificPass : public Pass {
+ VerificPass() : Pass("verific", "load Verilog and VHDL designs using Verific") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" verific {-vlog95|-vlog2k|-sv2005|-sv2009|-sv} <verilog-file>..\n");
+ log("\n");
+ log("Load the specified Verilog/SystemVerilog files into Verific.\n");
+ log("\n");
+ log("\n");
+ log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008} <vhdl-file>..\n");
+ log("\n");
+ log("Load the specified VHDL files into Verific.\n");
+ log("\n");
+ log("\n");
+ log(" verific -import [-gates] {-all | <top-module>..}\n");
+ log("\n");
+ log("Elaborate the design for the sepcified top modules, import to Yosys and\n");
+ log("reset the internal state of Verific. A gate-level netlist is created\n");
+ log("when called with -gates.\n");
+ log("\n");
+ log("Visit http://verific.com/ for more information on Verific.\n");
+ log("\n");
+ }
+#ifdef YOSYS_ENABLE_VERIFIC
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Executing VERIFIC (loading Verilog and VHDL designs using Verific).\n");
+
+ Message::SetConsoleOutput(0);
+ Message::RegisterCallBackMsg(msg_func);
+
+ if (args.size() > 1 && args[1] == "-vlog95") {
+ for (size_t argidx = 2; argidx < args.size(); argidx++)
+ if (!veri_file::Analyze(args[argidx].c_str(), veri_file::VERILOG_95))
+ log_cmd_error("Reading `%s' in VERILOG_95 mode failed.\n", args[argidx].c_str());
+ return;
+ }
+
+ if (args.size() > 1 && args[1] == "-vlog2k") {
+ for (size_t argidx = 2; argidx < args.size(); argidx++)
+ if (!veri_file::Analyze(args[argidx].c_str(), veri_file::VERILOG_2K))
+ log_cmd_error("Reading `%s' in VERILOG_2K mode failed.\n", args[argidx].c_str());
+ return;
+ }
+
+ if (args.size() > 1 && args[1] == "-sv2005") {
+ for (size_t argidx = 2; argidx < args.size(); argidx++)
+ if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG_2005))
+ log_cmd_error("Reading `%s' in SYSTEM_VERILOG_2005 mode failed.\n", args[argidx].c_str());
+ return;
+ }
+
+ if (args.size() > 1 && args[1] == "-sv2009") {
+ for (size_t argidx = 2; argidx < args.size(); argidx++)
+ if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG_2009))
+ log_cmd_error("Reading `%s' in SYSTEM_VERILOG_2009 mode failed.\n", args[argidx].c_str());
+ return;
+ }
+
+ if (args.size() > 1 && args[1] == "-sv") {
+ for (size_t argidx = 2; argidx < args.size(); argidx++)
+ if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG))
+ log_cmd_error("Reading `%s' in SYSTEM_VERILOG mode failed.\n", args[argidx].c_str());
+ return;
+ }
+
+ if (args.size() > 1 && args[1] == "-vhdl87") {
+ vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
+ for (size_t argidx = 2; argidx < args.size(); argidx++)
+ if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_87))
+ log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", args[argidx].c_str());
+ return;
+ }
+
+ if (args.size() > 1 && args[1] == "-vhdl93") {
+ vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
+ for (size_t argidx = 2; argidx < args.size(); argidx++)
+ if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_93))
+ log_cmd_error("Reading `%s' in VHDL_93 mode failed.\n", args[argidx].c_str());
+ return;
+ }
+
+ if (args.size() > 1 && args[1] == "-vhdl2k") {
+ vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
+ for (size_t argidx = 2; argidx < args.size(); argidx++)
+ if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_2K))
+ log_cmd_error("Reading `%s' in VHDL_2K mode failed.\n", args[argidx].c_str());
+ return;
+ }
+
+ if (args.size() > 1 && args[1] == "-vhdl2008") {
+ vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str());
+ for (size_t argidx = 2; argidx < args.size(); argidx++)
+ if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_2008))
+ log_cmd_error("Reading `%s' in VHDL_2008 mode failed.\n", args[argidx].c_str());
+ return;
+ }
+
+ if (args.size() > 1 && args[1] == "-import")
+ {
+ std::set<Netlist*> nl_todo, nl_done;
+ bool mode_all = false, mode_gates = false;
+
+ size_t argidx = 2;
+ for (; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-all") {
+ mode_all = true;
+ continue;
+ }
+ if (args[argidx] == "-gates") {
+ mode_gates = true;
+ continue;
+ }
+ break;
+ }
+
+ if (argidx > args.size() && args[argidx].substr(0, 1) == "-")
+ cmd_error(args, argidx, "unknown option");
+
+ if (mode_all)
+ {
+ if (argidx != args.size())
+ log_cmd_error("Got -all and an explicit list of top modules.\n");
+
+ MapIter m1, m2, m3;
+ VeriModule *mod;
+ FOREACH_VERILOG_MODULE(m1, mod)
+ args.push_back(mod->Name());
+
+ VhdlLibrary *lib;
+ VhdlPrimaryUnit *primunit;
+ FOREACH_VHDL_LIBRARY(m1, lib)
+ FOREACH_VHDL_PRIMARY_UNIT(lib, m2, primunit) {
+ if (primunit->IsPackageDecl())
+ continue;
+ args.push_back(primunit->Name());
+ }
+ }
+ else
+ if (argidx == args.size())
+ log_cmd_error("No top module specified.\n");
+
+ for (; argidx < args.size(); argidx++) {
+ if (veri_file::GetModule(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 {
+ 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());
+ }
+ }
+
+ while (!nl_todo.empty()) {
+ Netlist *nl = *nl_todo.begin();
+ if (nl_done.count(nl) == 0)
+ import_netlist(design, nl, nl_todo, mode_gates);
+ nl_todo.erase(nl);
+ nl_done.insert(nl);
+ }
+
+ Libset::Reset();
+ return;
+ }
+
+ log_cmd_error("Missing or unsupported mode parameter.\n");
+ }
+#else /* YOSYS_ENABLE_VERIFIC */
+ virtual void execute(std::vector<std::string>, RTLIL::Design *) {
+ log_cmd_error("This version of Yosys is built without Verific support.\n");
+ }
+#endif
+} VerificPass;
+
+YOSYS_NAMESPACE_END
+
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc
index 5586b4cc..49eb320e 100644
--- a/frontends/verilog/Makefile.inc
+++ b/frontends/verilog/Makefile.inc
@@ -5,13 +5,13 @@ GENFILES += frontends/verilog/parser.output
GENFILES += frontends/verilog/lexer.cc
frontends/verilog/parser.tab.cc: frontends/verilog/parser.y
- bison -d -r all -b frontends/verilog/parser frontends/verilog/parser.y
- mv frontends/verilog/parser.tab.c frontends/verilog/parser.tab.cc
+ $(P) bison -d -r all -b frontends/verilog/parser frontends/verilog/parser.y
+ $(Q) mv frontends/verilog/parser.tab.c frontends/verilog/parser.tab.cc
frontends/verilog/parser.tab.h: frontends/verilog/parser.tab.cc
frontends/verilog/lexer.cc: frontends/verilog/lexer.l
- flex -o frontends/verilog/lexer.cc frontends/verilog/lexer.l
+ $(P) flex -o frontends/verilog/lexer.cc frontends/verilog/lexer.l
OBJS += frontends/verilog/parser.tab.o
OBJS += frontends/verilog/lexer.o
diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
index c95ce5dc..a81e3010 100644
--- a/frontends/verilog/const2ast.cc
+++ b/frontends/verilog/const2ast.cc
@@ -36,10 +36,11 @@
#include "verilog_frontend.h"
#include "kernel/log.h"
-#include <assert.h>
#include <string.h>
#include <math.h>
+YOSYS_NAMESPACE_BEGIN
+
using namespace AST;
// divide an arbitrary length decimal number by two and return the rest
@@ -47,11 +48,13 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
{
int carry = 0;
for (size_t i = 0; i < digits.size(); i++) {
- assert(digits[i] < 10);
+ log_assert(digits[i] < 10);
digits[i] += carry * 10;
carry = digits[i] % 2;
digits[i] /= 2;
}
+ while (!digits.empty() && !digits.front())
+ digits.erase(digits.begin());
return carry;
}
@@ -90,10 +93,15 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
if (base == 10) {
data.clear();
- if (len_in_bits < 0)
- len_in_bits = ceil(digits.size()/log10(2));
- for (int i = 0; i < len_in_bits; i++)
- data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
+ if (len_in_bits < 0) {
+ while (!digits.empty())
+ data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
+ while (data.size() < 32)
+ data.push_back(RTLIL::S0);
+ } else {
+ for (int i = 0; i < len_in_bits; i++)
+ data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
+ }
return;
}
@@ -151,20 +159,24 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
str = code.c_str();
char *endptr;
- long intval = strtol(str, &endptr, 10);
+ long len_in_bits = strtol(str, &endptr, 10);
+
+ // Simple base-10 integer
+ if (*endptr == 0) {
+ std::vector<RTLIL::State> data;
+ my_strtobin(data, str, -1, 10, case_type);
+ if (data.back() == RTLIL::S1)
+ data.push_back(RTLIL::S0);
+ return AstNode::mkconst_bits(data, true);
+ }
- // Simple 32 bit integer
- if (*endptr == 0)
- return AstNode::mkconst_int(intval, true);
-
// unsized constant
if (str == endptr)
- intval = -1;
+ len_in_bits = -1;
// The "<bits>'s?[bodh]<digits>" syntax
if (*endptr == '\'')
{
- int len_in_bits = intval;
std::vector<RTLIL::State> data;
bool is_signed = false;
if (*(endptr+1) == 's') {
@@ -188,9 +200,17 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
default:
return NULL;
}
+ if (len_in_bits < 0) {
+ if (is_signed && data.back() == RTLIL::S1)
+ data.push_back(RTLIL::S0);
+ while (data.size() < 32)
+ data.push_back(RTLIL::S0);
+ }
return AstNode::mkconst_bits(data, is_signed);
}
return NULL;
}
+YOSYS_NAMESPACE_END
+
diff --git a/frontends/verilog/lexer.l b/frontends/verilog/lexer.l
index 81167cf4..c9302aba 100644
--- a/frontends/verilog/lexer.l
+++ b/frontends/verilog/lexer.l
@@ -34,18 +34,37 @@
%{
+#ifdef __clang__
+// bison generates code using the 'register' storage class specifier
+#pragma clang diagnostic ignored "-Wdeprecated-register"
+#endif
+
#include "kernel/log.h"
#include "verilog_frontend.h"
#include "frontends/ast/ast.h"
#include "parser.tab.h"
+USING_YOSYS_NAMESPACE
using namespace AST;
using namespace VERILOG_FRONTEND;
+YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND {
std::vector<std::string> fn_stack;
std::vector<int> ln_stack;
}
+YOSYS_NAMESPACE_END
+
+#define SV_KEYWORD(_tok) \
+ if (sv_mode) return _tok; \
+ log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\
+ "recognized unless read_verilog is called with -sv!\n", yytext, \
+ AST::current_filename.c_str(), frontend_verilog_yyget_lineno()); \
+ frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); \
+ return TOK_ID;
+
+#define YY_INPUT(buf,result,max_size) \
+ result = lexin->readsome(buf, max_size);
%}
@@ -58,29 +77,53 @@ namespace VERILOG_FRONTEND {
%x STRING
%x SYNOPSYS_TRANSLATE_OFF
%x SYNOPSYS_FLAGS
+%x IMPORT_DPI
%%
-"`file_push "[^\n]* {
+<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_push "[^\n]* {
fn_stack.push_back(current_filename);
ln_stack.push_back(frontend_verilog_yyget_lineno());
current_filename = yytext+11;
frontend_verilog_yyset_lineno(0);
}
-"`file_pop"[^\n]*\n {
+<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_pop"[^\n]*\n {
current_filename = fn_stack.back();
fn_stack.pop_back();
frontend_verilog_yyset_lineno(ln_stack.back());
ln_stack.pop_back();
}
+<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`line"[ \t]+[^ \t\r\n]+[ \t]+\"[^ \r\n]+\"[^\r\n]*\n {
+ char *p = yytext + 5;
+ while (*p == ' ' || *p == '\t') p++;
+ frontend_verilog_yyset_lineno(atoi(p));
+ while (*p && *p != ' ' && *p != '\t') p++;
+ while (*p == ' ' || *p == '\t') p++;
+ char *q = *p ? p + 1 : p;
+ while (*q && *q != '"') q++;
+ current_filename = std::string(p).substr(1, q-p-1);
+}
+
"`file_notfound "[^\n]* {
log_error("Can't open include file `%s'!\n", yytext + 15);
}
"`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */
+"`default_nettype"[ \t]+[^ \t\r\n/]+ {
+ char *p = yytext;
+ while (*p != 0 && *p != ' ' && *p != '\t') p++;
+ while (*p == ' ' || *p == '\t') p++;
+ if (!strcmp(p, "none"))
+ VERILOG_FRONTEND::default_nettype_wire = false;
+ else if (!strcmp(p, "wire"))
+ VERILOG_FRONTEND::default_nettype_wire = true;
+ else
+ frontend_verilog_yyerror("Unsupported default nettype: %s", p);
+}
+
"`"[a-zA-Z_$][a-zA-Z0-9_$]* {
frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext);
}
@@ -112,8 +155,17 @@ namespace VERILOG_FRONTEND {
"default" { return TOK_DEFAULT; }
"generate" { return TOK_GENERATE; }
"endgenerate" { return TOK_ENDGENERATE; }
+"while" { return TOK_WHILE; }
+"repeat" { return TOK_REPEAT; }
-"assert"([ \t\r\n]+"property")? { return TOK_ASSERT; }
+"always_comb" { SV_KEYWORD(TOK_ALWAYS); }
+"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
+"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
+
+"assert" { SV_KEYWORD(TOK_ASSERT); }
+"property" { SV_KEYWORD(TOK_PROPERTY); }
+"logic" { SV_KEYWORD(TOK_REG); }
+"bit" { SV_KEYWORD(TOK_REG); }
"input" { return TOK_INPUT; }
"output" { return TOK_OUTPUT; }
@@ -123,6 +175,7 @@ namespace VERILOG_FRONTEND {
"integer" { return TOK_INTEGER; }
"signed" { return TOK_SIGNED; }
"genvar" { return TOK_GENVAR; }
+"real" { return TOK_REAL; }
[0-9]+ {
frontend_verilog_yylval.string = new std::string(yytext);
@@ -134,6 +187,16 @@ namespace VERILOG_FRONTEND {
return TOK_CONST;
}
+[0-9][0-9_]*\.[0-9][0-9_]*([eE][-+]?[0-9_]+)? {
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_REALVAL;
+}
+
+[0-9][0-9_]*[eE][-+]?[0-9_]+ {
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_REALVAL;
+}
+
\" { BEGIN(STRING); }
<STRING>\\. { yymore(); }
<STRING>\" {
@@ -215,6 +278,27 @@ supply1 { return TOK_SUPPLY1; }
<SYNOPSYS_FLAGS>. /* ignore everything else */
<SYNOPSYS_FLAGS>"*/" { BEGIN(0); }
+import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
+ BEGIN(IMPORT_DPI);
+ return TOK_DPI_FUNCTION;
+}
+
+<IMPORT_DPI>[a-zA-Z_$][a-zA-Z0-9_$]* {
+ frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
+ return TOK_ID;
+}
+
+<IMPORT_DPI>[ \t\r\n] /* ignore whitespaces */
+
+<IMPORT_DPI>";" {
+ BEGIN(0);
+ return *yytext;
+}
+
+<IMPORT_DPI>. {
+ return *yytext;
+}
+
"\\"[^ \t\r\n]+ {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_ID;
diff --git a/frontends/verilog/parser.y b/frontends/verilog/parser.y
index 5b6bf58c..a9f69a49 100644
--- a/frontends/verilog/parser.y
+++ b/frontends/verilog/parser.y
@@ -35,13 +35,15 @@
%{
#include <list>
-#include <assert.h>
+#include <string.h>
#include "verilog_frontend.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
using namespace AST;
using namespace VERILOG_FRONTEND;
+YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND {
int port_counter;
std::map<std::string, int> port_stubs;
@@ -53,7 +55,12 @@ namespace VERILOG_FRONTEND {
struct AstNode *current_ast, *current_ast_mod;
int current_function_or_task_port_id;
std::vector<char> case_type_stack;
+ bool do_not_require_port_stubs;
+ bool default_nettype_wire;
+ bool sv_mode;
+ std::istream *lexin;
}
+YOSYS_NAMESPACE_END
static void append_attr(AstNode *ast, std::map<std::string, AstNode*> *al)
{
@@ -83,30 +90,31 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%}
-%name-prefix="frontend_verilog_yy"
+%name-prefix "frontend_verilog_yy"
%union {
std::string *string;
- struct AstNode *ast;
- std::map<std::string, AstNode*> *al;
+ struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
+ std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al;
bool boolean;
}
-%token <string> TOK_STRING TOK_ID TOK_CONST TOK_PRIMITIVE
+%token <string> TOK_STRING TOK_ID TOK_CONST TOK_REALVAL TOK_PRIMITIVE
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
-%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR
-%token TOK_POSEDGE TOK_NEGEDGE TOK_OR
+%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
+%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK
-%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR
+%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
+%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_PROPERTY
-%type <ast> wire_type range non_opt_range expr basic_expr concat_list rvalue lvalue lvalue_concat_list
+%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
+%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
%type <string> opt_label tok_prim_wrapper hierarchical_id
%type <boolean> opt_signed
%type <al> attr
@@ -130,14 +138,21 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%%
-input:
- module input |
- defattr input |
- /* empty */ {
- for (auto &it : default_attr_list)
- delete it.second;
- default_attr_list.clear();
- };
+input: {
+ ast_stack.push_back(current_ast);
+} design {
+ ast_stack.pop_back();
+ log_assert(SIZE(ast_stack) == 0);
+ for (auto &it : default_attr_list)
+ delete it.second;
+ default_attr_list.clear();
+};
+
+design:
+ module design |
+ defattr design |
+ task_func_decl design |
+ /* empty */;
attr:
{
@@ -205,10 +220,11 @@ hierarchical_id:
module:
attr TOK_MODULE TOK_ID {
+ do_not_require_port_stubs = false;
AstNode *mod = new AstNode(AST_MODULE);
- current_ast->children.push_back(mod);
- current_ast_mod = mod;
+ ast_stack.back()->children.push_back(mod);
ast_stack.push_back(mod);
+ current_ast_mod = mod;
port_stubs.clear();
port_counter = 0;
mod->str = *$3;
@@ -219,7 +235,8 @@ module:
frontend_verilog_yyerror("Missing details for module port `%s'.",
port_stubs.begin()->first.c_str());
ast_stack.pop_back();
- assert(ast_stack.size() == 0);
+ log_assert(ast_stack.size() == 1);
+ current_ast_mod = NULL;
};
module_para_opt:
@@ -288,7 +305,10 @@ module_arg:
ast_stack.back()->children.push_back(node);
append_attr(node, $1);
delete $4;
- } module_arg_opt_assignment;
+ } module_arg_opt_assignment |
+ '.' '.' '.' {
+ do_not_require_port_stubs = true;
+ };
wire_type:
{
@@ -320,6 +340,7 @@ wire_type_token:
astbuf3->is_reg = true;
astbuf3->range_left = 31;
astbuf3->range_right = 0;
+ astbuf3->is_signed = true;
} |
TOK_GENVAR {
astbuf3->type = AST_GENVAR;
@@ -352,6 +373,15 @@ non_opt_range:
$$->children.push_back($2);
};
+non_opt_multirange:
+ non_opt_range non_opt_range {
+ $$ = new AstNode(AST_MULTIRANGE, $1, $2);
+ } |
+ non_opt_multirange non_opt_range {
+ $$ = $1;
+ $$->children.push_back($2);
+ };
+
range:
non_opt_range {
$$ = $1;
@@ -360,44 +390,120 @@ range:
$$ = NULL;
};
+range_or_multirange:
+ range { $$ = $1; } |
+ non_opt_multirange { $$ = $1; };
+
+range_or_signed_int:
+ range {
+ $$ = $1;
+ } |
+ TOK_INTEGER {
+ $$ = new AstNode(AST_RANGE);
+ $$->children.push_back(AstNode::mkconst_int(31, true));
+ $$->children.push_back(AstNode::mkconst_int(0, true));
+ $$->is_signed = true;
+ };
+
module_body:
module_body module_body_stmt |
+ /* the following line makes the generate..endgenrate keywords optional */
+ module_body gen_stmt |
/* empty */;
module_body_stmt:
task_func_decl | param_decl | localparam_decl | defparam_decl | wire_decl | assign_stmt | cell_stmt |
- always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert;
+ always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property;
task_func_decl:
- TOK_TASK TOK_ID ';' {
+ attr TOK_DPI_FUNCTION TOK_ID TOK_ID {
+ current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$3), AstNode::mkconst_str(*$4));
+ current_function_or_task->str = *$4;
+ append_attr(current_function_or_task, $1);
+ ast_stack.back()->children.push_back(current_function_or_task);
+ delete $3;
+ delete $4;
+ } opt_dpi_function_args ';' {
+ current_function_or_task = NULL;
+ } |
+ attr TOK_DPI_FUNCTION TOK_ID '=' TOK_ID TOK_ID {
+ current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$5), AstNode::mkconst_str(*$3));
+ current_function_or_task->str = *$6;
+ append_attr(current_function_or_task, $1);
+ ast_stack.back()->children.push_back(current_function_or_task);
+ delete $3;
+ delete $5;
+ delete $6;
+ } opt_dpi_function_args ';' {
+ current_function_or_task = NULL;
+ } |
+ attr TOK_DPI_FUNCTION TOK_ID ':' TOK_ID '=' TOK_ID TOK_ID {
+ current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$7), AstNode::mkconst_str(*$3 + ":" + RTLIL::unescape_id(*$5)));
+ current_function_or_task->str = *$8;
+ append_attr(current_function_or_task, $1);
+ ast_stack.back()->children.push_back(current_function_or_task);
+ delete $3;
+ delete $5;
+ delete $7;
+ delete $8;
+ } opt_dpi_function_args ';' {
+ current_function_or_task = NULL;
+ } |
+ attr TOK_TASK TOK_ID ';' {
current_function_or_task = new AstNode(AST_TASK);
- current_function_or_task->str = *$2;
+ current_function_or_task->str = *$3;
+ append_attr(current_function_or_task, $1);
ast_stack.back()->children.push_back(current_function_or_task);
ast_stack.push_back(current_function_or_task);
current_function_or_task_port_id = 1;
- delete $2;
+ delete $3;
} task_func_body TOK_ENDTASK {
current_function_or_task = NULL;
ast_stack.pop_back();
} |
- TOK_FUNCTION opt_signed range TOK_ID ';' {
+ attr TOK_FUNCTION opt_signed range_or_signed_int TOK_ID ';' {
current_function_or_task = new AstNode(AST_FUNCTION);
- current_function_or_task->str = *$4;
+ current_function_or_task->str = *$5;
+ append_attr(current_function_or_task, $1);
ast_stack.back()->children.push_back(current_function_or_task);
ast_stack.push_back(current_function_or_task);
AstNode *outreg = new AstNode(AST_WIRE);
- if ($3 != NULL)
- outreg->children.push_back($3);
- outreg->str = *$4;
- outreg->is_signed = $2;
+ outreg->str = *$5;
+ outreg->is_signed = $3;
+ if ($4 != NULL) {
+ outreg->children.push_back($4);
+ outreg->is_signed = $3 || $4->is_signed;
+ $4->is_signed = false;
+ }
current_function_or_task->children.push_back(outreg);
current_function_or_task_port_id = 1;
- delete $4;
+ delete $5;
} task_func_body TOK_ENDFUNCTION {
current_function_or_task = NULL;
ast_stack.pop_back();
};
+dpi_function_arg:
+ TOK_ID TOK_ID {
+ current_function_or_task->children.push_back(AstNode::mkconst_str(*$1));
+ delete $1;
+ delete $2;
+ } |
+ TOK_ID {
+ current_function_or_task->children.push_back(AstNode::mkconst_str(*$1));
+ delete $1;
+ };
+
+opt_dpi_function_args:
+ '(' dpi_function_args ')' |
+ /* empty */;
+
+dpi_function_args:
+ dpi_function_args ',' dpi_function_arg |
+ dpi_function_args ',' |
+ dpi_function_arg |
+ /* empty */;
+
opt_signed:
TOK_SIGNED {
$$ = true;
@@ -422,6 +528,14 @@ param_integer:
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));
+ astbuf1->is_signed = true;
+ } | /* empty */;
+
+param_real:
+ TOK_REAL {
+ if (astbuf1->children.size() != 1)
+ frontend_verilog_yyerror("Syntax error.");
+ astbuf1->children.push_back(new AstNode(AST_REALVALUE));
} | /* empty */;
param_range:
@@ -437,7 +551,7 @@ param_decl:
TOK_PARAMETER {
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
- } param_signed param_integer param_range param_decl_list ';' {
+ } param_signed param_integer param_real param_range param_decl_list ';' {
delete astbuf1;
};
@@ -445,7 +559,7 @@ localparam_decl:
TOK_LOCALPARAM {
astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
- } param_signed param_integer param_range param_decl_list ';' {
+ } param_signed param_integer param_real param_range param_decl_list ';' {
delete astbuf1;
};
@@ -533,7 +647,7 @@ wire_name_and_opt_assign:
};
wire_name:
- TOK_ID range {
+ TOK_ID range_or_multirange {
AstNode *node = astbuf1->clone();
node->str = *$1;
append_attr_clone(node, albuf);
@@ -552,6 +666,9 @@ wire_name:
node->children.push_back($2);
}
if (current_function_or_task == NULL) {
+ if (do_not_require_port_stubs && (node->is_input || node->is_output) && port_stubs.count(*$1) == 0) {
+ port_stubs[*$1] = ++port_counter;
+ }
if (port_stubs.count(*$1) != 0) {
if (!node->is_input && !node->is_output)
frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $1->c_str());
@@ -563,12 +680,11 @@ wire_name:
if (node->is_input || node->is_output)
frontend_verilog_yyerror("Module port `%s' is not declared in module header.", $1->c_str());
}
- ast_stack.back()->children.push_back(node);
} else {
if (node->is_input || node->is_output)
node->port_id = current_function_or_task_port_id++;
- current_function_or_task->children.push_back(node);
}
+ ast_stack.back()->children.push_back(node);
delete $1;
};
@@ -621,6 +737,13 @@ single_cell:
astbuf2->str = *$1;
delete $1;
ast_stack.back()->children.push_back(astbuf2);
+ } '(' cell_port_list ')' |
+ TOK_ID non_opt_range {
+ astbuf2 = astbuf1->clone();
+ if (astbuf2->type != AST_PRIMITIVE)
+ astbuf2->str = *$1;
+ delete $1;
+ ast_stack.back()->children.push_back(new AstNode(AST_CELLARRAY, $2, astbuf2));
} '(' cell_port_list ')';
prim_list:
@@ -753,6 +876,11 @@ assert:
ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $3));
};
+assert_property:
+ TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $4));
+ };
+
simple_behavioral_stmt:
lvalue '=' expr {
AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3);
@@ -808,6 +936,32 @@ behavioral_stmt:
ast_stack.pop_back();
ast_stack.pop_back();
} |
+ attr TOK_WHILE '(' expr ')' {
+ AstNode *node = new AstNode(AST_WHILE);
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ append_attr(node, $1);
+ AstNode *block = new AstNode(AST_BLOCK);
+ ast_stack.back()->children.push_back($4);
+ ast_stack.back()->children.push_back(block);
+ ast_stack.push_back(block);
+ } behavioral_stmt {
+ ast_stack.pop_back();
+ ast_stack.pop_back();
+ } |
+ attr TOK_REPEAT '(' expr ')' {
+ AstNode *node = new AstNode(AST_REPEAT);
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ append_attr(node, $1);
+ AstNode *block = new AstNode(AST_BLOCK);
+ ast_stack.back()->children.push_back($4);
+ ast_stack.back()->children.push_back(block);
+ ast_stack.push_back(block);
+ } behavioral_stmt {
+ ast_stack.pop_back();
+ ast_stack.pop_back();
+ } |
attr TOK_IF '(' expr ')' {
AstNode *node = new AstNode(AST_CASE);
AstNode *block = new AstNode(AST_BLOCK);
@@ -934,8 +1088,8 @@ rvalue:
$$->str = *$1;
delete $1;
} |
- hierarchical_id non_opt_range non_opt_range {
- $$ = new AstNode(AST_IDENTIFIER, $2, $3);
+ hierarchical_id non_opt_multirange {
+ $$ = new AstNode(AST_IDENTIFIER, $2);
$$->str = *$1;
delete $1;
};
@@ -976,9 +1130,12 @@ single_arg:
};
module_gen_body:
- module_gen_body gen_stmt |
+ module_gen_body gen_stmt_or_module_body_stmt |
/* empty */;
+gen_stmt_or_module_body_stmt:
+ gen_stmt | module_body_stmt;
+
// this production creates the obligatory if-else shift/reduce conflict
gen_stmt:
TOK_FOR '(' {
@@ -1017,15 +1174,14 @@ gen_stmt:
if ($6 != NULL)
delete $6;
ast_stack.pop_back();
- } |
- module_body_stmt;
+ };
gen_stmt_block:
{
AstNode *node = new AstNode(AST_GENBLOCK);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
- } gen_stmt {
+ } gen_stmt_or_module_body_stmt {
ast_stack.pop_back();
};
@@ -1073,12 +1229,30 @@ basic_expr:
delete $1;
delete $2;
} |
+ TOK_CONST TOK_CONST {
+ $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
+ if ($$ == NULL || (*$2)[0] != '\'')
+ log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str());
+ delete $1;
+ delete $2;
+ } |
TOK_CONST {
$$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
if ($$ == NULL)
log_error("Value conversion failed: `%s'\n", $1->c_str());
delete $1;
} |
+ TOK_REALVAL {
+ $$ = new AstNode(AST_REALVALUE);
+ char *p = strdup($1->c_str()), *q;
+ for (int i = 0, j = 0; !p[j]; j++)
+ if (p[j] != '_')
+ p[i++] = p[j], p[i] = 0;
+ $$->realvalue = strtod(p, &q);
+ log_assert(*q == 0);
+ delete $1;
+ free(p);
+ } |
TOK_STRING {
$$ = AstNode::mkconst_str(*$1);
delete $1;
diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc
index db53e8c6..f8343321 100644
--- a/frontends/verilog/preproc.cc
+++ b/frontends/verilog/preproc.cc
@@ -37,7 +37,8 @@
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
-#include <assert.h>
+
+YOSYS_NAMESPACE_BEGIN
static std::list<std::string> output_code;
static std::list<std::string> input_buffer;
@@ -65,7 +66,7 @@ static char next_char()
if (input_buffer.empty())
return 0;
- assert(input_buffer_charp <= input_buffer.front().size());
+ log_assert(input_buffer_charp <= input_buffer.front().size());
if (input_buffer_charp == input_buffer.front().size()) {
input_buffer_charp = 0;
input_buffer.pop_front();
@@ -130,6 +131,12 @@ static std::string next_token(bool pass_newline = false)
token += ch;
}
}
+ if (token == "\"\"" && (ch = next_char()) != 0) {
+ if (ch == '"')
+ token += ch;
+ else
+ return_char(ch);
+ }
}
else if (ch == '/')
{
@@ -186,7 +193,7 @@ static std::string next_token(bool pass_newline = false)
return token;
}
-static void input_file(FILE *f, std::string filename)
+static void input_file(std::istream &f, std::string filename)
{
char buffer[513];
int rc;
@@ -195,14 +202,14 @@ static void input_file(FILE *f, std::string filename)
auto it = input_buffer.begin();
input_buffer.insert(it, "`file_push " + filename + "\n");
- while ((rc = fread(buffer, 1, sizeof(buffer)-1, f)) > 0) {
+ while ((rc = f.readsome(buffer, sizeof(buffer)-1)) > 0) {
buffer[rc] = 0;
input_buffer.insert(it, buffer);
}
- input_buffer.insert(it, "`file_pop\n");
+ input_buffer.insert(it, "\n`file_pop\n");
}
-std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs)
+std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs)
{
std::set<std::string> defines_with_args;
std::map<std::string, std::string> defines_map(pre_defines_map);
@@ -281,27 +288,28 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m
else
fn = fn.substr(0, pos) + fn.substr(pos+1);
}
- FILE *fp = fopen(fn.c_str(), "r");
- if (fp == NULL && fn.size() > 0 && fn[0] != '/' && filename.find('/') != std::string::npos) {
+ std::ifstream ff;
+ ff.clear();
+ ff.open(fn.c_str());
+ if (ff.fail() && fn.size() > 0 && fn[0] != '/' && filename.find('/') != std::string::npos) {
// if the include file was not found, it is not given with an absolute path, and the
// currently read file is given with a path, then try again relative to its directory
- std::string fn2 = filename.substr(0, filename.rfind('/')+1) + fn;
- fp = fopen(fn2.c_str(), "r");
+ ff.clear();
+ ff.open(filename.substr(0, filename.rfind('/')+1) + fn);
}
- if (fp == NULL && fn.size() > 0 && fn[0] != '/') {
+ if (ff.fail() && fn.size() > 0 && fn[0] != '/') {
// if the include file was not found and it is not given with an absolute path, then
// search it in the include path
for (auto incdir : include_dirs) {
- std::string fn2 = incdir + '/' + fn;
- fp = fopen(fn2.c_str(), "r");
- if (fp != NULL) break;
+ ff.clear();
+ ff.open(incdir + '/' + fn);
+ if (!ff.fail()) break;
}
}
- if (fp != NULL) {
- input_file(fp, fn);
- fclose(fp);
- } else
- output_code.push_back("`file_notfound " + fn + "\n");
+ if (ff.fail())
+ output_code.push_back("`file_notfound " + fn);
+ else
+ input_file(ff, fn);
continue;
}
@@ -310,12 +318,17 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m
std::map<std::string, int> args;
skip_spaces();
name = next_token(true);
+ bool here_doc_mode = false;
int newline_count = 0;
int state = 0;
if (skip_spaces() != "")
state = 3;
while (!tok.empty()) {
tok = next_token();
+ if (tok == "\"\"\"") {
+ here_doc_mode = !here_doc_mode;
+ continue;
+ }
if (state == 0 && tok == "(") {
state = 1;
skip_spaces();
@@ -332,9 +345,14 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m
if (state != 2)
state = 3;
if (tok == "\n") {
- return_char('\n');
- break;
- }
+ if (here_doc_mode) {
+ value += " ";
+ newline_count++;
+ } else {
+ return_char('\n');
+ break;
+ }
+ } else
if (tok == "\\") {
char ch = next_char();
if (ch == '\n') {
@@ -373,7 +391,6 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m
}
if (tok == "`timescale") {
- std::string name;
skip_spaces();
while (!tok.empty() && tok != "\n")
tok = next_token(true);
@@ -429,3 +446,5 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m
return output;
}
+YOSYS_NAMESPACE_END
+
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
index c70d6f30..c6d4a0b7 100644
--- a/frontends/verilog/verilog_frontend.cc
+++ b/frontends/verilog/verilog_frontend.cc
@@ -27,13 +27,11 @@
*/
#include "verilog_frontend.h"
-#include "kernel/register.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
#include "libs/sha1/sha1.h"
-#include <sstream>
#include <stdarg.h>
-#include <assert.h>
+YOSYS_NAMESPACE_BEGIN
using namespace VERILOG_FRONTEND;
// use the Verilog bison/flex parser to generate an AST and use AST::process() to convert it to RTLIL
@@ -47,11 +45,15 @@ struct VerilogFrontend : public Frontend {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" read_verilog [filename]\n");
+ log(" read_verilog [options] [filename]\n");
log("\n");
log("Load modules from a verilog file to the current design. A large subset of\n");
log("Verilog-2005 is supported.\n");
log("\n");
+ log(" -sv\n");
+ log(" enable support for SystemVerilog features. (only a small subset\n");
+ log(" of SystemVerilog is supported)\n");
+ log("\n");
log(" -dump_ast1\n");
log(" dump abstract syntax tree (before simplification)\n");
log("\n");
@@ -106,6 +108,11 @@ struct VerilogFrontend : public Frontend {
log(" ignore re-definitions of modules. (the default behavior is to\n");
log(" create an error message.)\n");
log("\n");
+ log(" -defer\n");
+ log(" only read the abstract syntax tree and defer actual compilation\n");
+ log(" to a later 'hierarchy' command. Useful in cases where the default\n");
+ log(" parameters of modules yield invalid or not synthesizable code.\n");
+ log("\n");
log(" -setattr <attribute_name>\n");
log(" set the specified attribute (to the value 1) on all loaded modules\n");
log("\n");
@@ -120,8 +127,13 @@ struct VerilogFrontend : public Frontend {
log("The command 'verilog_defaults' can be used to register default options for\n");
log("subsequent calls to 'read_verilog'.\n");
log("\n");
+ log("Note that the Verilog frontend does a pretty good job of processing valid\n");
+ log("verilog input, but has not very good error reporting. It generally is\n");
+ log("recommended to use a simulator (for example icarus verilog) for checking\n");
+ log("the syntax of the code, rather than to rely on read_verilog for that.\n");
+ log("\n");
}
- virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
bool flag_dump_ast1 = false;
bool flag_dump_ast2 = false;
@@ -135,10 +147,13 @@ struct VerilogFrontend : public Frontend {
bool flag_noopt = false;
bool flag_icells = false;
bool flag_ignore_redef = false;
+ bool flag_defer = false;
std::map<std::string, std::string> defines_map;
std::list<std::string> include_dirs;
std::list<std::string> attributes;
+
frontend_verilog_yydebug = false;
+ sv_mode = false;
log_header("Executing Verilog-2005 frontend.\n");
@@ -147,6 +162,10 @@ struct VerilogFrontend : public Frontend {
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
+ if (arg == "-sv") {
+ sv_mode = true;
+ continue;
+ }
if (arg == "-dump_ast1") {
flag_dump_ast1 = true;
continue;
@@ -199,6 +218,10 @@ struct VerilogFrontend : public Frontend {
flag_ignore_redef = true;
continue;
}
+ if (arg == "-defer") {
+ flag_defer = true;
+ continue;
+ }
if (arg == "-setattr" && argidx+1 < args.size()) {
attributes.push_back(RTLIL::escape_id(args[++argidx]));
continue;
@@ -241,33 +264,34 @@ struct VerilogFrontend : public Frontend {
AST::get_line_num = &frontend_verilog_yyget_lineno;
current_ast = new AST::AstNode(AST::AST_DESIGN);
+ default_nettype_wire = true;
- FILE *fp = f;
+ lexin = f;
std::string code_after_preproc;
if (!flag_nopp) {
- code_after_preproc = frontend_verilog_preproc(f, filename, defines_map, include_dirs);
+ code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, include_dirs);
if (flag_ppdump)
log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str());
- fp = fmemopen((void*)code_after_preproc.c_str(), code_after_preproc.size(), "r");
+ lexin = new std::istringstream(code_after_preproc);
}
frontend_verilog_yyset_lineno(1);
- frontend_verilog_yyrestart(fp);
+ frontend_verilog_yyrestart(NULL);
frontend_verilog_yyparse();
frontend_verilog_yylex_destroy();
for (auto &child : current_ast->children) {
- log_assert(child->type == AST::AST_MODULE);
- for (auto &attr : attributes)
- if (child->attributes.count(attr) == 0)
- child->attributes[attr] = AST::AstNode::mkconst_int(1, false);
+ if (child->type == AST::AST_MODULE)
+ for (auto &attr : attributes)
+ if (child->attributes.count(attr) == 0)
+ child->attributes[attr] = AST::AstNode::mkconst_int(1, false);
}
- AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef);
+ AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
if (!flag_nopp)
- fclose(fp);
+ delete lexin;
delete current_ast;
current_ast = NULL;
@@ -350,3 +374,5 @@ struct VerilogDefaults : public Pass {
}
} VerilogDefaults;
+YOSYS_NAMESPACE_END
+
diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h
index 8b4fae6e..af6495f8 100644
--- a/frontends/verilog/verilog_frontend.h
+++ b/frontends/verilog/verilog_frontend.h
@@ -29,12 +29,14 @@
#ifndef VERILOG_FRONTEND_H
#define VERILOG_FRONTEND_H
-#include "kernel/rtlil.h"
+#include "kernel/yosys.h"
#include "frontends/ast/ast.h"
#include <stdio.h>
#include <stdint.h>
#include <list>
+YOSYS_NAMESPACE_BEGIN
+
namespace VERILOG_FRONTEND
{
// this variable is set to a new AST_DESIGN node and then filled with the AST by the bison parser
@@ -42,10 +44,21 @@ namespace VERILOG_FRONTEND
// this function converts a Verilog constant to an AST_CONSTANT node
AST::AstNode *const2ast(std::string code, char case_type = 0);
+
+ // state of `default_nettype
+ extern bool default_nettype_wire;
+
+ // running in SystemVerilog mode
+ extern bool sv_mode;
+
+ // lexer input stream
+ extern std::istream *lexin;
}
// the pre-processor
-std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs);
+std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs);
+
+YOSYS_NAMESPACE_END
// the usual bison/flex stuff
extern int frontend_verilog_yydebug;
diff --git a/frontends/vhdl2verilog/Makefile.inc b/frontends/vhdl2verilog/Makefile.inc
new file mode 100644
index 00000000..003d89c4
--- /dev/null
+++ b/frontends/vhdl2verilog/Makefile.inc
@@ -0,0 +1 @@
+OBJS += frontends/vhdl2verilog/vhdl2verilog.o
diff --git a/frontends/vhdl2verilog/vhdl2verilog.cc b/frontends/vhdl2verilog/vhdl2verilog.cc
new file mode 100644
index 00000000..b408d621
--- /dev/null
+++ b/frontends/vhdl2verilog/vhdl2verilog.cc
@@ -0,0 +1,196 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
+
+YOSYS_NAMESPACE_BEGIN
+
+struct Vhdl2verilogPass : public Pass {
+ Vhdl2verilogPass() : Pass("vhdl2verilog", "importing VHDL designs using vhdl2verilog") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" vhdl2verilog [options] <vhdl-file>..\n");
+ log("\n");
+ log("This command reads VHDL source files using the 'vhdl2verilog' tool and the\n");
+ log("Yosys Verilog frontend.\n");
+ log("\n");
+ log(" -out <out_file>\n");
+ log(" do not import the vhdl2verilog output. instead write it to the\n");
+ log(" specified file.\n");
+ log("\n");
+ log(" -vhdl2verilog_dir <directory>\n");
+ log(" do use the specified vhdl2verilog installation. this is the directory\n");
+ log(" that contains the setup_env.sh file. when this option is not present,\n");
+ log(" it is assumed that vhdl2verilog is in the PATH environment variable.\n");
+ log("\n");
+ log(" -top <top-entity-name>\n");
+ log(" The name of the top entity. This option is mandatory.\n");
+ log("\n");
+ log("The following options are passed as-is to vhdl2verilog:\n");
+ log("\n");
+ log(" -arch <architecture_name>\n");
+ log(" -unroll_generate\n");
+ log(" -nogenericeval\n");
+ log(" -nouniquify\n");
+ log(" -oldparser\n");
+ log(" -suppress <list>\n");
+ log(" -quiet\n");
+ log(" -nobanner\n");
+ log(" -mapfile <file>\n");
+ log("\n");
+ log("vhdl2verilog can be obtained from:\n");
+ log("http://www.edautils.com/vhdl2verilog.html\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Executing VHDL2VERILOG (importing VHDL designs using vhdl2verilog).\n");
+ log_push();
+
+ std::string out_file, top_entity;
+ std::string vhdl2verilog_dir;
+ std::string extra_opts;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-out" && argidx+1 < args.size()) {
+ out_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-top" && argidx+1 < args.size()) {
+ top_entity = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-vhdl2verilog_dir" && argidx+1 < args.size()) {
+ vhdl2verilog_dir = args[++argidx];
+ continue;
+ }
+ if ((args[argidx] == "-arch" || args[argidx] == "-suppress" || args[argidx] == "-mapfile") && argidx+1 < args.size()) {
+ if (args[argidx] == "-mapfile" && !args[argidx+1].empty() && args[argidx+1][0] != '/') {
+ char pwd[PATH_MAX];
+ if (!getcwd(pwd, sizeof(pwd))) {
+ log_cmd_error("getcwd failed: %s", strerror(errno));
+ log_abort();
+ }
+ args[argidx+1] = pwd + ("/" + args[argidx+1]);
+ }
+ extra_opts += std::string(" ") + args[argidx];
+ extra_opts += std::string(" '") + args[++argidx] + std::string("'");
+ continue;
+ }
+ if (args[argidx] == "-unroll_generate" || args[argidx] == "-nogenericeval" || args[argidx] == "-nouniquify" ||
+ args[argidx] == "-oldparser" || args[argidx] == "-quiet" || args[argidx] == "-nobanner") {
+ extra_opts += std::string(" ") + args[argidx];
+ continue;
+ }
+ break;
+ }
+
+ if (argidx == args.size())
+ cmd_error(args, argidx, "Missing filenames.");
+ if (args[argidx].substr(0, 1) == "-")
+ cmd_error(args, argidx, "Unknown option.");
+ if (top_entity.empty())
+ log_cmd_error("Missing -top option.\n");
+
+ char tempdir_name[] = "/tmp/yosys-vhdl2verilog-XXXXXX";
+ char *p = mkdtemp(tempdir_name);
+ log("Using temp directory %s.\n", tempdir_name);
+ if (p == NULL)
+ log_error("For some reason mkdtemp() failed!\n");
+
+ if (!out_file.empty() && out_file[0] != '/') {
+ char pwd[PATH_MAX];
+ if (!getcwd(pwd, sizeof(pwd))) {
+ log_cmd_error("getcwd failed: %s", strerror(errno));
+ log_abort();
+ }
+ out_file = pwd + ("/" + out_file);
+ }
+
+ FILE *f = fopen(stringf("%s/files.list", tempdir_name).c_str(), "wt");
+ while (argidx < args.size()) {
+ std::string file = args[argidx++];
+ if (file.empty())
+ continue;
+ if (file[0] != '/') {
+ char pwd[PATH_MAX];
+ if (!getcwd(pwd, sizeof(pwd))) {
+ log_cmd_error("getcwd failed: %s", strerror(errno));
+ log_abort();
+ }
+ file = pwd + ("/" + file);
+ }
+ fprintf(f, "%s\n", file.c_str());
+ log("Adding '%s' to the file list.\n", file.c_str());
+ }
+ fclose(f);
+
+ std::string command = "exec 2>&1; ";
+ if (!vhdl2verilog_dir.empty())
+ command += stringf("cd '%s'; . ./setup_env.sh; ", vhdl2verilog_dir.c_str());
+ command += stringf("cd '%s'; vhdl2verilog -out '%s' -filelist files.list -top '%s'%s", tempdir_name,
+ out_file.empty() ? "vhdl2verilog_output.v" : out_file.c_str(), top_entity.c_str(), extra_opts.c_str());
+
+ log("Running '%s'..\n", command.c_str());
+
+ errno = ENOMEM; // popen does not set errno if memory allocation fails, therefore set it by hand
+ f = popen(command.c_str(), "r");
+ if (f == NULL)
+ log_error("Opening pipe to `%s' for reading failed: %s\n", command.c_str(), strerror(errno));
+
+ char logbuf[1024];
+ while (fgets(logbuf, 1024, f) != NULL)
+ log("%s", logbuf);
+
+ int ret = pclose(f);
+ if (ret < 0)
+ log_error("Closing pipe to `%s' failed: %s\n", command.c_str(), strerror(errno));
+ if (WEXITSTATUS(ret) != 0)
+ log_error("Execution of command \"%s\" failed: the shell returned %d\n", command.c_str(), WEXITSTATUS(ret));
+
+ if (out_file.empty()) {
+ std::ifstream ff;
+ ff.open(stringf("%s/vhdl2verilog_output.v", tempdir_name).c_str());
+ if (ff.fail())
+ log_error("Can't open vhdl2verilog output file `vhdl2verilog_output.v'.\n");
+ Frontend::frontend_call(design, &ff, stringf("%s/vhdl2verilog_output.v", tempdir_name), "verilog");
+ }
+
+ log_header("Removing temp directory `%s':\n", tempdir_name);
+ if (system(stringf("rm -rf '%s'", tempdir_name).c_str()) != 0)
+ log_error("Execution of \"rm -rf '%s'\" failed!\n", tempdir_name);
+
+ log_pop();
+ }
+} Vhdl2verilogPass;
+
+YOSYS_NAMESPACE_END
+
diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h
index aaefa50f..91f54593 100644
--- a/kernel/bitpattern.h
+++ b/kernel/bitpattern.h
@@ -31,16 +31,12 @@ struct BitPatternPool
BitPatternPool(RTLIL::SigSpec sig)
{
- width = sig.width;
+ width = sig.size();
if (width > 0) {
std::vector<RTLIL::State> pattern(width);
- sig.optimize();
for (int i = 0; i < width; i++) {
- RTLIL::SigSpec s = sig.extract(i, 1);
- s.optimize();
- assert(s.chunks.size() == 1);
- if (s.chunks[0].wire == NULL && s.chunks[0].data.bits[0] <= RTLIL::State::S1)
- pattern[i] = s.chunks[0].data.bits[0];
+ if (sig[i].wire == NULL && sig[i].data <= RTLIL::State::S1)
+ pattern[i] = sig[i].data;
else
pattern[i] = RTLIL::State::Sa;
}
@@ -61,10 +57,7 @@ struct BitPatternPool
bits_t sig2bits(RTLIL::SigSpec sig)
{
- sig.optimize();
- assert(sig.is_fully_const());
- assert(sig.chunks.size() == 1);
- bits_t bits = sig.chunks[0].data.bits;
+ bits_t bits = sig.as_const().bits;
for (auto &b : bits)
if (b > RTLIL::State::S1)
b = RTLIL::State::Sa;
@@ -73,8 +66,8 @@ struct BitPatternPool
bool match(bits_t a, bits_t b)
{
- assert(int(a.size()) == width);
- assert(int(b.size()) == width);
+ log_assert(int(a.size()) == width);
+ log_assert(int(b.size()) == width);
for (int i = 0; i < width; i++)
if (a[i] <= RTLIL::State::S1 && b[i] <= RTLIL::State::S1 && a[i] != b[i])
return false;
diff --git a/kernel/calc.cc b/kernel/calc.cc
index a56db93a..41179d04 100644
--- a/kernel/calc.cc
+++ b/kernel/calc.cc
@@ -21,21 +21,10 @@
// Schneier, Bruce (1996). Applied Cryptography: Protocols, Algorithms, and Source Code in C,
// Second Edition (2nd ed.). Wiley. ISBN 978-0-471-11709-4, page 244
-#include "kernel/log.h"
-#include "kernel/rtlil.h"
+#include "kernel/yosys.h"
#include "libs/bigint/BigIntegerLibrary.hh"
-#include <assert.h>
-static void extend(RTLIL::Const &arg, int width, bool is_signed)
-{
- RTLIL::State padding = RTLIL::State::S0;
-
- if (arg.bits.size() > 0 && (is_signed || arg.bits.back() > RTLIL::State::S1))
- padding = arg.bits.back();
-
- while (int(arg.bits.size()) < width)
- arg.bits.push_back(padding);
-}
+YOSYS_NAMESPACE_BEGIN
static void extend_u0(RTLIL::Const &arg, int width, bool is_signed)
{
@@ -46,6 +35,8 @@ static void extend_u0(RTLIL::Const &arg, int width, bool is_signed)
while (int(arg.bits.size()) < width)
arg.bits.push_back(padding);
+
+ arg.bits.resize(width);
}
static BigInteger const2big(const RTLIL::Const &val, bool as_signed, int &undef_bit_pos)
@@ -277,7 +268,7 @@ RTLIL::Const RTLIL::const_logic_or(const RTLIL::Const &arg1, const RTLIL::Const
return result;
}
-static RTLIL::Const const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, int direction, int result_len)
+static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, int direction, int result_len)
{
int undef_bit_pos = -1;
BigInteger offset = const2big(arg2, false, undef_bit_pos) * direction;
@@ -305,29 +296,62 @@ static RTLIL::Const const_shift(const RTLIL::Const &arg1, const RTLIL::Const &ar
RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
{
RTLIL::Const arg1_ext = arg1;
- extend(arg1_ext, result_len, signed1);
- return const_shift(arg1_ext, arg2, false, -1, result_len);
+ extend_u0(arg1_ext, result_len, signed1);
+ return const_shift_worker(arg1_ext, arg2, false, -1, result_len);
}
RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
{
RTLIL::Const arg1_ext = arg1;
- extend(arg1_ext, result_len, signed1);
- return const_shift(arg1_ext, arg2, false, +1, result_len);
+ extend_u0(arg1_ext, std::max(result_len, SIZE(arg1)), signed1);
+ return const_shift_worker(arg1_ext, arg2, false, +1, result_len);
}
RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{
if (!signed1)
return const_shl(arg1, arg2, signed1, signed2, result_len);
- return const_shift(arg1, arg2, true, -1, result_len);
+ return const_shift_worker(arg1, arg2, true, -1, result_len);
}
RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{
if (!signed1)
return const_shr(arg1, arg2, signed1, signed2, result_len);
- return const_shift(arg1, arg2, true, +1, result_len);
+ return const_shift_worker(arg1, arg2, true, +1, result_len);
+}
+
+static RTLIL::Const const_shift_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool signed2, int result_len, RTLIL::State other_bits)
+{
+ int undef_bit_pos = -1;
+ BigInteger offset = const2big(arg2, signed2, undef_bit_pos);
+
+ if (result_len < 0)
+ result_len = arg1.bits.size();
+
+ RTLIL::Const result(RTLIL::State::Sx, result_len);
+ if (undef_bit_pos >= 0)
+ return result;
+
+ for (int i = 0; i < result_len; i++) {
+ BigInteger pos = BigInteger(i) + offset;
+ if (pos < 0 || pos >= arg1.bits.size())
+ result.bits[i] = other_bits;
+ else
+ result.bits[i] = arg1.bits[pos.toInt()];
+ }
+
+ return result;
+}
+
+RTLIL::Const RTLIL::const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::Sx);
}
RTLIL::Const RTLIL::const_lt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
@@ -538,14 +562,6 @@ RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2
RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
{
RTLIL::Const arg1_ext = arg1;
- extend(arg1_ext, result_len, signed1);
-
- return arg1_ext;
-}
-
-RTLIL::Const RTLIL::const_bu0(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
-{
- RTLIL::Const arg1_ext = arg1;
extend_u0(arg1_ext, result_len, signed1);
return arg1_ext;
@@ -554,9 +570,10 @@ RTLIL::Const RTLIL::const_bu0(const RTLIL::Const &arg1, const RTLIL::Const&, boo
RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
{
RTLIL::Const arg1_ext = arg1;
- extend(arg1_ext, result_len, signed1);
-
RTLIL::Const zero(RTLIL::State::S0, 1);
- return RTLIL::const_sub(zero, arg1_ext, false, signed1, result_len);
+
+ return RTLIL::const_sub(zero, arg1_ext, true, signed1, result_len);
}
+YOSYS_NAMESPACE_END
+
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index 34a6e56f..85c21ef3 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -20,202 +20,204 @@
#ifndef CELLTYPES_H
#define CELLTYPES_H
-#include <set>
-#include <string>
-#include <stdlib.h>
+#include <kernel/yosys.h>
-#include <kernel/rtlil.h>
-#include <kernel/log.h>
+YOSYS_NAMESPACE_BEGIN
+
+struct CellType
+{
+ RTLIL::IdString type;
+ std::set<RTLIL::IdString> inputs, outputs;
+ bool is_evaluable;
+};
struct CellTypes
{
- std::set<std::string> cell_types;
- std::vector<const RTLIL::Design*> designs;
+ std::map<RTLIL::IdString, CellType> cell_types;
CellTypes()
{
}
- CellTypes(const RTLIL::Design *design)
+ CellTypes(RTLIL::Design *design)
{
setup(design);
}
- void setup(const RTLIL::Design *design = NULL)
+ void setup(RTLIL::Design *design = NULL)
{
if (design)
setup_design(design);
+
setup_internals();
setup_internals_mem();
setup_stdcells();
setup_stdcells_mem();
}
- void setup_design(const RTLIL::Design *design)
+ void setup_type(RTLIL::IdString type, const std::set<RTLIL::IdString> &inputs, const std::set<RTLIL::IdString> &outputs, bool is_evaluable = false)
+ {
+ CellType ct = {type, inputs, outputs, is_evaluable};
+ cell_types[ct.type] = ct;
+ }
+
+ void setup_module(RTLIL::Module *module)
+ {
+ std::set<RTLIL::IdString> inputs, outputs;
+ for (RTLIL::IdString wire_name : module->ports) {
+ RTLIL::Wire *wire = module->wire(wire_name);
+ if (wire->port_input)
+ inputs.insert(wire->name);
+ if (wire->port_output)
+ outputs.insert(wire->name);
+ }
+ setup_type(module->name, inputs, outputs);
+ }
+
+ void setup_design(RTLIL::Design *design)
{
- designs.push_back(design);
+ for (auto module : design->modules())
+ setup_module(module);
}
void setup_internals()
{
- cell_types.insert("$not");
- cell_types.insert("$pos");
- cell_types.insert("$bu0");
- cell_types.insert("$neg");
- cell_types.insert("$and");
- cell_types.insert("$or");
- cell_types.insert("$xor");
- cell_types.insert("$xnor");
- cell_types.insert("$reduce_and");
- cell_types.insert("$reduce_or");
- cell_types.insert("$reduce_xor");
- cell_types.insert("$reduce_xnor");
- cell_types.insert("$reduce_bool");
- cell_types.insert("$shl");
- cell_types.insert("$shr");
- cell_types.insert("$sshl");
- cell_types.insert("$sshr");
- cell_types.insert("$lt");
- cell_types.insert("$le");
- cell_types.insert("$eq");
- cell_types.insert("$ne");
- cell_types.insert("$eqx");
- cell_types.insert("$nex");
- cell_types.insert("$ge");
- cell_types.insert("$gt");
- cell_types.insert("$add");
- cell_types.insert("$sub");
- cell_types.insert("$mul");
- cell_types.insert("$div");
- cell_types.insert("$mod");
- cell_types.insert("$pow");
- cell_types.insert("$logic_not");
- cell_types.insert("$logic_and");
- cell_types.insert("$logic_or");
- cell_types.insert("$mux");
- cell_types.insert("$pmux");
- cell_types.insert("$slice");
- cell_types.insert("$concat");
- cell_types.insert("$safe_pmux");
- cell_types.insert("$lut");
- cell_types.insert("$assert");
+ std::vector<RTLIL::IdString> unary_ops = {
+ "$not", "$pos", "$neg",
+ "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
+ "$logic_not", "$slice", "$lut"
+ };
+
+ std::vector<RTLIL::IdString> binary_ops = {
+ "$and", "$or", "$xor", "$xnor",
+ "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
+ "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
+ "$add", "$sub", "$mul", "$div", "$mod", "$pow",
+ "$logic_and", "$logic_or", "$concat", "$macc"
+ };
+
+ for (auto type : unary_ops)
+ setup_type(type, {"\\A"}, {"\\Y"}, true);
+
+ for (auto type : binary_ops)
+ setup_type(type, {"\\A", "\\B"}, {"\\Y"}, true);
+
+ for (auto type : std::vector<RTLIL::IdString>({"$mux", "$pmux"}))
+ setup_type(type, {"\\A", "\\B", "\\S"}, {"\\Y"}, true);
+
+ setup_type("$lcu", {"\\P", "\\G", "\\CI"}, {"\\CO"}, true);
+ setup_type("$alu", {"\\A", "\\B", "\\CI", "\\BI"}, {"\\X", "\\Y", "\\CO"}, true);
+ setup_type("$fa", {"\\A", "\\B", "\\C"}, {"\\X", "\\Y"}, true);
+
+ setup_type("$assert", {"\\A", "\\EN"}, std::set<RTLIL::IdString>(), true);
}
void setup_internals_mem()
{
- cell_types.insert("$sr");
- cell_types.insert("$dff");
- cell_types.insert("$dffsr");
- cell_types.insert("$adff");
- cell_types.insert("$dlatch");
- cell_types.insert("$memrd");
- cell_types.insert("$memwr");
- cell_types.insert("$mem");
- cell_types.insert("$fsm");
+ setup_type("$sr", {"\\SET", "\\CLR"}, {"\\Q"});
+ setup_type("$dff", {"\\CLK", "\\D"}, {"\\Q"});
+ setup_type("$dffsr", {"\\CLK", "\\SET", "\\CLR", "\\D"}, {"\\Q"});
+ setup_type("$adff", {"\\CLK", "\\ARST", "\\D"}, {"\\Q"});
+ setup_type("$dlatch", {"\\EN", "\\D"}, {"\\Q"});
+ setup_type("$dlatchsr", {"\\EN", "\\SET", "\\CLR", "\\D"}, {"\\Q"});
+
+ setup_type("$memrd", {"\\CLK", "\\ADDR"}, {"\\DATA"});
+ setup_type("$memwr", {"\\CLK", "\\EN", "\\ADDR", "\\DATA"}, std::set<RTLIL::IdString>());
+ setup_type("$mem", {"\\RD_CLK", "\\RD_ADDR", "\\WR_CLK", "\\WR_EN", "\\WR_ADDR", "\\WR_DATA"}, {"\\RD_DATA"});
+
+ setup_type("$fsm", {"\\CLK", "\\ARST", "\\CTRL_IN"}, {"\\CTRL_OUT"});
}
void setup_stdcells()
{
- cell_types.insert("$_INV_");
- cell_types.insert("$_AND_");
- cell_types.insert("$_OR_");
- cell_types.insert("$_XOR_");
- cell_types.insert("$_MUX_");
+ setup_type("$_NOT_", {"\\A"}, {"\\Y"}, true);
+ setup_type("$_AND_", {"\\A", "\\B"}, {"\\Y"}, true);
+ setup_type("$_NAND_", {"\\A", "\\B"}, {"\\Y"}, true);
+ setup_type("$_OR_", {"\\A", "\\B"}, {"\\Y"}, true);
+ setup_type("$_NOR_", {"\\A", "\\B"}, {"\\Y"}, true);
+ setup_type("$_XOR_", {"\\A", "\\B"}, {"\\Y"}, true);
+ setup_type("$_XNOR_", {"\\A", "\\B"}, {"\\Y"}, true);
+ setup_type("$_MUX_", {"\\A", "\\B", "\\S"}, {"\\Y"}, true);
+ setup_type("$_AOI3_", {"\\A", "\\B", "\\C"}, {"\\Y"}, true);
+ setup_type("$_OAI3_", {"\\A", "\\B", "\\C"}, {"\\Y"}, true);
+ setup_type("$_AOI4_", {"\\A", "\\B", "\\C", "\\D"}, {"\\Y"}, true);
+ setup_type("$_OAI4_", {"\\A", "\\B", "\\C", "\\D"}, {"\\Y"}, true);
}
void setup_stdcells_mem()
{
- cell_types.insert("$_SR_NN_");
- cell_types.insert("$_SR_NP_");
- cell_types.insert("$_SR_PN_");
- cell_types.insert("$_SR_PP_");
- cell_types.insert("$_DFF_N_");
- cell_types.insert("$_DFF_P_");
- cell_types.insert("$_DFF_NN0_");
- cell_types.insert("$_DFF_NN1_");
- cell_types.insert("$_DFF_NP0_");
- cell_types.insert("$_DFF_NP1_");
- cell_types.insert("$_DFF_PN0_");
- cell_types.insert("$_DFF_PN1_");
- cell_types.insert("$_DFF_PP0_");
- cell_types.insert("$_DFF_PP1_");
- cell_types.insert("$_DFFSR_NNN_");
- cell_types.insert("$_DFFSR_NNP_");
- cell_types.insert("$_DFFSR_NPN_");
- cell_types.insert("$_DFFSR_NPP_");
- cell_types.insert("$_DFFSR_PNN_");
- cell_types.insert("$_DFFSR_PNP_");
- cell_types.insert("$_DFFSR_PPN_");
- cell_types.insert("$_DFFSR_PPP_");
- cell_types.insert("$_DLATCH_N_");
- cell_types.insert("$_DLATCH_P_");
+ std::vector<char> list_np = {'N', 'P'}, list_01 = {'0', '1'};
+
+ for (auto c1 : list_np)
+ for (auto c2 : list_np)
+ setup_type(stringf("$_SR_%c%c_", c1, c2), {"\\S", "\\R"}, {"\\Q"});
+
+ for (auto c1 : list_np)
+ setup_type(stringf("$_DFF_%c_", c1), {"\\C", "\\D"}, {"\\Q"});
+
+ for (auto c1 : list_np)
+ for (auto c2 : list_np)
+ for (auto c3 : list_01)
+ setup_type(stringf("$_DFF_%c%c%c_", c1, c2, c3), {"\\C", "\\R", "\\D"}, {"\\Q"});
+
+ for (auto c1 : list_np)
+ for (auto c2 : list_np)
+ for (auto c3 : list_np)
+ setup_type(stringf("$_DFFSR_%c%c%c_", c1, c2, c3), {"\\C", "\\S", "\\R", "\\D"}, {"\\Q"});
+
+ for (auto c1 : list_np)
+ setup_type(stringf("$_DLATCH_%c_", c1), {"\\E", "\\D"}, {"\\Q"});
+
+ for (auto c1 : list_np)
+ for (auto c2 : list_np)
+ for (auto c3 : list_np)
+ setup_type(stringf("$_DLATCHSR_%c%c%c_", c1, c2, c3), {"\\E", "\\S", "\\R", "\\D"}, {"\\Q"});
}
void clear()
{
cell_types.clear();
- designs.clear();
}
- bool cell_known(std::string type)
+ bool cell_known(RTLIL::IdString type)
{
- if (cell_types.count(type) > 0)
- return true;
- for (auto design : designs)
- if (design->modules.count(type) > 0)
- return true;
- return false;
+ return cell_types.count(type) != 0;
}
- bool cell_output(std::string type, std::string port)
+ bool cell_output(RTLIL::IdString type, RTLIL::IdString port)
{
- if (cell_types.count(type) == 0) {
- for (auto design : designs)
- if (design->modules.count(type) > 0) {
- if (design->modules.at(type)->wires.count(port))
- return design->modules.at(type)->wires.at(port)->port_output;
- return false;
- }
- return false;
- }
-
- if (port == "\\Y" || port == "\\Q" || port == "\\RD_DATA")
- return true;
- if (type == "$memrd" && port == "\\DATA")
- return true;
- if (type == "$fsm" && port == "\\CTRL_OUT")
- return true;
- if (type == "$lut" && port == "\\O")
- return true;
- return false;
+ auto it = cell_types.find(type);
+ return it != cell_types.end() && it->second.outputs.count(port) != 0;
}
- bool cell_input(std::string type, std::string port)
+ bool cell_input(RTLIL::IdString type, RTLIL::IdString port)
{
- if (cell_types.count(type) == 0) {
- for (auto design : designs)
- if (design->modules.count(type) > 0) {
- if (design->modules.at(type)->wires.count(port))
- return design->modules.at(type)->wires.at(port)->port_input;
- return false;
- }
- return false;
- }
+ auto it = cell_types.find(type);
+ return it != cell_types.end() && it->second.inputs.count(port) != 0;
+ }
- if (cell_types.count(type) > 0)
- return !cell_output(type, port);
+ bool cell_evaluable(RTLIL::IdString type)
+ {
+ auto it = cell_types.find(type);
+ return it != cell_types.end() && it->second.is_evaluable;
+ }
- return false;
+ static RTLIL::Const eval_not(RTLIL::Const v)
+ {
+ for (auto &bit : v.bits)
+ if (bit == RTLIL::S0) bit = RTLIL::S1;
+ else if (bit == RTLIL::S1) bit = RTLIL::S0;
+ return v;
}
- static RTLIL::Const eval(std::string 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)
{
if (type == "$sshr" && !signed1)
type = "$shr";
if (type == "$sshl" && !signed1)
type = "$shl";
- if (type != "$sshr" && type != "$sshl" && type != "$shr" && type != "$shl" &&
+ if (type != "$sshr" && type != "$sshl" && type != "$shr" && type != "$shl" && type != "$shift" && type != "$shiftx" &&
type != "$pos" && type != "$neg" && type != "$not") {
if (!signed1 || !signed2)
signed1 = false, signed2 = false;
@@ -239,6 +241,8 @@ struct CellTypes
HANDLE_CELL_TYPE(shr)
HANDLE_CELL_TYPE(sshl)
HANDLE_CELL_TYPE(sshr)
+ HANDLE_CELL_TYPE(shift)
+ HANDLE_CELL_TYPE(shiftx)
HANDLE_CELL_TYPE(lt)
HANDLE_CELL_TYPE(le)
HANDLE_CELL_TYPE(eq)
@@ -254,18 +258,23 @@ struct CellTypes
HANDLE_CELL_TYPE(mod)
HANDLE_CELL_TYPE(pow)
HANDLE_CELL_TYPE(pos)
- HANDLE_CELL_TYPE(bu0)
HANDLE_CELL_TYPE(neg)
#undef HANDLE_CELL_TYPE
- if (type == "$_INV_")
- return const_not(arg1, arg2, false, false, 1);
+ if (type == "$_NOT_")
+ return eval_not(arg1);
if (type == "$_AND_")
return const_and(arg1, arg2, false, false, 1);
+ if (type == "$_NAND_")
+ return eval_not(const_and(arg1, arg2, false, false, 1));
if (type == "$_OR_")
return const_or(arg1, arg2, false, false, 1);
+ if (type == "$_NOR_")
+ return eval_not(const_and(arg1, arg2, false, false, 1));
if (type == "$_XOR_")
return const_xor(arg1, arg2, false, false, 1);
+ if (type == "$_XNOR_")
+ return const_xnor(arg1, arg2, false, false, 1);
log_abort();
}
@@ -286,28 +295,72 @@ struct CellTypes
return ret;
}
+ if (cell->type == "$lut")
+ {
+ int width = cell->parameters.at("\\WIDTH").as_int();
+
+ std::vector<RTLIL::State> t = cell->parameters.at("\\LUT").bits;
+ while (SIZE(t) < (1 << width))
+ t.push_back(RTLIL::S0);
+ t.resize(1 << width);
+
+ for (int i = width-1; i >= 0; i--) {
+ RTLIL::State sel = arg1.bits.at(i);
+ std::vector<RTLIL::State> new_t;
+ if (sel == RTLIL::S0)
+ new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + SIZE(t)/2);
+ else if (sel == RTLIL::S1)
+ new_t = std::vector<RTLIL::State>(t.begin() + SIZE(t)/2, t.end());
+ else
+ for (int j = 0; j < SIZE(t)/2; j++)
+ new_t.push_back(t[j] == t[j + SIZE(t)/2] ? t[j] : RTLIL::Sx);
+ t.swap(new_t);
+ }
+
+ log_assert(SIZE(t) == 1);
+ return t;
+ }
+
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);
}
- static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &sel)
+ static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3)
{
- if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_") {
+ if (cell->type.in("$mux", "$pmux", "$_MUX_")) {
RTLIL::Const ret = arg1;
- for (size_t i = 0; i < sel.bits.size(); i++)
- if (sel.bits[i] == RTLIL::State::S1) {
+ for (size_t i = 0; i < arg3.bits.size(); i++)
+ if (arg3.bits[i] == RTLIL::State::S1) {
std::vector<RTLIL::State> bits(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size());
ret = RTLIL::Const(bits);
}
return ret;
}
- assert(sel.bits.size() == 0);
+ if (cell->type == "$_AOI3_")
+ return eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1));
+ if (cell->type == "$_OAI3_")
+ 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);
}
+
+ static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4)
+ {
+ 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));
+
+ log_assert(arg4.bits.size() == 0);
+ return eval(cell, arg1, arg2, arg3);
+ }
};
+YOSYS_NAMESPACE_END
+
#endif
diff --git a/kernel/consteval.h b/kernel/consteval.h
index 10116ccf..2d29d3f7 100644
--- a/kernel/consteval.h
+++ b/kernel/consteval.h
@@ -23,6 +23,7 @@
#include "kernel/rtlil.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
+#include "kernel/macc.h"
struct ConstEval
{
@@ -40,10 +41,10 @@ struct ConstEval
ct.setup_internals();
ct.setup_stdcells();
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (!ct.cell_known(it.second->type))
continue;
- for (auto &it2 : it.second->connections)
+ for (auto &it2 : it.second->connections())
if (ct.cell_output(it.second->type, it2.first))
sig2driver.insert(assign_map(it2.second), it.second);
}
@@ -71,11 +72,8 @@ struct ConstEval
assign_map.apply(sig);
#ifndef NDEBUG
RTLIL::SigSpec current_val = values_map(sig);
- current_val.expand();
- for (size_t i = 0; i < current_val.chunks.size(); i++) {
- RTLIL::SigChunk &chunk = current_val.chunks[i];
- assert(chunk.wire != NULL || chunk.data.bits[0] == value.bits[i]);
- }
+ for (int i = 0; i < SIZE(current_val); i++)
+ log_assert(current_val[i].wire != NULL || current_val[i] == value.bits[i]);
#endif
values_map.add(sig, RTLIL::SigSpec(value));
}
@@ -88,35 +86,72 @@ struct ConstEval
bool eval(RTLIL::Cell *cell, RTLIL::SigSpec &undef)
{
+ if (cell->type == "$lcu")
+ {
+ RTLIL::SigSpec sig_p = cell->getPort("\\P");
+ RTLIL::SigSpec sig_g = cell->getPort("\\G");
+ RTLIL::SigSpec sig_ci = cell->getPort("\\CI");
+ RTLIL::SigSpec sig_co = values_map(assign_map(cell->getPort("\\CO")));
+
+ if (sig_co.is_fully_const())
+ return true;
+
+ if (!eval(sig_p, undef, cell))
+ return false;
+
+ if (!eval(sig_g, undef, cell))
+ return false;
+
+ if (!eval(sig_ci, undef, cell))
+ return false;
+
+ if (sig_p.is_fully_def() && sig_g.is_fully_def() && sig_ci.is_fully_def())
+ {
+ RTLIL::Const coval(RTLIL::Sx, SIZE(sig_co));
+ bool carry = sig_ci.as_bool();
+
+ for (int i = 0; i < SIZE(coval); i++) {
+ carry = (sig_g[i] == RTLIL::S1) || (sig_p[i] == RTLIL::S1 && carry);
+ coval.bits[i] = carry ? RTLIL::S1 : RTLIL::S0;
+ }
+
+ set(sig_co, coval);
+ }
+ else
+ set(sig_co, RTLIL::Const(RTLIL::Sx, SIZE(sig_co)));
+
+ return true;
+ }
+
RTLIL::SigSpec sig_a, sig_b, sig_s, sig_y;
- assert(cell->connections.count("\\Y") > 0);
- sig_y = values_map(assign_map(cell->connections["\\Y"]));
+ log_assert(cell->hasPort("\\Y"));
+ sig_y = values_map(assign_map(cell->getPort("\\Y")));
if (sig_y.is_fully_const())
return true;
- if (cell->connections.count("\\S") > 0) {
- sig_s = cell->connections["\\S"];
+ if (cell->hasPort("\\S")) {
+ sig_s = cell->getPort("\\S");
if (!eval(sig_s, undef, cell))
return false;
}
- if (cell->connections.count("\\A") > 0)
- sig_a = cell->connections["\\A"];
+ if (cell->hasPort("\\A"))
+ sig_a = cell->getPort("\\A");
- if (cell->connections.count("\\B") > 0)
- sig_b = cell->connections["\\B"];
+ if (cell->hasPort("\\B"))
+ sig_b = cell->getPort("\\B");
- if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_")
+ if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_")
{
std::vector<RTLIL::SigSpec> y_candidates;
int count_maybe_set_s_bits = 0;
int count_set_s_bits = 0;
- for (int i = 0; i < sig_s.width; i++)
+ for (int i = 0; i < sig_s.size(); i++)
{
RTLIL::State s_bit = sig_s.extract(i, 1).as_const().bits.at(0);
- RTLIL::SigSpec b_slice = sig_b.extract(sig_y.width*i, sig_y.width);
+ RTLIL::SigSpec b_slice = sig_b.extract(sig_y.size()*i, sig_y.size());
if (s_bit == RTLIL::State::Sx || s_bit == RTLIL::State::S1)
y_candidates.push_back(b_slice);
@@ -128,15 +163,12 @@ struct ConstEval
count_set_s_bits++;
}
- if (cell->type == "$safe_pmux" && count_set_s_bits > 1)
- y_candidates.clear();
-
- if ((cell->type == "$safe_pmux" && count_maybe_set_s_bits > 1) || count_set_s_bits == 0)
+ if (count_set_s_bits == 0)
y_candidates.push_back(sig_a);
std::vector<RTLIL::Const> y_values;
- assert(y_candidates.size() > 0);
+ log_assert(y_candidates.size() > 0);
for (auto &yc : y_candidates) {
if (!eval(yc, undef, cell))
return false;
@@ -149,7 +181,7 @@ struct ConstEval
for (size_t i = 1; i < y_values.size(); i++) {
std::vector<RTLIL::State> &slave_bits = y_values.at(i).bits;
- assert(master_bits.size() == slave_bits.size());
+ log_assert(master_bits.size() == slave_bits.size());
for (size_t j = 0; j < master_bits.size(); j++)
if (master_bits[j] != slave_bits[j])
master_bits[j] = RTLIL::State::Sx;
@@ -160,13 +192,134 @@ struct ConstEval
else
set(sig_y, y_values.front());
}
+ else if (cell->type == "$fa")
+ {
+ RTLIL::SigSpec sig_c = cell->getPort("\\C");
+ RTLIL::SigSpec sig_x = cell->getPort("\\X");
+ int width = SIZE(sig_c);
+
+ if (!eval(sig_a, undef, cell))
+ return false;
+
+ if (!eval(sig_b, undef, cell))
+ return false;
+
+ if (!eval(sig_c, undef, cell))
+ return false;
+
+ RTLIL::Const t1 = const_xor(sig_a.as_const(), sig_b.as_const(), false, false, width);
+ RTLIL::Const val_y = const_xor(t1, sig_c.as_const(), false, false, width);
+
+ RTLIL::Const t2 = const_and(sig_a.as_const(), sig_b.as_const(), false, false, width);
+ RTLIL::Const t3 = const_and(sig_c.as_const(), t1, false, false, width);
+ RTLIL::Const val_x = const_or(t2, t3, false, false, width);
+
+ for (int i = 0; i < SIZE(val_y); i++)
+ if (val_y.bits[i] == RTLIL::Sx)
+ val_x.bits[i] = RTLIL::Sx;
+
+ set(sig_y, val_y);
+ set(sig_x, val_x);
+ }
+ else if (cell->type == "$alu")
+ {
+ bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool();
+ bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool();
+
+ RTLIL::SigSpec sig_ci = cell->getPort("\\CI");
+ RTLIL::SigSpec sig_bi = cell->getPort("\\BI");
+
+ if (!eval(sig_a, undef, cell))
+ return false;
+
+ if (!eval(sig_b, undef, cell))
+ return false;
+
+ if (!eval(sig_ci, undef, cell))
+ return false;
+
+ if (!eval(sig_bi, undef, cell))
+ return false;
+
+ RTLIL::SigSpec sig_x = cell->getPort("\\X");
+ RTLIL::SigSpec sig_co = cell->getPort("\\CO");
+
+ bool any_input_undef = !(sig_a.is_fully_def() && sig_b.is_fully_def() && sig_ci.is_fully_def() && sig_bi.is_fully_def());
+ sig_a.extend_u0(SIZE(sig_y), signed_a);
+ sig_b.extend_u0(SIZE(sig_y), signed_b);
+
+ bool carry = sig_ci[0] == RTLIL::S1;
+ bool b_inv = sig_bi[0] == RTLIL::S1;
+
+ for (int i = 0; i < SIZE(sig_y); i++)
+ {
+ RTLIL::SigSpec x_inputs = { sig_a[i], sig_b[i], sig_bi[0] };
+
+ if (!x_inputs.is_fully_def()) {
+ set(sig_x[i], RTLIL::Sx);
+ } else {
+ bool bit_a = sig_a[i] == RTLIL::S1;
+ bool bit_b = (sig_b[i] == RTLIL::S1) != b_inv;
+ bool bit_x = bit_a != bit_b;
+ set(sig_x[i], bit_x ? RTLIL::S1 : RTLIL::S0);
+ }
+
+ if (any_input_undef) {
+ set(sig_y[i], RTLIL::Sx);
+ set(sig_co[i], RTLIL::Sx);
+ } else {
+ bool bit_a = sig_a[i] == RTLIL::S1;
+ bool bit_b = (sig_b[i] == RTLIL::S1) != b_inv;
+ bool bit_y = (bit_a != bit_b) != carry;
+ carry = (bit_a && bit_b) || (bit_a && carry) || (bit_b && carry);
+ set(sig_y[i], bit_y ? RTLIL::S1 : RTLIL::S0);
+ set(sig_co[i], carry ? RTLIL::S1 : RTLIL::S0);
+ }
+ }
+ }
+ else if (cell->type == "$macc")
+ {
+ Macc macc;
+ macc.from_cell(cell);
+
+ if (!eval(macc.bit_ports, undef, cell))
+ return false;
+
+ for (auto &port : macc.ports) {
+ if (!eval(port.in_a, undef, cell))
+ return false;
+ if (!eval(port.in_b, undef, cell))
+ return false;
+ }
+
+ RTLIL::Const result(0, SIZE(cell->getPort("\\Y")));
+ if (!macc.eval(result))
+ log_abort();
+
+ set(cell->getPort("\\Y"), result);
+ }
else
{
- if (sig_a.width > 0 && !eval(sig_a, undef, cell))
+ RTLIL::SigSpec sig_c, sig_d;
+
+ if (cell->type.in("$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_")) {
+ if (cell->hasPort("\\C"))
+ sig_c = cell->getPort("\\C");
+ if (cell->hasPort("\\D"))
+ sig_d = cell->getPort("\\D");
+ }
+
+ if (sig_a.size() > 0 && !eval(sig_a, undef, cell))
+ return false;
+ if (sig_b.size() > 0 && !eval(sig_b, undef, cell))
return false;
- if (sig_b.width > 0 && !eval(sig_b, undef, cell))
+ if (sig_c.size() > 0 && !eval(sig_c, undef, cell))
return false;
- set(sig_y, CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const()));
+ 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()));
}
return true;
@@ -210,9 +363,9 @@ struct ConstEval
if (sig.is_fully_const())
return true;
- for (size_t i = 0; i < sig.chunks.size(); i++)
- if (sig.chunks[i].wire != NULL)
- undef.append(sig.chunks[i]);
+ for (auto &c : sig.chunks())
+ if (c.wire != NULL)
+ undef.append(c);
return false;
}
diff --git a/kernel/driver.cc b/kernel/driver.cc
index 00a61ec0..f26d9ef8 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -17,464 +17,38 @@
*
*/
+#include "kernel/yosys.h"
+#include "libs/sha1/sha1.h"
+
+#ifdef YOSYS_ENABLE_READLINE
+# include <readline/readline.h>
+# include <readline/history.h>
+#endif
+
#include <stdio.h>
-#include <readline/readline.h>
-#include <readline/history.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
-#include <dlfcn.h>
-
-#include <algorithm>
-
-#include "kernel/rtlil.h"
-#include "kernel/register.h"
-#include "kernel/log.h"
-
-bool fgetline(FILE *f, std::string &buffer)
-{
- buffer = "";
- char block[4096];
- while (1) {
- if (fgets(block, 4096, f) == NULL)
- return false;
- buffer += block;
- if (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) {
- while (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r'))
- buffer.resize(buffer.size()-1);
- return true;
- }
- }
-}
-
-static void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command)
-{
- if (command == "auto") {
- if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
- command = "verilog";
- else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
- command = "ilang";
- else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
- command = "script";
- else if (filename == "-")
- command = "script";
- else
- log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str());
- }
-
- if (command == "script") {
- log("\n-- Executing script file `%s' --\n", filename.c_str());
- FILE *f = stdin;
- if (filename != "-")
- f = fopen(filename.c_str(), "r");
- if (f == NULL)
- log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
- std::string command;
- while (fgetline(f, command)) {
- while (!command.empty() && command[command.size()-1] == '\\') {
- std::string next_line;
- if (!fgetline(f, next_line))
- break;
- command.resize(command.size()-1);
- command += next_line;
- }
- Pass::call(design, command);
- }
- if (!command.empty())
- Pass::call(design, command);
- if (filename != "-")
- fclose(f);
- if (backend_command != NULL && *backend_command == "auto")
- *backend_command = "";
- return;
- }
-
- if (filename == "-") {
- log("\n-- Parsing stdin using frontend `%s' --\n", command.c_str());
- } else {
- log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
- }
-
- Frontend::frontend_call(design, NULL, filename, command);
-}
-
-static void run_pass(std::string command, RTLIL::Design *design)
-{
- log("\n-- Running pass `%s' --\n", command.c_str());
-
- Pass::call(design, command);
-}
-
-static void run_backend(std::string filename, std::string command, RTLIL::Design *design)
-{
- if (command == "auto") {
- if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
- command = "verilog";
- else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
- command = "ilang";
- else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif")
- command = "blif";
- else if (filename == "-")
- command = "ilang";
- else if (filename.empty())
- return;
- else
- log_error("Can't guess backend for output file `%s' (missing -b option)!\n", filename.c_str());
- }
-
- if (filename.empty())
- filename = "-";
-
- if (filename == "-") {
- log("\n-- Writing to stdout using backend `%s' --\n", command.c_str());
- } else {
- log("\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str());
- }
-
- Backend::backend_call(design, NULL, filename, command);
-}
-
-static char *readline_cmd_generator(const char *text, int state)
-{
- static std::map<std::string, Pass*>::iterator it;
- static int len;
-
- if (!state) {
- it = REGISTER_INTERN::pass_register.begin();
- len = strlen(text);
- }
-
- for (; it != REGISTER_INTERN::pass_register.end(); it++) {
- if (it->first.substr(0, len) == text)
- return strdup((it++)->first.c_str());
- }
- return NULL;
-}
-
-static char *readline_obj_generator(const char *text, int state)
-{
- static std::vector<char*> obj_names;
- static size_t idx;
-
- if (!state)
- {
- idx = 0;
- obj_names.clear();
-
- RTLIL::Design *design = yosys_get_design();
- int len = strlen(text);
-
- if (design->selected_active_module.empty())
- {
- for (auto &it : design->modules)
- if (RTLIL::unescape_id(it.first).substr(0, len) == text)
- obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str())));
- }
- else
- if (design->modules.count(design->selected_active_module) > 0)
- {
- RTLIL::Module *module = design->modules.at(design->selected_active_module);
-
- for (auto &it : module->wires)
- if (RTLIL::unescape_id(it.first).substr(0, len) == text)
- obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str())));
-
- for (auto &it : module->memories)
- if (RTLIL::unescape_id(it.first).substr(0, len) == text)
- obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str())));
-
- for (auto &it : module->cells)
- if (RTLIL::unescape_id(it.first).substr(0, len) == text)
- obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str())));
-
- for (auto &it : module->processes)
- if (RTLIL::unescape_id(it.first).substr(0, len) == text)
- obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str())));
- }
-
- std::sort(obj_names.begin(), obj_names.end());
- }
-
- if (idx < obj_names.size())
- return strdup(obj_names[idx++]);
-
- idx = 0;
- obj_names.clear();
- return NULL;
-}
-
-static char **readline_completion(const char *text, int start, int)
-{
- if (start == 0)
- return rl_completion_matches(text, readline_cmd_generator);
- if (strncmp(rl_line_buffer, "read_", 5) && strncmp(rl_line_buffer, "write_", 6))
- return rl_completion_matches(text, readline_obj_generator);
- return NULL;
-}
-
-const char *create_prompt(RTLIL::Design *design, int recursion_counter)
-{
- static char buffer[100];
- std::string str = "\n";
- if (recursion_counter > 1)
- str += stringf("(%d) ", recursion_counter);
- str += "yosys";
- if (!design->selected_active_module.empty())
- str += stringf(" [%s]", RTLIL::id2cstr(design->selected_active_module));
- if (!design->selection_stack.back().full_selection) {
- if (design->selected_active_module.empty())
- str += "*";
- else if (design->selection_stack.back().selected_modules.size() != 1 || design->selection_stack.back().selected_members.size() != 0 ||
- design->selection_stack.back().selected_modules.count(design->selected_active_module) == 0)
- str += "*";
- }
- snprintf(buffer, 100, "%s> ", str.c_str());
- return buffer;
-}
-
-static void shell(RTLIL::Design *design)
-{
- static int recursion_counter = 0;
-
- recursion_counter++;
- log_cmd_error_throw = true;
-
- rl_readline_name = "yosys";
- rl_attempted_completion_function = readline_completion;
- rl_basic_word_break_characters = " \t\n";
-
- char *command = NULL;
- while ((command = readline(create_prompt(design, recursion_counter))) != NULL)
- {
- if (command[strspn(command, " \t\r\n")] == 0)
- continue;
- add_history(command);
-
- char *p = command + strspn(command, " \t\r\n");
- if (!strncmp(p, "exit", 4)) {
- p += 4;
- p += strspn(p, " \t\r\n");
- if (*p == 0)
- break;
- }
-
- try {
- assert(design->selection_stack.size() == 1);
- Pass::call(design, command);
- } catch (int) {
- while (design->selection_stack.size() > 1)
- design->selection_stack.pop_back();
- log_reset_stack();
- }
- }
- if (command == NULL)
- printf("exit\n");
-
- recursion_counter--;
- log_cmd_error_throw = false;
-}
-
-struct ShellPass : public Pass {
- ShellPass() : Pass("shell", "enter interactive command mode") { }
- virtual void help() {
- log("\n");
- log(" shell\n");
- log("\n");
- log("This command enters the interactive command mode. This can be useful\n");
- log("in a script to interrupt the script at a certain point and allow for\n");
- log("interactive inspection or manual synthesis of the design at this point.\n");
- log("\n");
- log("The command prompt of the interactive shell indicates the current\n");
- log("selection (see 'help select'):\n");
- log("\n");
- log(" yosys>\n");
- log(" the entire design is selected\n");
- log("\n");
- log(" yosys*>\n");
- log(" only part of the design is selected\n");
- log("\n");
- log(" yosys [modname]>\n");
- log(" the entire module 'modname' is selected using 'select -module modname'\n");
- log("\n");
- log(" yosys [modname]*>\n");
- log(" only part of current module 'modname' is selected\n");
- log("\n");
- log("When in interactive shell, some errors (e.g. invalid command arguments)\n");
- log("do not terminate yosys but return to the command prompt.\n");
- log("\n");
- log("This command is the default action if nothing else has been specified\n");
- log("on the command line.\n");
- log("\n");
- log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n");
- log("\n");
- }
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
- extra_args(args, 1, design, false);
- shell(design);
- }
-} ShellPass;
-
-struct HistoryPass : public Pass {
- HistoryPass() : Pass("history", "show last interactive commands") { }
- virtual void help() {
- log("\n");
- log(" history\n");
- log("\n");
- log("This command prints all commands in the shell history buffer. This are\n");
- log("all commands executed in an interactive session, but not the commands\n");
- log("from executed scripts.\n");
- log("\n");
- }
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
- extra_args(args, 1, design, false);
- for(HIST_ENTRY **list = history_list(); *list != NULL; list++)
- log("%s\n", (*list)->line);
- }
-} HistoryPass;
-
-struct ScriptPass : public Pass {
- ScriptPass() : Pass("script", "execute commands from script file") { }
- virtual void help() {
- log("\n");
- log(" script <filename>\n");
- log("\n");
- log("This command executes the yosys commands in the specified file.\n");
- log("\n");
- }
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
- if (args.size() < 2)
- log_cmd_error("Missing script file.\n");
- if (args.size() > 2)
- extra_args(args, 1, design, false);
- run_frontend(args[1], "script", design, NULL);
- }
-} ScriptPass;
-
-#ifdef YOSYS_ENABLE_TCL
-static Tcl_Interp *yosys_tcl_interp = NULL;
-
-static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
-{
- std::vector<std::string> args;
- for (int i = 1; i < argc; i++)
- args.push_back(argv[i]);
-
- if (args.size() >= 1 && args[0] == "-import") {
- for (auto &it : REGISTER_INTERN::pass_register) {
- std::string tcl_command_name = it.first;
- if (tcl_command_name == "proc")
- tcl_command_name = "procs";
- Tcl_CmdInfo info;
- if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) {
- log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str());
- } else {
- std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str());
- Tcl_Eval(interp, tcl_script.c_str());
- }
- }
- return TCL_OK;
- }
-
- if (args.size() == 1) {
- Pass::call(yosys_get_design(), args[0]);
- return TCL_OK;
- }
-
- Pass::call(yosys_get_design(), args);
- return TCL_OK;
-}
+#include <limits.h>
+#include <errno.h>
-extern Tcl_Interp *yosys_get_tcl_interp()
-{
- if (yosys_tcl_interp == NULL) {
- yosys_tcl_interp = Tcl_CreateInterp();
- Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL);
- }
- return yosys_tcl_interp;
-}
-
-struct TclPass : public Pass {
- TclPass() : Pass("tcl", "execute a TCL script file") { }
- virtual void help() {
- log("\n");
- log(" tcl <filename>\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");
- log("\n");
- log("The tcl command 'yosys -import' can be used to import all yosys\n");
- log("commands directly as tcl commands to the tcl shell. The yosys\n");
- log("command 'proc' is wrapped using the tcl command 'procs' in order\n");
- log("to avoid a name collision with the tcl builting command 'proc'.\n");
- log("\n");
- }
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
- 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()));
- }
-} TclPass;
-#endif
-
-static RTLIL::Design *yosys_design = NULL;
-
-extern RTLIL::Design *yosys_get_design()
-{
- return yosys_design;
-}
-
-std::string rewrite_yosys_exe(std::string exe)
-{
- char buffer[1024];
- ssize_t buflen = readlink("/proc/self/exe", buffer, sizeof(buffer)-1);
-
- if (buflen < 0)
- return exe;
-
- buffer[buflen] = 0;
- std::string newexe = stringf("%s/%s", dirname(buffer), exe.c_str());
- if (access(newexe.c_str(), X_OK) == 0)
- return newexe;
-
- return exe;
-}
-
-std::string get_share_file_name(std::string file)
-{
- char buffer[1024];
- ssize_t buflen = readlink("/proc/self/exe", buffer, sizeof(buffer)-1);
-
- if (buflen < 0)
- log_error("Can't find file `%s': reading of /proc/self/exe failed!\n", file.c_str());
-
- buffer[buflen] = 0;
- const char *dir = dirname(buffer);
-
- std::string newfile_inplace = stringf("%s/share/%s", dir, file.c_str());
- if (access(newfile_inplace.c_str(), F_OK) == 0)
- return newfile_inplace;
-
- std::string newfile_system = stringf("%s/../share/yosys/%s", dir, file.c_str());
- if (access(newfile_system.c_str(), F_OK) == 0)
- return newfile_system;
-
- log_error("Can't find file `%s': no `%s' and no `%s' found!\n", file.c_str(), newfile_inplace.c_str(), newfile_system.c_str());
-}
+USING_YOSYS_NAMESPACE
int main(int argc, char **argv)
{
std::string frontend_command = "auto";
std::string backend_command = "auto";
std::vector<std::string> passes_commands;
- std::vector<void*> loaded_modules;
+ std::vector<std::string> plugin_filenames;
std::string output_filename = "";
std::string scriptfile = "";
bool scriptfile_tcl = false;
bool got_output_filename = false;
+ bool print_banner = true;
+ bool print_stats = true;
+ bool call_abort = false;
+#ifdef YOSYS_ENABLE_READLINE
int history_offset = 0;
std::string history_file;
if (getenv("HOME") != NULL) {
@@ -482,30 +56,30 @@ int main(int argc, char **argv)
read_history(history_file.c_str());
history_offset = where_history();
}
+#endif
int opt;
- while ((opt = getopt(argc, argv, "VSm:f:Hh:b:o:p:l:qv:ts:c:")) != -1)
+ while ((opt = getopt(argc, argv, "AQTVSm:f:Hh:b:o:p:l:qv:ts:c:")) != -1)
{
switch (opt)
{
+ case 'A':
+ call_abort = true;
+ break;
+ case 'Q':
+ print_banner = false;
+ break;
+ case 'T':
+ print_stats = false;
+ break;
case 'V':
printf("%s\n", yosys_version_str);
exit(0);
case 'S':
- passes_commands.push_back("hierarchy");
- passes_commands.push_back("proc");
- passes_commands.push_back("opt");
- passes_commands.push_back("memory");
- passes_commands.push_back("opt");
- passes_commands.push_back("techmap");
- passes_commands.push_back("opt");
+ passes_commands.push_back("synth");
break;
case 'm':
- loaded_modules.push_back(dlopen(optarg, RTLD_LAZY|RTLD_GLOBAL));
- if (loaded_modules.back() == NULL) {
- fprintf(stderr, "Can't load module `%s': %s\n", optarg, dlerror());
- exit(1);
- }
+ plugin_filenames.push_back(optarg);
break;
case 'f':
frontend_command = optarg;
@@ -553,9 +127,15 @@ int main(int argc, char **argv)
break;
default:
fprintf(stderr, "\n");
- fprintf(stderr, "Usage: %s [-V] [-S] [-q] [-v <level>[-t] [-l <logfile>] [-o <outfile>] [-f <frontend>] [-h cmd] \\\n", argv[0]);
+ fprintf(stderr, "Usage: %s [-V -S -Q -T -q] [-v <level>[-t] [-l <logfile>] [-o <outfile>] [-f <frontend>] [-h cmd] \\\n", argv[0]);
fprintf(stderr, " %*s[{-s|-c} <scriptfile>] [-p <pass> [-p ..]] [-b <backend>] [-m <module_file>] [<infile> [..]]\n", int(strlen(argv[0])+1), "");
fprintf(stderr, "\n");
+ fprintf(stderr, " -Q\n");
+ fprintf(stderr, " suppress printing of banner (copyright, disclaimer, version)\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -T\n");
+ fprintf(stderr, " suppress printing of footer (log hash, version, timing statistics)\n");
+ fprintf(stderr, "\n");
fprintf(stderr, " -q\n");
fprintf(stderr, " quiet operation. only write error messages to console\n");
fprintf(stderr, "\n");
@@ -595,13 +175,16 @@ int main(int argc, char **argv)
fprintf(stderr, " -m module_file\n");
fprintf(stderr, " load the specified module (aka plugin)\n");
fprintf(stderr, "\n");
+ fprintf(stderr, " -A\n");
+ fprintf(stderr, " will call abort() at the end of the script. useful for debugging\n");
+ fprintf(stderr, "\n");
fprintf(stderr, " -V\n");
fprintf(stderr, " print version information and exit\n");
fprintf(stderr, "\n");
- fprintf(stderr, "The option -S is an alias for the following options that perform a simple\n");
- fprintf(stderr, "transformation of the input to a gate-level netlist.\n");
+ fprintf(stderr, "The option -S is an shortcut for calling the \"synth\" command, a default\n");
+ fprintf(stderr, "script for transforming the verilog input to a gate-level netlist. For example:\n");
fprintf(stderr, "\n");
- fprintf(stderr, " -p hierarchy -p proc -p opt -p memory -p opt -p techmap -p opt\n");
+ fprintf(stderr, " yosys -o output.blif -S input.v\n");
fprintf(stderr, "\n");
fprintf(stderr, "For more complex synthesis jobs it is recommended to use the read_* and write_*\n");
fprintf(stderr, "commands in a script file instead of specifying input and output files on the\n");
@@ -618,35 +201,39 @@ int main(int argc, char **argv)
if (log_errfile == NULL)
log_files.push_back(stderr);
- log("\n");
- log(" /-----------------------------------------------------------------------------\\\n");
- log(" | |\n");
- log(" | yosys -- Yosys Open SYnthesis Suite |\n");
- log(" | |\n");
- log(" | Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> |\n");
- log(" | |\n");
- log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
- log(" | purpose with or without fee is hereby granted, provided that the above |\n");
- log(" | copyright notice and this permission notice appear in all copies. |\n");
- log(" | |\n");
- log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n");
- log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n");
- log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n");
- log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n");
- log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n");
- log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n");
- log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n");
- log(" | |\n");
- log(" \\-----------------------------------------------------------------------------/\n");
- log("\n");
- log(" %s\n", yosys_version_str);
- log("\n");
-
- Pass::init_register();
-
- yosys_design = new RTLIL::Design;
- yosys_design->selection_stack.push_back(RTLIL::Selection());
- log_push();
+ if (print_banner) {
+ log("\n");
+ log(" /-----------------------------------------------------------------------------\\\n");
+ log(" | |\n");
+ log(" | yosys -- Yosys Open SYnthesis Suite |\n");
+ log(" | |\n");
+ log(" | Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> |\n");
+ log(" | |\n");
+ log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
+ log(" | purpose with or without fee is hereby granted, provided that the above |\n");
+ log(" | copyright notice and this permission notice appear in all copies. |\n");
+ log(" | |\n");
+ log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n");
+ log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n");
+ log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n");
+ log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n");
+ log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n");
+ log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n");
+ log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n");
+ log(" | |\n");
+ log(" \\-----------------------------------------------------------------------------/\n");
+ log("\n");
+ log(" %s\n", yosys_version_str);
+ log("\n");
+ }
+
+ if (print_stats)
+ log_hasher = new SHA1;
+
+ yosys_setup();
+
+ for (auto &fn : plugin_filenames)
+ load_plugin(fn, {});
if (optind == argc && passes_commands.size() == 0 && scriptfile.empty()) {
if (!got_output_filename)
@@ -655,7 +242,7 @@ int main(int argc, char **argv)
}
while (optind < argc)
- run_frontend(argv[optind++], frontend_command, yosys_design, output_filename == "-" ? &backend_command : NULL);
+ run_frontend(argv[optind++], frontend_command, yosys_design, output_filename == "-" ? &backend_command : NULL, NULL);
if (!scriptfile.empty()) {
if (scriptfile_tcl) {
@@ -666,7 +253,7 @@ int main(int argc, char **argv)
log_error("Can't exectue TCL script: this version of yosys is not built with TCL support enabled.\n");
#endif
} else
- run_frontend(scriptfile, "script", yosys_design, output_filename == "-" ? &backend_command : NULL);
+ run_frontend(scriptfile, "script", yosys_design, output_filename == "-" ? &backend_command : NULL, NULL);
}
for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
@@ -675,12 +262,72 @@ int main(int argc, char **argv)
if (!backend_command.empty())
run_backend(output_filename, backend_command, yosys_design);
- delete yosys_design;
- yosys_design = NULL;
+ if (print_stats)
+ {
+ std::string hash = log_hasher->final().substr(0, 10);
+ delete log_hasher;
+ log_hasher = nullptr;
+
+ struct rusage ru_buffer;
+ getrusage(RUSAGE_SELF, &ru_buffer);
+ log_spacer();
+ log("End of script. Logfile hash: %s, CPU: user %.2fs system %.2fs\n", hash.c_str(),
+ ru_buffer.ru_utime.tv_sec + 1e-6 * ru_buffer.ru_utime.tv_usec,
+ ru_buffer.ru_stime.tv_sec + 1e-6 * ru_buffer.ru_stime.tv_usec);
+ log("%s\n", yosys_version_str);
+
+ int64_t total_ns = 0;
+ std::set<std::tuple<int64_t, int, std::string>> timedat;
+
+ for (auto &it : pass_register)
+ if (it.second->call_counter) {
+ total_ns += it.second->runtime_ns + 1;
+ timedat.insert(make_tuple(it.second->runtime_ns + 1, it.second->call_counter, it.first));
+ }
+
+ int out_count = 0;
+ log("Time spent:");
+ for (auto it = timedat.rbegin(); it != timedat.rend() && out_count < 4; it++, out_count++) {
+ if (out_count >= 2 && (std::get<0>(*it) < 1000000000 || int(100*std::get<0>(*it) / total_ns) < 20)) {
+ log(", ...");
+ break;
+ }
+ log("%s %d%% %dx %s (%d sec)", out_count ? "," : "", int(100*std::get<0>(*it) / total_ns),
+ std::get<1>(*it), std::get<2>(*it).c_str(), int(std::get<0>(*it) / 1000000000));
+ }
+ log("%s\n", out_count ? "" : " no commands executed");
+ }
+
+#ifdef COVER_ACTIVE
+ if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE"))
+ {
+ char filename_buffer[4096];
+ FILE *f;
+
+ if (getenv("YOSYS_COVER_DIR")) {
+ snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", getenv("YOSYS_COVER_DIR"), getpid());
+ f = fdopen(mkstemps(filename_buffer, 4), "w");
+ } else {
+ snprintf(filename_buffer, 4096, "%s", getenv("YOSYS_COVER_FILE"));
+ f = fopen(filename_buffer, "a+");
+ }
+
+ if (f == NULL)
+ log_error("Can't create coverage file `%s'.\n", filename_buffer);
+
+ log("<writing coverage file \"%s\">\n", filename_buffer);
- log("\nREADY.\n");
- log_pop();
+ for (auto &it : get_coverage_data())
+ fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str());
+ fclose(f);
+ }
+#endif
+
+ if (call_abort)
+ abort();
+
+#ifdef YOSYS_ENABLE_READLINE
if (!history_file.empty()) {
if (history_offset > 0) {
history_truncate_file(history_file.c_str(), 100);
@@ -693,26 +340,10 @@ int main(int argc, char **argv)
HIST_ENTRY **hist_list = history_list();
if (hist_list != NULL)
free(hist_list);
-
- for (auto f : log_files)
- if (f != stderr)
- fclose(f);
- log_errfile = NULL;
- log_files.clear();
-
- Pass::done_register();
-
- for (auto mod : loaded_modules)
- dlclose(mod);
-
-#ifdef YOSYS_ENABLE_TCL
- if (yosys_tcl_interp != NULL) {
- Tcl_DeleteInterp(yosys_tcl_interp);
- Tcl_Finalize();
- yosys_tcl_interp = NULL;
- }
#endif
+ yosys_shutdown();
+
return 0;
}
diff --git a/kernel/log.cc b/kernel/log.cc
index 779f9373..1b0eb664 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -17,7 +17,8 @@
*
*/
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+#include "libs/sha1/sha1.h"
#include "backends/ilang/ilang_backend.h"
#include <sys/time.h>
@@ -28,44 +29,50 @@
#include <vector>
#include <list>
+YOSYS_NAMESPACE_BEGIN
+
std::vector<FILE*> log_files;
+std::vector<std::ostream*> log_streams;
FILE *log_errfile = NULL;
+SHA1 *log_hasher = NULL;
+
bool log_time = false;
bool log_cmd_error_throw = false;
int log_verbose_level;
std::vector<int> header_count;
std::list<std::string> string_buf;
+int string_buf_size = 0;
static struct timeval initial_tv = { 0, 0 };
static bool next_print_log = false;
+static int log_newline_count = 0;
-std::string stringf(const char *fmt, ...)
+void logv(const char *format, va_list ap)
{
- std::string string;
- char *str = NULL;
- va_list ap;
+ while (format[0] == '\n' && format[1] != 0) {
+ log("\n");
+ format++;
+ }
- va_start(ap, fmt);
- if (vasprintf(&str, fmt, ap) < 0)
- str = NULL;
- va_end(ap);
+ std::string str = vstringf(format, ap);
- if (str != NULL) {
- string = str;
- free(str);
- }
+ if (str.empty())
+ return;
- return string;
-}
+ size_t nnl_pos = str.find_last_not_of('\n');
+ if (nnl_pos == std::string::npos)
+ log_newline_count += SIZE(str);
+ else
+ log_newline_count = SIZE(str) - nnl_pos - 1;
+
+ if (log_hasher)
+ log_hasher->update(str);
+
+ if (log_time)
+ {
+ std::string time_str;
-void logv(const char *format, va_list ap)
-{
- if (log_time) {
- while (format[0] == '\n' && format[1] != 0) {
- format++;
- log("\n");
- }
if (next_print_log || initial_tv.tv_sec == 0) {
next_print_log = false;
struct timeval tv;
@@ -78,48 +85,56 @@ void logv(const char *format, va_list ap)
}
tv.tv_sec -= initial_tv.tv_sec;
tv.tv_usec -= initial_tv.tv_usec;
- log("[%05d.%06d] ", int(tv.tv_sec), int(tv.tv_usec));
+ time_str += stringf("[%05d.%06d] ", int(tv.tv_sec), int(tv.tv_usec));
}
+
if (format[0] && format[strlen(format)-1] == '\n')
next_print_log = true;
- }
- for (auto f : log_files) {
- va_list aq;
- va_copy(aq, ap);
- vfprintf(f, format, aq);
- va_end(aq);
+ for (auto f : log_files)
+ fputs(time_str.c_str(), f);
+
+ for (auto f : log_streams)
+ *f << time_str;
}
+
+ for (auto f : log_files)
+ fputs(str.c_str(), f);
+
+ for (auto f : log_streams)
+ *f << str;
}
void logv_header(const char *format, va_list ap)
{
- log("\n");
+ bool pop_errfile = false;
+
+ log_spacer();
if (header_count.size() > 0)
header_count.back()++;
+
+ if (int(header_count.size()) <= log_verbose_level && log_errfile != NULL) {
+ log_files.push_back(log_errfile);
+ pop_errfile = true;
+ }
+
for (int c : header_count)
log("%d.", c);
log(" ");
logv(format, ap);
log_flush();
- if (int(header_count.size()) <= log_verbose_level && log_errfile != NULL) {
- for (int c : header_count)
- fprintf(log_errfile, "%d.", c);
- fprintf(log_errfile, " ");
- vfprintf(log_errfile, format, ap);
- fflush(log_errfile);
- }
+ if (pop_errfile)
+ log_files.pop_back();
}
void logv_error(const char *format, va_list ap)
{
+ if (log_errfile != NULL)
+ log_files.push_back(log_errfile);
+
log("ERROR: ");
logv(format, ap);
- if (log_errfile != NULL) {
- fprintf(log_errfile, "ERROR: ");
- vfprintf(log_errfile, format, ap);
- }
log_flush();
exit(1);
}
@@ -156,12 +171,18 @@ void log_cmd_error(const char *format, ...)
log("ERROR: ");
logv(format, ap);
log_flush();
- throw 0;
+ throw log_cmd_error_expection();
}
logv_error(format, ap);
}
+void log_spacer()
+{
+ while (log_newline_count < 2)
+ log("\n");
+}
+
void log_push()
{
header_count.push_back(0);
@@ -171,6 +192,7 @@ void log_pop()
{
header_count.pop_back();
string_buf.clear();
+ string_buf_size = 0;
log_flush();
}
@@ -179,6 +201,7 @@ void log_reset_stack()
while (header_count.size() > 1)
header_count.pop_back();
string_buf.clear();
+ string_buf_size = 0;
log_flush();
}
@@ -186,21 +209,95 @@ void log_flush()
{
for (auto f : log_files)
fflush(f);
+
+ for (auto f : log_streams)
+ f->flush();
+}
+
+void log_dump_val_worker(RTLIL::SigSpec v) {
+ log("%s", log_signal(v));
}
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
{
- char *ptr;
- size_t size;
+ std::stringstream buf;
+ ILANG_BACKEND::dump_sigspec(buf, sig, autoint);
- FILE *f = open_memstream(&ptr, &size);
- ILANG_BACKEND::dump_sigspec(f, sig, autoint);
- fputc(0, f);
- fclose(f);
-
- string_buf.push_back(ptr);
- free(ptr);
+ if (string_buf_size < 100)
+ string_buf_size++;
+ else
+ string_buf.pop_front();
+ string_buf.push_back(buf.str());
return string_buf.back().c_str();
}
+const char *log_id(RTLIL::IdString str)
+{
+ const char *p = str.c_str();
+ log_assert(RTLIL::IdString::global_refcount_storage_[str.index_] > 1);
+ if (p[0] == '\\' && p[1] != '$' && p[1] != 0)
+ return p+1;
+ return p;
+}
+
+void log_cell(RTLIL::Cell *cell, std::string indent)
+{
+ std::stringstream buf;
+ ILANG_BACKEND::dump_cell(buf, indent, cell);
+ log("%s", buf.str().c_str());
+}
+
+// ---------------------------------------------------
+// This is the magic behind the code coverage counters
+// ---------------------------------------------------
+#ifdef COVER_ACTIVE
+
+std::map<std::string, std::pair<std::string, int>> extra_coverage_data;
+
+void cover_extra(std::string parent, std::string id, bool increment) {
+ if (extra_coverage_data.count(id) == 0) {
+ for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++)
+ if (p->id == parent)
+ extra_coverage_data[id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
+ log_assert(extra_coverage_data.count(id));
+ }
+ if (increment)
+ extra_coverage_data[id].second++;
+}
+
+std::map<std::string, std::pair<std::string, int>> get_coverage_data()
+{
+ std::map<std::string, std::pair<std::string, int>> coverage_data;
+
+ for (auto &it : pass_register) {
+ std::string key = stringf("passes.%s", it.first.c_str());
+ coverage_data[key].first = stringf("%s:%d:%s", __FILE__, __LINE__, __FUNCTION__);
+ coverage_data[key].second += it.second->call_counter;
+ }
+
+ for (auto &it : extra_coverage_data) {
+ if (coverage_data.count(it.first))
+ log("WARNING: found duplicate coverage id \"%s\".\n", it.first.c_str());
+ coverage_data[it.first].first = it.second.first;
+ coverage_data[it.first].second += it.second.second;
+ }
+
+ for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) {
+ if (coverage_data.count(p->id))
+ log("WARNING: found duplicate coverage id \"%s\".\n", p->id);
+ coverage_data[p->id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
+ coverage_data[p->id].second += p->counter;
+ }
+
+ for (auto &it : coverage_data)
+ if (!it.second.first.compare(0, strlen(YOSYS_SRC "/"), YOSYS_SRC "/"))
+ it.second.first = it.second.first.substr(strlen(YOSYS_SRC "/"));
+
+ return coverage_data;
+}
+
+#endif
+
+YOSYS_NAMESPACE_END
+
diff --git a/kernel/log.h b/kernel/log.h
index c4c03352..e2b4db87 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -17,22 +17,32 @@
*
*/
+#include "kernel/yosys.h"
+
#ifndef LOG_H
#define LOG_H
-#include "kernel/rtlil.h"
-#include <stdio.h>
#include <time.h>
-#include <vector>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+YOSYS_NAMESPACE_BEGIN
+
+#define S__LINE__sub2(x) #x
+#define S__LINE__sub1(x) S__LINE__sub2(x)
+#define S__LINE__ S__LINE__sub1(__LINE__)
+
+struct log_cmd_error_expection { };
extern std::vector<FILE*> log_files;
+extern std::vector<std::ostream*> log_streams;
extern FILE *log_errfile;
+extern class SHA1 *log_hasher;
+
extern bool log_time;
extern bool log_cmd_error_throw;
extern int log_verbose_level;
-std::string stringf(const char *fmt, ...);
-
void logv(const char *format, va_list ap);
void logv_header(const char *format, va_list ap);
void logv_error(const char *format, va_list ap) __attribute__ ((noreturn));
@@ -42,6 +52,7 @@ void log_header(const char *format, ...) __attribute__ ((format (printf, 1, 2)))
void log_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
void log_cmd_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
+void log_spacer();
void log_push();
void log_pop();
@@ -49,9 +60,70 @@ void log_reset_stack();
void log_flush();
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
+const char *log_id(RTLIL::IdString id);
+
+template<typename T> static inline const char *log_id(T *obj) {
+ return log_id(obj->name);
+}
+
+void log_cell(RTLIL::Cell *cell, std::string indent = "");
#define log_abort() log_error("Abort in %s:%d.\n", __FILE__, __LINE__)
#define log_assert(_assert_expr_) do { if (_assert_expr_) break; log_error("Assert `%s' failed in %s:%d.\n", #_assert_expr_, __FILE__, __LINE__); } while (0)
+#define log_ping() log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+
+// ---------------------------------------------------
+// This is the magic behind the code coverage counters
+// ---------------------------------------------------
+
+#if defined(__linux__) && !defined(NDEBUG)
+#define COVER_ACTIVE
+
+#define cover(_id) do { \
+ static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1))) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
+ __d.counter++; \
+} while (0)
+
+struct CoverData {
+ const char *file, *func, *id;
+ int line, counter;
+} __attribute__ ((packed));
+
+// this two symbols are created by the linker for the "yosys_cover_list" ELF section
+extern "C" struct CoverData __start_yosys_cover_list[];
+extern "C" struct CoverData __stop_yosys_cover_list[];
+
+extern std::map<std::string, std::pair<std::string, int>> extra_coverage_data;
+
+void cover_extra(std::string parent, std::string id, bool increment = true);
+std::map<std::string, std::pair<std::string, int>> get_coverage_data();
+
+#define cover_list(_id, ...) do { cover(_id); \
+ std::string r = cover_list_worker(_id, __VA_ARGS__); \
+ log_assert(r.empty()); \
+} while (0)
+
+static inline std::string cover_list_worker(std::string, std::string last) {
+ return last;
+}
+
+template<typename... T>
+std::string cover_list_worker(std::string prefix, std::string first, T... rest) {
+ std::string selected = cover_list_worker(prefix, rest...);
+ cover_extra(prefix, prefix + "." + first, first == selected);
+ return first == selected ? "" : selected;
+}
+
+#else
+# define cover(...) do { } while (0)
+# define cover_list(...) do { } while (0)
+#endif
+
+
+// ------------------------------------------------------------
+// everything below this line are utilities for troubleshooting
+// ------------------------------------------------------------
// simple timer for performance measurements
// toggle the '#if 1' to get a baseline for the perormance penalty added by the measurement
@@ -65,30 +137,45 @@ struct PerformanceTimer
}
static int64_t query() {
+#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
struct timespec ts;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
return int64_t(ts.tv_sec)*1000000000 + ts.tv_nsec;
+#elif defined(RUSAGE_SELF)
+ struct rusage rusage;
+ int64_t t;
+ if (getrusage(RUSAGE_SELF, &rusage) == -1) {
+ log_cmd_error("getrusage failed!\n");
+ log_abort();
+ }
+ t = 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL;
+ t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL;
+ return t;
+#else
+ #error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?).
+#endif
}
void reset() {
total_ns = 0;
}
- void add() {
- total_ns += query();
+ void begin() {
+ total_ns -= query();
}
- void sub() {
- total_ns -= query();
+ void end() {
+ total_ns += query();
}
float sec() const {
return total_ns * 1e-9;
}
#else
+ static int64_t query() { return 0; }
void reset() { }
- void add() { }
- void sub() { }
+ void begin() { }
+ void end() { }
float sec() const { return 0; }
#endif
};
@@ -107,12 +194,17 @@ static inline void log_dump_val_worker(char c) { log(c >= 32 && c < 127 ? "'%c'"
static inline void log_dump_val_worker(unsigned char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", c); }
static inline void log_dump_val_worker(bool v) { log("%s", v ? "true" : "false"); }
static inline void log_dump_val_worker(double v) { log("%f", v); }
+static inline void log_dump_val_worker(char *v) { log("%s", v); }
static inline void log_dump_val_worker(const char *v) { log("%s", v); }
static inline void log_dump_val_worker(std::string v) { log("%s", v.c_str()); }
-static inline void log_dump_val_worker(RTLIL::SigSpec v) { log("%s", log_signal(v)); }
+static inline void log_dump_val_worker(PerformanceTimer p) { log("%f seconds", p.sec()); }
static inline void log_dump_args_worker(const char *p) { log_assert(*p == 0); }
+void log_dump_val_worker(RTLIL::SigSpec v);
-template <typename T, typename ... Args>
+template<typename T>
+static inline void log_dump_val_worker(T *ptr) { log("%p", ptr); }
+
+template<typename T, typename ... Args>
void log_dump_args_worker(const char *p, T first, Args ... args)
{
int next_p_state = 0;
@@ -152,4 +244,6 @@ void log_dump_args_worker(const char *p, T first, Args ... args)
log("\n"); \
} while (0)
+YOSYS_NAMESPACE_END
+
#endif
diff --git a/kernel/macc.h b/kernel/macc.h
new file mode 100644
index 00000000..27114111
--- /dev/null
+++ b/kernel/macc.h
@@ -0,0 +1,231 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef MACC_H
+#define MACC_H
+
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+struct Macc
+{
+ struct port_t {
+ RTLIL::SigSpec in_a, in_b;
+ bool is_signed, do_subtract;
+ };
+
+ std::vector<port_t> ports;
+ RTLIL::SigSpec bit_ports;
+
+ void optimize(int width)
+ {
+ std::vector<port_t> new_ports;
+ RTLIL::SigSpec new_bit_ports;
+ RTLIL::Const off(0, width);
+
+ for (auto &port : ports)
+ {
+ if (SIZE(port.in_a) == 0 && SIZE(port.in_b) == 0)
+ continue;
+
+ if (SIZE(port.in_a) == 1 && SIZE(port.in_b) == 0 && !port.is_signed && !port.do_subtract) {
+ bit_ports.append(port.in_a);
+ continue;
+ }
+
+ if (port.in_a.is_fully_const() && port.in_b.is_fully_const()) {
+ RTLIL::Const v = port.in_a.as_const();
+ if (SIZE(port.in_b))
+ v = const_mul(v, port.in_b.as_const(), port.is_signed, port.is_signed, width);
+ if (port.do_subtract)
+ off = const_sub(off, v, port.is_signed, port.is_signed, width);
+ else
+ off = const_add(off, v, port.is_signed, port.is_signed, width);
+ continue;
+ }
+
+ if (port.is_signed) {
+ while (SIZE(port.in_a) > 1 && port.in_a[SIZE(port.in_a)-1] == port.in_a[SIZE(port.in_a)-2])
+ port.in_a.remove(SIZE(port.in_a)-1);
+ while (SIZE(port.in_b) > 1 && port.in_b[SIZE(port.in_b)-1] == port.in_b[SIZE(port.in_b)-2])
+ port.in_b.remove(SIZE(port.in_b)-1);
+ } else {
+ while (SIZE(port.in_a) > 1 && port.in_a[SIZE(port.in_a)-1] == RTLIL::S0)
+ port.in_a.remove(SIZE(port.in_a)-1);
+ while (SIZE(port.in_b) > 1 && port.in_b[SIZE(port.in_b)-1] == RTLIL::S0)
+ port.in_b.remove(SIZE(port.in_b)-1);
+ }
+
+ new_ports.push_back(port);
+ }
+
+ for (auto &bit : bit_ports)
+ if (bit == RTLIL::S1)
+ off = const_add(off, RTLIL::Const(1, width), false, false, width);
+ else if (bit != RTLIL::S0)
+ new_bit_ports.append(bit);
+
+ if (off.as_bool()) {
+ port_t port;
+ port.in_a = off;
+ port.is_signed = false;
+ port.do_subtract = false;
+ new_ports.push_back(port);
+ }
+
+ new_ports.swap(ports);
+ bit_ports = new_bit_ports;
+ }
+
+ void from_cell(RTLIL::Cell *cell)
+ {
+ RTLIL::SigSpec port_a = cell->getPort("\\A");
+
+ ports.clear();
+ bit_ports = cell->getPort("\\B");
+
+ std::vector<RTLIL::State> config_bits = cell->getParam("\\CONFIG").bits;
+ int config_width = cell->getParam("\\CONFIG_WIDTH").as_int();
+ int config_cursor = 0;
+
+ log_assert(SIZE(config_bits) >= config_width);
+
+ int num_bits = 0;
+ if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 1;
+ if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 2;
+ if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 4;
+ if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 8;
+
+ int port_a_cursor = 0;
+ while (port_a_cursor < SIZE(port_a))
+ {
+ log_assert(config_cursor + 2 + 2*num_bits <= config_width);
+
+ port_t this_port;
+ this_port.is_signed = config_bits[config_cursor++] == RTLIL::S1;
+ this_port.do_subtract = config_bits[config_cursor++] == RTLIL::S1;
+
+ int size_a = 0;
+ for (int i = 0; i < num_bits; i++)
+ if (config_bits[config_cursor++] == RTLIL::S1)
+ size_a |= 1 << i;
+
+ this_port.in_a = port_a.extract(port_a_cursor, size_a);
+ port_a_cursor += size_a;
+
+ int size_b = 0;
+ for (int i = 0; i < num_bits; i++)
+ if (config_bits[config_cursor++] == RTLIL::S1)
+ size_b |= 1 << i;
+
+ this_port.in_b = port_a.extract(port_a_cursor, size_b);
+ port_a_cursor += size_b;
+
+ if (size_a || size_b)
+ ports.push_back(this_port);
+ }
+
+ log_assert(config_cursor == config_width);
+ log_assert(port_a_cursor == SIZE(port_a));
+ }
+
+ void to_cell(RTLIL::Cell *cell) const
+ {
+ RTLIL::SigSpec port_a;
+ std::vector<RTLIL::State> config_bits;
+ int max_size = 0, num_bits = 0;
+
+ for (auto &port : ports) {
+ max_size = std::max(max_size, SIZE(port.in_a));
+ max_size = std::max(max_size, SIZE(port.in_b));
+ }
+
+ while (max_size)
+ num_bits++, max_size /= 2;
+
+ log_assert(num_bits < 16);
+ config_bits.push_back(num_bits & 1 ? RTLIL::S1 : RTLIL::S0);
+ config_bits.push_back(num_bits & 2 ? RTLIL::S1 : RTLIL::S0);
+ config_bits.push_back(num_bits & 4 ? RTLIL::S1 : RTLIL::S0);
+ config_bits.push_back(num_bits & 8 ? RTLIL::S1 : RTLIL::S0);
+
+ for (auto &port : ports)
+ {
+ if (SIZE(port.in_a) == 0)
+ continue;
+
+ config_bits.push_back(port.is_signed ? RTLIL::S1 : RTLIL::S0);
+ config_bits.push_back(port.do_subtract ? RTLIL::S1 : RTLIL::S0);
+
+ int size_a = SIZE(port.in_a);
+ for (int i = 0; i < num_bits; i++)
+ config_bits.push_back(size_a & (1 << i) ? RTLIL::S1 : RTLIL::S0);
+
+ int size_b = SIZE(port.in_b);
+ for (int i = 0; i < num_bits; i++)
+ config_bits.push_back(size_b & (1 << i) ? RTLIL::S1 : RTLIL::S0);
+
+ port_a.append(port.in_a);
+ port_a.append(port.in_b);
+ }
+
+ cell->setPort("\\A", port_a);
+ cell->setPort("\\B", bit_ports);
+ cell->setParam("\\CONFIG", config_bits);
+ cell->setParam("\\CONFIG_WIDTH", SIZE(config_bits));
+ cell->setParam("\\A_WIDTH", SIZE(port_a));
+ cell->setParam("\\B_WIDTH", SIZE(bit_ports));
+ }
+
+ bool eval(RTLIL::Const &result) const
+ {
+ for (auto &bit : result.bits)
+ bit = RTLIL::S0;
+
+ for (auto &port : ports)
+ {
+ if (!port.in_a.is_fully_const() || !port.in_b.is_fully_const())
+ return false;
+
+ RTLIL::Const summand;
+ if (SIZE(port.in_b) == 0)
+ summand = const_pos(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, SIZE(result));
+ else
+ summand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, SIZE(result));
+
+ if (port.do_subtract)
+ result = const_sub(result, summand, port.is_signed, port.is_signed, SIZE(result));
+ else
+ result = const_add(result, summand, port.is_signed, port.is_signed, SIZE(result));
+ }
+
+ for (auto bit : bit_ports) {
+ if (bit.wire)
+ return false;
+ result = const_add(result, bit.data, false, false, SIZE(result));
+ }
+
+ return true;
+ }
+};
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/kernel/modtools.h b/kernel/modtools.h
new file mode 100644
index 00000000..58cdd5b0
--- /dev/null
+++ b/kernel/modtools.h
@@ -0,0 +1,455 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef MODTOOLS_H
+#define MODTOOLS_H
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+struct ModIndex : public RTLIL::Monitor
+{
+ struct PortInfo {
+ RTLIL::Cell* cell;
+ RTLIL::IdString port;
+ int offset;
+
+ PortInfo(RTLIL::Cell* _c, RTLIL::IdString _p, int _o) : cell(_c), port(_p), offset(_o) { }
+
+ bool operator<(const PortInfo &other) const {
+ if (cell != other.cell)
+ return cell < other.cell;
+ if (offset != other.offset)
+ return offset < other.offset;
+ return port < other.port;
+ }
+ };
+
+ struct SigBitInfo
+ {
+ bool is_input, is_output;
+ std::set<PortInfo> ports;
+
+ SigBitInfo() : is_input(false), is_output(false) { }
+ };
+
+ SigMap sigmap;
+ RTLIL::Module *module;
+ std::map<RTLIL::SigBit, SigBitInfo> database;
+ bool auto_reload_module;
+
+ void port_add(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig)
+ {
+ for (int i = 0; i < SIZE(sig); i++) {
+ RTLIL::SigBit bit = sigmap(sig[i]);
+ if (bit.wire)
+ database[bit].ports.insert(PortInfo(cell, port, i));
+ }
+ }
+
+ void port_del(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig)
+ {
+ for (int i = 0; i < SIZE(sig); i++) {
+ RTLIL::SigBit bit = sigmap(sig[i]);
+ if (bit.wire)
+ database[bit].ports.erase(PortInfo(cell, port, i));
+ }
+ }
+
+ const SigBitInfo &info(RTLIL::SigBit bit)
+ {
+ return database[sigmap(bit)];
+ }
+
+ void reload_module()
+ {
+ sigmap.clear();
+ sigmap.set(module);
+
+ database.clear();
+ for (auto wire : module->wires())
+ if (wire->port_input || wire->port_output)
+ for (int i = 0; i < SIZE(wire); i++) {
+ RTLIL::SigBit bit = sigmap(RTLIL::SigBit(wire, i));
+ if (bit.wire && wire->port_input)
+ database[bit].is_input = true;
+ if (bit.wire && wire->port_output)
+ database[bit].is_output = true;
+ }
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections())
+ port_add(cell, conn.first, conn.second);
+
+ auto_reload_module = false;
+ }
+
+ virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) OVERRIDE
+ {
+ if (auto_reload_module)
+ reload_module();
+
+ port_del(cell, port, old_sig);
+ port_add(cell, port, sig);
+ }
+
+ virtual void notify_connect(RTLIL::Module *mod, const RTLIL::SigSig&)
+ {
+ log_assert(module == mod);
+ auto_reload_module = true;
+ }
+
+ virtual void notify_connect(RTLIL::Module *mod, const std::vector<RTLIL::SigSig>&)
+ {
+ log_assert(module == mod);
+ auto_reload_module = true;
+ }
+
+ virtual void notify_blackout(RTLIL::Module *mod)
+ {
+ log_assert(module == mod);
+ auto_reload_module = true;
+ }
+
+ ModIndex(RTLIL::Module *_m) : module(_m)
+ {
+ auto_reload_module = true;
+ module->monitors.insert(this);
+ }
+
+ ~ModIndex()
+ {
+ module->monitors.erase(this);
+ }
+
+ SigBitInfo *query(RTLIL::SigBit bit)
+ {
+ if (auto_reload_module)
+ reload_module();
+
+ auto it = database.find(sigmap(bit));
+ if (it == database.end())
+ return nullptr;
+ else
+ return &it->second;
+ }
+
+ bool query_is_input(RTLIL::SigBit bit)
+ {
+ const SigBitInfo *info = query(bit);
+ if (info == nullptr)
+ return false;
+ return info->is_input;
+ }
+
+ bool query_is_output(RTLIL::SigBit bit)
+ {
+ const SigBitInfo *info = query(bit);
+ if (info == nullptr)
+ return false;
+ return info->is_output;
+ }
+
+ std::set<PortInfo> &query_ports(RTLIL::SigBit bit)
+ {
+ static std::set<PortInfo> empty_result_set;
+ SigBitInfo *info = query(bit);
+ if (info == nullptr)
+ return empty_result_set;
+ return info->ports;
+ }
+};
+
+struct ModWalker
+{
+ struct PortBit
+ {
+ RTLIL::Cell *cell;
+ RTLIL::IdString port;
+ int offset;
+
+ bool operator<(const PortBit &other) const {
+ if (cell != other.cell)
+ return cell < other.cell;
+ if (port != other.port)
+ return port < other.port;
+ return offset < other.offset;
+ }
+ };
+
+ RTLIL::Design *design;
+ RTLIL::Module *module;
+
+ CellTypes ct;
+ SigMap sigmap;
+
+ std::map<RTLIL::SigBit, std::set<PortBit>> signal_drivers;
+ std::map<RTLIL::SigBit, std::set<PortBit>> signal_consumers;
+ std::set<RTLIL::SigBit> signal_inputs, signal_outputs;
+
+ std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_outputs, cell_inputs;
+
+ void add_wire(RTLIL::Wire *wire)
+ {
+ if (wire->port_input) {
+ std::vector<RTLIL::SigBit> bits = sigmap(wire);
+ for (auto bit : bits)
+ if (bit.wire != NULL)
+ signal_inputs.insert(bit);
+ }
+
+ if (wire->port_output) {
+ std::vector<RTLIL::SigBit> bits = sigmap(wire);
+ for (auto bit : bits)
+ if (bit.wire != NULL)
+ signal_outputs.insert(bit);
+ }
+ }
+
+ void add_cell_port(RTLIL::Cell *cell, RTLIL::IdString port, std::vector<RTLIL::SigBit> bits, bool is_output, bool is_input)
+ {
+ for (int i = 0; i < int(bits.size()); i++)
+ if (bits[i].wire != NULL) {
+ PortBit pbit = { cell, port, i };
+ if (is_output) {
+ signal_drivers[bits[i]].insert(pbit);
+ cell_outputs[cell].insert(bits[i]);
+ }
+ if (is_input) {
+ signal_consumers[bits[i]].insert(pbit);
+ cell_inputs[cell].insert(bits[i]);
+ }
+ }
+ }
+
+ void add_cell(RTLIL::Cell *cell)
+ {
+ if (ct.cell_known(cell->type)) {
+ for (auto &conn : cell->connections())
+ add_cell_port(cell, conn.first, sigmap(conn.second),
+ ct.cell_output(cell->type, conn.first),
+ ct.cell_input(cell->type, conn.first));
+ } else {
+ for (auto &conn : cell->connections())
+ add_cell_port(cell, conn.first, sigmap(conn.second), true, true);
+ }
+ }
+
+ ModWalker() : design(NULL), module(NULL)
+ {
+ }
+
+ ModWalker(RTLIL::Design *design, RTLIL::Module *module, CellTypes *filter_ct = NULL)
+ {
+ setup(design, module, filter_ct);
+ }
+
+ void setup(RTLIL::Design *design, RTLIL::Module *module, CellTypes *filter_ct = NULL)
+ {
+ this->design = design;
+ this->module = module;
+
+ ct.clear();
+ ct.setup(design);
+ sigmap.set(module);
+
+ signal_drivers.clear();
+ signal_consumers.clear();
+ signal_inputs.clear();
+ signal_outputs.clear();
+
+ for (auto &it : module->wires_)
+ add_wire(it.second);
+ for (auto &it : module->cells_)
+ if (filter_ct == NULL || filter_ct->cell_known(it.second->type))
+ add_cell(it.second);
+ }
+
+ // get_* methods -- single RTLIL::SigBit
+
+ template<typename T>
+ inline bool get_drivers(std::set<PortBit> &result, RTLIL::SigBit bit) const
+ {
+ bool found = false;
+ if (signal_drivers.count(bit)) {
+ const std::set<PortBit> &r = signal_drivers.at(bit);
+ result.insert(r.begin(), r.end());
+ found = true;
+ }
+ return found;
+ }
+
+ template<typename T>
+ inline bool get_consumers(std::set<PortBit> &result, RTLIL::SigBit bit) const
+ {
+ bool found = false;
+ if (signal_consumers.count(bit)) {
+ const std::set<PortBit> &r = signal_consumers.at(bit);
+ result.insert(r.begin(), r.end());
+ found = true;
+ }
+ return found;
+ }
+
+ template<typename T>
+ inline bool get_inputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
+ {
+ bool found = false;
+ if (signal_inputs.count(bit))
+ result.insert(bit), found = true;
+ return found;
+ }
+
+ template<typename T>
+ inline bool get_outputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
+ {
+ bool found = false;
+ if (signal_outputs.count(bit))
+ result.insert(bit), found = true;
+ return found;
+ }
+
+ // get_* methods -- container of RTLIL::SigBit's (always by reference)
+
+ template<typename T>
+ inline bool get_drivers(std::set<PortBit> &result, const T &bits) const
+ {
+ bool found = false;
+ for (RTLIL::SigBit bit : bits)
+ if (signal_drivers.count(bit)) {
+ const std::set<PortBit> &r = signal_drivers.at(bit);
+ result.insert(r.begin(), r.end());
+ found = true;
+ }
+ return found;
+ }
+
+ template<typename T>
+ inline bool get_consumers(std::set<PortBit> &result, const T &bits) const
+ {
+ bool found = false;
+ for (RTLIL::SigBit bit : bits)
+ if (signal_consumers.count(bit)) {
+ const std::set<PortBit> &r = signal_consumers.at(bit);
+ result.insert(r.begin(), r.end());
+ found = true;
+ }
+ return found;
+ }
+
+ template<typename T>
+ inline bool get_inputs(std::set<RTLIL::SigBit> &result, const T &bits) const
+ {
+ bool found = false;
+ for (RTLIL::SigBit bit : bits)
+ if (signal_inputs.count(bit))
+ result.insert(bit), found = true;
+ return found;
+ }
+
+ template<typename T>
+ inline bool get_outputs(std::set<RTLIL::SigBit> &result, const T &bits) const
+ {
+ bool found = false;
+ for (RTLIL::SigBit bit : bits)
+ if (signal_outputs.count(bit))
+ result.insert(bit), found = true;
+ return found;
+ }
+
+ // get_* methods -- call by RTLIL::SigSpec (always by value)
+
+ bool get_drivers(std::set<PortBit> &result, RTLIL::SigSpec signal) const
+ {
+ std::vector<RTLIL::SigBit> bits = sigmap(signal);
+ return get_drivers(result, bits);
+ }
+
+ bool get_consumers(std::set<PortBit> &result, RTLIL::SigSpec signal) const
+ {
+ std::vector<RTLIL::SigBit> bits = sigmap(signal);
+ return get_consumers(result, bits);
+ }
+
+ bool get_inputs(std::set<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
+ {
+ std::vector<RTLIL::SigBit> bits = sigmap(signal);
+ return get_inputs(result, bits);
+ }
+
+ bool get_outputs(std::set<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
+ {
+ std::vector<RTLIL::SigBit> bits = sigmap(signal);
+ return get_outputs(result, bits);
+ }
+
+ // has_* methods -- call by reference
+
+ template<typename T>
+ inline bool has_drivers(const T &sig) const {
+ std::set<PortBit> result;
+ return get_drivers(result, sig);
+ }
+
+ template<typename T>
+ inline bool has_consumers(const T &sig) const {
+ std::set<PortBit> result;
+ return get_consumers(result, sig);
+ }
+
+ template<typename T>
+ inline bool has_inputs(const T &sig) const {
+ std::set<RTLIL::SigBit> result;
+ return get_inputs(result, sig);
+ }
+
+ template<typename T>
+ inline bool has_outputs(const T &sig) const {
+ std::set<RTLIL::SigBit> result;
+ return get_outputs(result, sig);
+ }
+
+ // has_* methods -- call by value
+
+ inline bool has_drivers(RTLIL::SigSpec sig) const {
+ std::set<PortBit> result;
+ return get_drivers(result, sig);
+ }
+
+ inline bool has_consumers(RTLIL::SigSpec sig) const {
+ std::set<PortBit> result;
+ return get_consumers(result, sig);
+ }
+
+ inline bool has_inputs(RTLIL::SigSpec sig) const {
+ std::set<RTLIL::SigBit> result;
+ return get_inputs(result, sig);
+ }
+
+ inline bool has_outputs(RTLIL::SigSpec sig) const {
+ std::set<RTLIL::SigBit> result;
+ return get_outputs(result, sig);
+ }
+};
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/kernel/register.cc b/kernel/register.cc
index 32570966..2f7b89ff 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -17,50 +17,46 @@
*
*/
-#include "register.h"
-#include "log.h"
-#include <assert.h>
+#include "kernel/yosys.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
+#include <errno.h>
+
+YOSYS_NAMESPACE_BEGIN
-using namespace REGISTER_INTERN;
#define MAX_REG_COUNT 1000
-namespace REGISTER_INTERN
-{
- bool echo_mode = false;
- int raw_register_count = 0;
- bool raw_register_done = false;
- Pass *raw_register_array[MAX_REG_COUNT];
-
- std::map<std::string, Frontend*> frontend_register;
- std::map<std::string, Pass*> pass_register;
- std::map<std::string, Backend*> backend_register;
-}
+bool echo_mode = false;
+Pass *first_queued_pass;
+Pass *current_pass;
+
+std::map<std::string, Frontend*> frontend_register;
+std::map<std::string, Pass*> pass_register;
+std::map<std::string, Backend*> backend_register;
std::vector<std::string> Frontend::next_args;
Pass::Pass(std::string name, std::string short_help) : pass_name(name), short_help(short_help)
{
- assert(!raw_register_done);
- assert(raw_register_count < MAX_REG_COUNT);
- raw_register_array[raw_register_count++] = this;
+ next_queued_pass = first_queued_pass;
+ first_queued_pass = this;
+ call_counter = 0;
+ runtime_ns = 0;
}
void Pass::run_register()
{
- assert(pass_register.count(pass_name) == 0);
+ log_assert(pass_register.count(pass_name) == 0);
pass_register[pass_name] = this;
}
void Pass::init_register()
{
- if (raw_register_done)
- done_register();
- while (raw_register_count > 0)
- raw_register_array[--raw_register_count]->run_register();
- raw_register_done = true;
+ while (first_queued_pass) {
+ first_queued_pass->run_register();
+ first_queued_pass = first_queued_pass->next_queued_pass;
+ }
}
void Pass::done_register()
@@ -68,13 +64,32 @@ void Pass::done_register()
frontend_register.clear();
pass_register.clear();
backend_register.clear();
- raw_register_done = false;
+ log_assert(first_queued_pass == NULL);
}
Pass::~Pass()
{
}
+Pass::pre_post_exec_state_t Pass::pre_execute()
+{
+ pre_post_exec_state_t state;
+ call_counter++;
+ state.begin_ns = PerformanceTimer::query();
+ state.parent_pass = current_pass;
+ current_pass = this;
+ return state;
+}
+
+void Pass::post_execute(Pass::pre_post_exec_state_t state)
+{
+ int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
+ runtime_ns += time_ns;
+ current_pass = state.parent_pass;
+ if (current_pass)
+ current_pass->runtime_ns -= time_ns;
+}
+
void Pass::help()
{
log("\n");
@@ -117,7 +132,7 @@ void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Desig
std::string arg = args[argidx];
if (arg.substr(0, 1) == "-")
- cmd_error(args, argidx, "Unkown option or option in arguments.");
+ cmd_error(args, argidx, "Unknown option or option in arguments.");
if (!select)
cmd_error(args, argidx, "Extra argument.");
@@ -133,8 +148,10 @@ void Pass::call(RTLIL::Design *design, std::string command)
std::vector<std::string> args;
char *s = strdup(command.c_str()), *sstart = s, *saveptr;
s += strspn(s, " \t\r\n");
- if (*s == 0 || *s == '#')
+ if (*s == 0 || *s == '#') {
+ free(sstart);
return;
+ }
if (*s == '!') {
for (s++; *s == ' ' || *s == '\t'; s++) { }
char *p = s + strlen(s) - 1;
@@ -144,6 +161,7 @@ void Pass::call(RTLIL::Design *design, std::string command)
int retCode = system(s);
if (retCode != 0)
log_cmd_error("Shell command returned error code %d.\n", retCode);
+ free(sstart);
return;
}
for (char *p = strtok_r(s, " \t\r\n", &saveptr); p; p = strtok_r(NULL, " \t\r\n", &saveptr)) {
@@ -186,18 +204,20 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args[0].c_str());
size_t orig_sel_stack_pos = design->selection_stack.size();
+ auto state = pass_register[args[0]]->pre_execute();
pass_register[args[0]]->execute(args, design);
+ pass_register[args[0]]->post_execute(state);
while (design->selection_stack.size() > orig_sel_stack_pos)
design->selection_stack.pop_back();
design->check();
}
-void Pass::call_newsel(RTLIL::Design *design, std::string command)
+void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command)
{
std::string backup_selected_active_module = design->selected_active_module;
design->selected_active_module.clear();
- design->selection_stack.push_back(RTLIL::Selection());
+ design->selection_stack.push_back(selection);
Pass::call(design, command);
@@ -205,11 +225,11 @@ void Pass::call_newsel(RTLIL::Design *design, std::string command)
design->selected_active_module = backup_selected_active_module;
}
-void Pass::call_newsel(RTLIL::Design *design, std::vector<std::string> args)
+void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::vector<std::string> args)
{
std::string backup_selected_active_module = design->selected_active_module;
design->selected_active_module.clear();
- design->selection_stack.push_back(RTLIL::Selection());
+ design->selection_stack.push_back(selection);
Pass::call(design, args);
@@ -217,16 +237,44 @@ void Pass::call_newsel(RTLIL::Design *design, std::vector<std::string> args)
design->selected_active_module = backup_selected_active_module;
}
-Frontend::Frontend(std::string name, std::string short_help) : Pass("read_"+name, short_help), frontend_name(name)
+void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::string command)
+{
+ std::string backup_selected_active_module = design->selected_active_module;
+ design->selected_active_module = module->name.str();
+ design->selection_stack.push_back(RTLIL::Selection(false));
+ design->selection_stack.back().select(module);
+
+ Pass::call(design, command);
+
+ design->selection_stack.pop_back();
+ design->selected_active_module = backup_selected_active_module;
+}
+
+void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vector<std::string> args)
+{
+ std::string backup_selected_active_module = design->selected_active_module;
+ design->selected_active_module = module->name.str();
+ design->selection_stack.push_back(RTLIL::Selection(false));
+ design->selection_stack.back().select(module);
+
+ Pass::call(design, args);
+
+ design->selection_stack.pop_back();
+ design->selected_active_module = backup_selected_active_module;
+}
+
+Frontend::Frontend(std::string name, std::string short_help) :
+ Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help),
+ frontend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name)
{
}
void Frontend::run_register()
{
- assert(pass_register.count(pass_name) == 0);
+ log_assert(pass_register.count(pass_name) == 0);
pass_register[pass_name] = this;
- assert(frontend_register.count(frontend_name) == 0);
+ log_assert(frontend_register.count(frontend_name) == 0);
frontend_register[frontend_name] = this;
}
@@ -236,17 +284,22 @@ Frontend::~Frontend()
void Frontend::execute(std::vector<std::string> args, RTLIL::Design *design)
{
- assert(next_args.empty());
+ log_assert(next_args.empty());
do {
- FILE *f = NULL;
+ std::istream *f = NULL;
next_args.clear();
+ auto state = pre_execute();
execute(f, std::string(), args, design);
+ post_execute(state);
args = next_args;
- fclose(f);
+ delete f;
} while (!args.empty());
}
-void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
+FILE *Frontend::current_script_file = NULL;
+std::string Frontend::last_here_document;
+
+void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
{
bool called_with_fp = f != NULL;
@@ -256,15 +309,53 @@ void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::stri
std::string arg = args[argidx];
if (arg.substr(0, 1) == "-")
- cmd_error(args, argidx, "Unkown option or option in arguments.");
+ cmd_error(args, argidx, "Unknown option or option in arguments.");
if (f != NULL)
cmd_error(args, argidx, "Extra filename argument in direct file mode.");
filename = arg;
- f = fopen(filename.c_str(), "r");
+ if (filename == "<<" && argidx+1 < args.size())
+ filename += args[++argidx];
+ if (filename.substr(0, 2) == "<<") {
+ if (Frontend::current_script_file == NULL)
+ log_error("Unexpected here document '%s' outside of script!\n", filename.c_str());
+ if (filename.size() <= 2)
+ log_error("Missing EOT marker in here document!\n");
+ std::string eot_marker = filename.substr(2);
+ last_here_document.clear();
+ while (1) {
+ std::string buffer;
+ char block[4096];
+ while (1) {
+ if (fgets(block, 4096, Frontend::current_script_file) == NULL)
+ log_error("Unexpected end of file in here document '%s'!\n", filename.c_str());
+ buffer += block;
+ if (buffer.size() > 0 && (buffer[buffer.size() - 1] == '\n' || buffer[buffer.size() - 1] == '\r'))
+ break;
+ }
+ int indent = buffer.find_first_not_of(" \t\r\n");
+ if (buffer.substr(indent, eot_marker.size()) == eot_marker)
+ break;
+ last_here_document += buffer;
+ }
+ f = new std::istringstream(last_here_document);
+ } else {
+ if (filename.substr(0, 2) == "+/")
+ filename = proc_share_dirname() + filename.substr(1);
+ std::ifstream *ff = new std::ifstream;
+ ff->open(filename.c_str());
+ if (ff->fail())
+ delete ff;
+ else
+ f = ff;
+ }
if (f == NULL)
log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
+ for (size_t i = argidx+1; i < args.size(); i++)
+ if (args[i].substr(0, 1) == "-")
+ cmd_error(args, i, "Found option, expected arguments.");
+
if (argidx+1 < args.size()) {
next_args.insert(next_args.begin(), args.begin(), args.begin()+argidx);
next_args.insert(next_args.begin()+argidx, args.begin()+argidx+1, args.end());
@@ -281,7 +372,7 @@ void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::stri
// cmd_log_args(args);
}
-void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command)
+void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command)
{
std::vector<std::string> args;
char *s = strdup(command.c_str());
@@ -291,7 +382,7 @@ void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filenam
frontend_call(design, f, filename, args);
}
-void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args)
+void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::vector<std::string> args)
{
if (args.size() == 0)
return;
@@ -299,9 +390,14 @@ void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filenam
log_cmd_error("No such frontend: %s\n", args[0].c_str());
if (f != NULL) {
+ auto state = frontend_register[args[0]]->pre_execute();
frontend_register[args[0]]->execute(f, filename, args, design);
+ frontend_register[args[0]]->post_execute(state);
} else if (filename == "-") {
- frontend_register[args[0]]->execute(stdin, "<stdin>", args, design);
+ std::istream *f_cin = &std::cin;
+ auto state = frontend_register[args[0]]->pre_execute();
+ frontend_register[args[0]]->execute(f_cin, "<stdin>", args, design);
+ frontend_register[args[0]]->post_execute(state);
} else {
if (!filename.empty())
args.push_back(filename);
@@ -311,16 +407,18 @@ void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filenam
design->check();
}
-Backend::Backend(std::string name, std::string short_help) : Pass("write_"+name, short_help), backend_name(name)
+Backend::Backend(std::string name, std::string short_help) :
+ Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "write_" + name, short_help),
+ backend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name)
{
}
void Backend::run_register()
{
- assert(pass_register.count(pass_name) == 0);
+ log_assert(pass_register.count(pass_name) == 0);
pass_register[pass_name] = this;
- assert(backend_register.count(backend_name) == 0);
+ log_assert(backend_register.count(backend_name) == 0);
backend_register[backend_name] = this;
}
@@ -330,13 +428,15 @@ Backend::~Backend()
void Backend::execute(std::vector<std::string> args, RTLIL::Design *design)
{
- FILE *f = NULL;
+ std::ostream *f = NULL;
+ auto state = pre_execute();
execute(f, std::string(), args, design);
- if (f != stdout)
- fclose(f);
+ post_execute(state);
+ if (f != &std::cout)
+ delete f;
}
-void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
+void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
{
bool called_with_fp = f != NULL;
@@ -345,20 +445,24 @@ void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::strin
std::string arg = args[argidx];
if (arg.substr(0, 1) == "-" && arg != "-")
- cmd_error(args, argidx, "Unkown option or option in arguments.");
+ cmd_error(args, argidx, "Unknown option or option in arguments.");
if (f != NULL)
cmd_error(args, argidx, "Extra filename argument in direct file mode.");
if (arg == "-") {
filename = "<stdout>";
- f = stdout;
+ f = &std::cout;
continue;
}
filename = arg;
- f = fopen(filename.c_str(), "w");
- if (f == NULL)
+ std::ofstream *ff = new std::ofstream;
+ ff->open(filename.c_str(), std::ofstream::trunc);
+ if (ff->fail()) {
+ delete ff;
log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+ }
+ f = ff;
}
if (called_with_fp)
@@ -368,11 +472,11 @@ void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::strin
if (f == NULL) {
filename = "<stdout>";
- f = stdout;
+ f = &std::cout;
}
}
-void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command)
+void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command)
{
std::vector<std::string> args;
char *s = strdup(command.c_str());
@@ -382,7 +486,7 @@ void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename,
backend_call(design, f, filename, args);
}
-void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args)
+void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::vector<std::string> args)
{
if (args.size() == 0)
return;
@@ -392,9 +496,14 @@ void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename,
size_t orig_sel_stack_pos = design->selection_stack.size();
if (f != NULL) {
+ auto state = backend_register[args[0]]->pre_execute();
backend_register[args[0]]->execute(f, filename, args, design);
+ backend_register[args[0]]->post_execute(state);
} else if (filename == "-") {
- backend_register[args[0]]->execute(stdout, "<stdout>", args, design);
+ std::ostream *f_cout = &std::cout;
+ auto state = backend_register[args[0]]->pre_execute();
+ backend_register[args[0]]->execute(f_cout, "<stdout>", args, design);
+ backend_register[args[0]]->post_execute(state);
} else {
if (!filename.empty())
args.push_back(filename);
@@ -479,7 +588,7 @@ struct HelpPass : public Pass {
{
if (args.size() == 1) {
log("\n");
- for (auto &it : REGISTER_INTERN::pass_register)
+ for (auto &it : pass_register)
log(" %-20s %s\n", it.first.c_str(), it.second->short_help.c_str());
log("\n");
log("Type 'help <command>' for more information on a command.\n");
@@ -489,7 +598,7 @@ struct HelpPass : public Pass {
if (args.size() == 2) {
if (args[1] == "-all") {
- for (auto &it : REGISTER_INTERN::pass_register) {
+ for (auto &it : pass_register) {
log("\n\n");
log("%s -- %s\n", it.first.c_str(), it.second->short_help.c_str());
for (size_t i = 0; i < it.first.size() + it.second->short_help.size() + 6; i++)
@@ -502,39 +611,31 @@ struct HelpPass : public Pass {
else if (args[1] == "-write-tex-command-reference-manual") {
FILE *f = fopen("command-reference-manual.tex", "wt");
fprintf(f, "%% Generated using the yosys 'help -write-tex-command-reference-manual' command.\n\n");
- for (auto &it : REGISTER_INTERN::pass_register) {
- size_t memsize;
- char *memptr;
- FILE *memf = open_memstream(&memptr, &memsize);
- log_files.push_back(memf);
+ for (auto &it : pass_register) {
+ std::ostringstream buf;
+ log_streams.push_back(&buf);
it.second->help();
- log_files.pop_back();
- fclose(memf);
- write_tex(f, it.first, it.second->short_help, memptr);
- free(memptr);
+ log_streams.pop_back();
+ write_tex(f, it.first, it.second->short_help, buf.str());
}
fclose(f);
}
// this option is undocumented as it is for internal use only
else if (args[1] == "-write-web-command-reference-manual") {
FILE *f = fopen("templates/cmd_index.in", "wt");
- for (auto &it : REGISTER_INTERN::pass_register) {
- size_t memsize;
- char *memptr;
- FILE *memf = open_memstream(&memptr, &memsize);
- log_files.push_back(memf);
+ for (auto &it : pass_register) {
+ std::ostringstream buf;
+ log_streams.push_back(&buf);
it.second->help();
- log_files.pop_back();
- fclose(memf);
- write_html(f, it.first, it.second->short_help, memptr);
- free(memptr);
+ log_streams.pop_back();
+ write_html(f, it.first, it.second->short_help, buf.str());
}
fclose(f);
}
- else if (REGISTER_INTERN::pass_register.count(args[1]) == 0)
+ else if (pass_register.count(args[1]) == 0)
log("No such command: %s\n", args[1].c_str());
else
- REGISTER_INTERN::pass_register.at(args[1])->help();
+ pass_register.at(args[1])->help();
return;
}
@@ -575,3 +676,5 @@ struct EchoPass : public Pass {
}
} EchoPass;
+YOSYS_NAMESPACE_END
+
diff --git a/kernel/register.h b/kernel/register.h
index 83e1059c..a49675ed 100644
--- a/kernel/register.h
+++ b/kernel/register.h
@@ -17,38 +17,33 @@
*
*/
+#include "kernel/yosys.h"
+
#ifndef REGISTER_H
#define REGISTER_H
-#include "kernel/rtlil.h"
-#include <stdio.h>
-#include <string>
-#include <vector>
-#include <map>
-
-#ifdef YOSYS_ENABLE_TCL
-#include <tcl.h>
-extern Tcl_Interp *yosys_get_tcl_interp();
-#endif
-
-// from kernel/version_*.o (cc source generated from Makefile)
-extern const char *yosys_version_str;
-
-// implemented in driver.cc
-extern RTLIL::Design *yosys_get_design();
-std::string rewrite_yosys_exe(std::string exe);
-std::string get_share_file_name(std::string file);
-const char *create_prompt(RTLIL::Design *design, int recursion_counter);
+YOSYS_NAMESPACE_BEGIN
struct Pass
{
std::string pass_name, short_help;
Pass(std::string name, std::string short_help = "** document me **");
- virtual void run_register();
virtual ~Pass();
+
virtual void help();
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0;
+ int call_counter;
+ int64_t runtime_ns;
+
+ struct pre_post_exec_state_t {
+ Pass *parent_pass;
+ int64_t begin_ns;
+ };
+
+ pre_post_exec_state_t pre_execute();
+ void post_execute(pre_post_exec_state_t state);
+
void cmd_log_args(const std::vector<std::string> &args);
void cmd_error(const std::vector<std::string> &args, size_t argidx, std::string msg);
void extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Design *design, bool select = true);
@@ -56,27 +51,36 @@ struct Pass
static void call(RTLIL::Design *design, std::string command);
static void call(RTLIL::Design *design, std::vector<std::string> args);
- static void call_newsel(RTLIL::Design *design, std::string command);
- static void call_newsel(RTLIL::Design *design, std::vector<std::string> args);
+ static void call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command);
+ static void call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::vector<std::string> args);
+
+ static void call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::string command);
+ static void call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vector<std::string> args);
+ Pass *next_queued_pass;
+ virtual void run_register();
static void init_register();
static void done_register();
};
struct Frontend : Pass
{
+ // for reading of here documents
+ static FILE *current_script_file;
+ static std::string last_here_document;
+
std::string frontend_name;
Frontend(std::string name, std::string short_help = "** document me **");
virtual void run_register();
virtual ~Frontend();
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design);
- virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL;
+ virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
static std::vector<std::string> next_args;
- void extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
+ void extra_args(std::istream *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
- static void frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command);
- static void frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args);
+ static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command);
+ static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::vector<std::string> args);
};
struct Backend : Pass
@@ -85,25 +89,22 @@ struct Backend : Pass
Backend(std::string name, std::string short_help = "** document me **");
virtual void run_register();
virtual ~Backend();
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design);
- virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL;
+ virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
- void extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
+ void extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
- static void backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command);
- static void backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args);
+ static void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command);
+ static void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::vector<std::string> args);
};
// implemented in passes/cmds/select.cc
extern void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t argidx, size_t args_size, RTLIL::Design *design);
-namespace REGISTER_INTERN {
- extern int raw_register_count;
- extern bool raw_register_done;
- extern Pass *raw_register_array[];
- extern std::map<std::string, Pass*> pass_register;
- extern std::map<std::string, Frontend*> frontend_register;
- extern std::map<std::string, Backend*> backend_register;
-}
+extern std::map<std::string, Pass*> pass_register;
+extern std::map<std::string, Frontend*> frontend_register;
+extern std::map<std::string, Backend*> backend_register;
+
+YOSYS_NAMESPACE_END
#endif
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 396eaf11..00be796f 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -17,16 +17,20 @@
*
*/
-#include "kernel/rtlil.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+#include "kernel/macc.h"
#include "frontends/verilog/verilog_frontend.h"
#include "backends/ilang/ilang_backend.h"
-#include <assert.h>
#include <string.h>
#include <algorithm>
-int RTLIL::autoidx = 1;
+YOSYS_NAMESPACE_BEGIN
+
+std::vector<int> RTLIL::IdString::global_refcount_storage_;
+std::vector<char*> RTLIL::IdString::global_id_storage_;
+std::map<char*, int, RTLIL::IdString::char_ptr_cmp> RTLIL::IdString::global_id_index_;
+std::vector<int> RTLIL::IdString::global_free_idx_list_;
RTLIL::Const::Const()
{
@@ -61,6 +65,13 @@ RTLIL::Const::Const(RTLIL::State bit, int width)
bits.push_back(bit);
}
+RTLIL::Const::Const(const std::vector<bool> &bits)
+{
+ flags = RTLIL::CONST_FLAG_NONE;
+ for (auto b : bits)
+ this->bits.push_back(b ? RTLIL::S1 : RTLIL::S0);
+}
+
bool RTLIL::Const::operator <(const RTLIL::Const &other) const
{
if (bits.size() != other.bits.size())
@@ -89,12 +100,15 @@ bool RTLIL::Const::as_bool() const
return false;
}
-int RTLIL::Const::as_int() const
+int RTLIL::Const::as_int(bool is_signed) const
{
- int ret = 0;
+ int32_t ret = 0;
for (size_t i = 0; i < bits.size() && i < 32; i++)
if (bits[i] == RTLIL::S1)
ret |= 1 << i;
+ if (is_signed && bits.back() == RTLIL::S1)
+ for (size_t i = bits.size(); i < 32; i++)
+ ret |= 1 << i;
return ret;
}
@@ -174,7 +188,7 @@ void RTLIL::Selection::optimize(RTLIL::Design *design)
del_list.clear();
for (auto mod_name : selected_modules) {
- if (design->modules.count(mod_name) == 0)
+ if (design->modules_.count(mod_name) == 0)
del_list.push_back(mod_name);
selected_members.erase(mod_name);
}
@@ -183,7 +197,7 @@ void RTLIL::Selection::optimize(RTLIL::Design *design)
del_list.clear();
for (auto &it : selected_members)
- if (design->modules.count(it.first) == 0)
+ if (design->modules_.count(it.first) == 0)
del_list.push_back(it.first);
for (auto mod_name : del_list)
selected_members.erase(mod_name);
@@ -191,7 +205,7 @@ void RTLIL::Selection::optimize(RTLIL::Design *design)
for (auto &it : selected_members) {
del_list.clear();
for (auto memb_name : it.second)
- if (design->modules[it.first]->count_id(memb_name) == 0)
+ if (design->modules_[it.first]->count_id(memb_name) == 0)
del_list.push_back(memb_name);
for (auto memb_name : del_list)
it.second.erase(memb_name);
@@ -202,8 +216,8 @@ void RTLIL::Selection::optimize(RTLIL::Design *design)
for (auto &it : selected_members)
if (it.second.size() == 0)
del_list.push_back(it.first);
- else if (it.second.size() == design->modules[it.first]->wires.size() + design->modules[it.first]->memories.size() +
- design->modules[it.first]->cells.size() + design->modules[it.first]->processes.size())
+ else if (it.second.size() == design->modules_[it.first]->wires_.size() + design->modules_[it.first]->memories.size() +
+ design->modules_[it.first]->cells_.size() + design->modules_[it.first]->processes.size())
add_list.push_back(it.first);
for (auto mod_name : del_list)
selected_members.erase(mod_name);
@@ -212,25 +226,140 @@ void RTLIL::Selection::optimize(RTLIL::Design *design)
selected_modules.insert(mod_name);
}
- if (selected_modules.size() == design->modules.size()) {
+ if (selected_modules.size() == design->modules_.size()) {
full_selection = true;
selected_modules.clear();
selected_members.clear();
}
}
+RTLIL::Design::Design()
+{
+ refcount_modules_ = 0;
+ selection_stack.push_back(RTLIL::Selection());
+}
+
RTLIL::Design::~Design()
{
- for (auto it = modules.begin(); it != modules.end(); it++)
+ for (auto it = modules_.begin(); it != modules_.end(); it++)
delete it->second;
}
+RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules()
+{
+ return RTLIL::ObjRange<RTLIL::Module*>(&modules_, &refcount_modules_);
+}
+
+RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name)
+{
+ return modules_.count(name) ? modules_.at(name) : NULL;
+}
+
+void RTLIL::Design::add(RTLIL::Module *module)
+{
+ log_assert(modules_.count(module->name) == 0);
+ log_assert(refcount_modules_ == 0);
+ modules_[module->name] = module;
+ module->design = this;
+
+ for (auto mon : monitors)
+ mon->notify_module_add(module);
+}
+
+RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name)
+{
+ log_assert(modules_.count(name) == 0);
+ log_assert(refcount_modules_ == 0);
+
+ RTLIL::Module *module = new RTLIL::Module;
+ modules_[name] = module;
+ module->design = this;
+ module->name = name;
+
+ for (auto mon : monitors)
+ mon->notify_module_add(module);
+
+ return module;
+}
+
+void RTLIL::Design::scratchpad_unset(std::string varname)
+{
+ scratchpad.erase(varname);
+}
+
+void RTLIL::Design::scratchpad_set_int(std::string varname, int value)
+{
+ scratchpad[varname] = stringf("%d", value);
+}
+
+void RTLIL::Design::scratchpad_set_bool(std::string varname, bool value)
+{
+ scratchpad[varname] = value ? "true" : "false";
+}
+
+void RTLIL::Design::scratchpad_set_string(std::string varname, std::string value)
+{
+ scratchpad[varname] = value;
+}
+
+int RTLIL::Design::scratchpad_get_int(std::string varname, int default_value) const
+{
+ if (scratchpad.count(varname) == 0)
+ return default_value;
+
+ std::string str = scratchpad.at(varname);
+
+ if (str == "0" || str == "false")
+ return 0;
+
+ if (str == "1" || str == "true")
+ return 1;
+
+ char *endptr = nullptr;
+ long int parsed_value = strtol(str.c_str(), &endptr, 10);
+ return *endptr ? default_value : parsed_value;
+}
+
+bool RTLIL::Design::scratchpad_get_bool(std::string varname, bool default_value) const
+{
+ if (scratchpad.count(varname) == 0)
+ return default_value;
+
+ std::string str = scratchpad.at(varname);
+
+ if (str == "0" || str == "false")
+ return false;
+
+ if (str == "1" || str == "true")
+ return true;
+
+ return default_value;
+}
+
+std::string RTLIL::Design::scratchpad_get_string(std::string varname, std::string default_value) const
+{
+ if (scratchpad.count(varname) == 0)
+ return default_value;
+ return scratchpad.at(varname);
+}
+
+void RTLIL::Design::remove(RTLIL::Module *module)
+{
+ for (auto mon : monitors)
+ mon->notify_module_del(module);
+
+ log_assert(modules_.at(module->name) == module);
+ modules_.erase(module->name);
+ delete module;
+}
+
void RTLIL::Design::check()
{
#ifndef NDEBUG
- for (auto &it : modules) {
- assert(it.first == it.second->name);
- assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
+ for (auto &it : modules_) {
+ log_assert(this == it.second->design);
+ log_assert(it.first == it.second->name);
+ log_assert(!it.first.empty());
it.second->check();
}
#endif
@@ -238,7 +367,7 @@ void RTLIL::Design::check()
void RTLIL::Design::optimize()
{
- for (auto &it : modules)
+ for (auto &it : modules_)
it.second->optimize();
for (auto &it : selection_stack)
it.optimize(this);
@@ -273,13 +402,62 @@ bool RTLIL::Design::selected_member(RTLIL::IdString mod_name, RTLIL::IdString me
return selection_stack.back().selected_member(mod_name, memb_name);
}
+bool RTLIL::Design::selected_module(RTLIL::Module *mod) const
+{
+ return selected_module(mod->name);
+}
+
+bool RTLIL::Design::selected_whole_module(RTLIL::Module *mod) const
+{
+ return selected_whole_module(mod->name);
+}
+
+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))
+ result.push_back(it.second);
+ return result;
+}
+
+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))
+ result.push_back(it.second);
+ return result;
+}
+
+std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const
+{
+ std::vector<RTLIL::Module*> result;
+ result.reserve(modules_.size());
+ for (auto &it : modules_)
+ if (selected_whole_module(it.first))
+ result.push_back(it.second);
+ else if (selected_module(it.first))
+ log("Warning: Ignoring partially selected module %s.\n", log_id(it.first));
+ return result;
+}
+
+RTLIL::Module::Module()
+{
+ design = nullptr;
+ refcount_wires_ = 0;
+ refcount_cells_ = 0;
+}
+
RTLIL::Module::~Module()
{
- for (auto it = wires.begin(); it != wires.end(); it++)
+ for (auto it = wires_.begin(); it != wires_.end(); it++)
delete it->second;
for (auto it = memories.begin(); it != memories.end(); it++)
delete it->second;
- for (auto it = cells.begin(); it != cells.end(); it++)
+ for (auto it = cells_.begin(); it != cells_.end(); it++)
delete it->second;
for (auto it = processes.begin(); it != processes.end(); it++)
delete it->second;
@@ -292,7 +470,7 @@ RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, std::map<RTLIL::IdString,
size_t RTLIL::Module::count_id(RTLIL::IdString id)
{
- return wires.count(id) + memories.count(id) + cells.count(id) + processes.count(id);
+ return wires_.count(id) + memories.count(id) + cells_.count(id) + processes.count(id);
}
#ifndef NDEBUG
@@ -307,17 +485,12 @@ namespace {
void error(int linenr)
{
- char *ptr;
- size_t size;
-
- FILE *f = open_memstream(&ptr, &size);
- ILANG_BACKEND::dump_cell(f, " ", cell);
- fputc(0, f);
- fclose(f);
+ std::stringstream buf;
+ ILANG_BACKEND::dump_cell(buf, " ", cell);
- log_error("Found error in internal cell %s.%s (%s) at %s:%d:\n%s",
- module->name.c_str(), cell->name.c_str(), cell->type.c_str(),
- __FILE__, linenr, ptr);
+ log_error("Found error in internal cell %s%s%s (%s) at %s:%d:\n%s",
+ module ? module->name.c_str() : "", module ? "." : "",
+ cell->name.c_str(), cell->type.c_str(), __FILE__, linenr, buf.str().c_str());
}
int param(const char *name)
@@ -347,9 +520,9 @@ namespace {
void port(const char *name, int width)
{
- if (cell->connections.count(name) == 0)
+ if (!cell->hasPort(name))
error(__LINE__);
- if (cell->connections.at(name).width != width)
+ if (cell->getPort(name).size() != width)
error(__LINE__);
expected_ports.insert(name);
}
@@ -359,7 +532,7 @@ namespace {
for (auto &para : cell->parameters)
if (expected_params.count(para.first) == 0)
error(__LINE__);
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
if (expected_ports.count(conn.first) == 0)
error(__LINE__);
@@ -378,23 +551,27 @@ namespace {
for (const char *p = ports; *p; p++) {
char portname[3] = { '\\', *p, 0 };
- if (cell->connections.count(portname) == 0)
+ if (!cell->hasPort(portname))
error(__LINE__);
- if (cell->connections.at(portname).width != 1)
+ if (cell->getPort(portname).size() != 1)
error(__LINE__);
}
- for (auto &conn : cell->connections) {
- if (conn.first.size() != 2 || conn.first.at(0) != '\\')
+ for (auto &conn : cell->connections()) {
+ if (conn.first.size() != 2 || conn.first[0] != '\\')
error(__LINE__);
- if (strchr(ports, conn.first.at(1)) == NULL)
+ if (strchr(ports, conn.first[1]) == NULL)
error(__LINE__);
}
}
void check()
{
- if (cell->type == "$not" || cell->type == "$pos" || cell->type == "$bu0" || cell->type == "$neg") {
+ if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" ||
+ cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:")
+ return;
+
+ if (cell->type.in("$not", "$pos", "$neg")) {
param_bool("\\A_SIGNED");
port("\\A", param("\\A_WIDTH"));
port("\\Y", param("\\Y_WIDTH"));
@@ -402,7 +579,7 @@ namespace {
return;
}
- if (cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor") {
+ if (cell->type.in("$and", "$or", "$xor", "$xnor")) {
param_bool("\\A_SIGNED");
param_bool("\\B_SIGNED");
port("\\A", param("\\A_WIDTH"));
@@ -412,8 +589,7 @@ namespace {
return;
}
- if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_xor" ||
- cell->type == "$reduce_xnor" || cell->type == "$reduce_bool") {
+ if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool")) {
param_bool("\\A_SIGNED");
port("\\A", param("\\A_WIDTH"));
port("\\Y", param("\\Y_WIDTH"));
@@ -421,7 +597,7 @@ namespace {
return;
}
- if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr") {
+ if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx")) {
param_bool("\\A_SIGNED");
param_bool("\\B_SIGNED");
port("\\A", param("\\A_WIDTH"));
@@ -431,8 +607,7 @@ namespace {
return;
}
- if (cell->type == "$lt" || cell->type == "$le" || cell->type == "$eq" || cell->type == "$ne" ||
- cell->type == "$eqx" || cell->type == "$nex" || cell->type == "$ge" || cell->type == "$gt") {
+ if (cell->type.in("$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt")) {
param_bool("\\A_SIGNED");
param_bool("\\B_SIGNED");
port("\\A", param("\\A_WIDTH"));
@@ -442,8 +617,7 @@ namespace {
return;
}
- if (cell->type == "$add" || cell->type == "$sub" || cell->type == "$mul" || cell->type == "$div" ||
- cell->type == "$mod" || cell->type == "$pow") {
+ if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$pow")) {
param_bool("\\A_SIGNED");
param_bool("\\B_SIGNED");
port("\\A", param("\\A_WIDTH"));
@@ -453,6 +627,50 @@ namespace {
return;
}
+ if (cell->type == "$fa") {
+ port("\\A", param("\\WIDTH"));
+ port("\\B", param("\\WIDTH"));
+ port("\\C", param("\\WIDTH"));
+ port("\\X", param("\\WIDTH"));
+ port("\\Y", param("\\WIDTH"));
+ check_expected();
+ return;
+ }
+
+ if (cell->type == "$lcu") {
+ port("\\P", param("\\WIDTH"));
+ port("\\G", param("\\WIDTH"));
+ port("\\CI", 1);
+ port("\\CO", param("\\WIDTH"));
+ check_expected();
+ return;
+ }
+
+ if (cell->type == "$alu") {
+ param_bool("\\A_SIGNED");
+ param_bool("\\B_SIGNED");
+ port("\\A", param("\\A_WIDTH"));
+ port("\\B", param("\\B_WIDTH"));
+ port("\\CI", 1);
+ port("\\BI", 1);
+ port("\\X", param("\\Y_WIDTH"));
+ port("\\Y", param("\\Y_WIDTH"));
+ port("\\CO", param("\\Y_WIDTH"));
+ check_expected();
+ return;
+ }
+
+ if (cell->type == "$macc") {
+ param("\\CONFIG");
+ param("\\CONFIG_WIDTH");
+ port("\\A", param("\\A_WIDTH"));
+ port("\\B", param("\\B_WIDTH"));
+ port("\\Y", param("\\Y_WIDTH"));
+ check_expected();
+ Macc().from_cell(cell);
+ return;
+ }
+
if (cell->type == "$logic_not") {
param_bool("\\A_SIGNED");
port("\\A", param("\\A_WIDTH"));
@@ -498,7 +716,7 @@ namespace {
return;
}
- if (cell->type == "$pmux" || cell->type == "$safe_pmux") {
+ if (cell->type == "$pmux") {
port("\\A", param("\\WIDTH"));
port("\\B", param("\\WIDTH") * param("\\S_WIDTH"));
port("\\S", param("\\S_WIDTH"));
@@ -509,8 +727,8 @@ namespace {
if (cell->type == "$lut") {
param("\\LUT");
- port("\\I", param("\\WIDTH"));
- port("\\O", 1);
+ port("\\A", param("\\WIDTH"));
+ port("\\Y", 1);
check_expected();
return;
}
@@ -568,6 +786,19 @@ namespace {
return;
}
+ if (cell->type == "$dlatchsr") {
+ param_bool("\\EN_POLARITY");
+ param_bool("\\SET_POLARITY");
+ param_bool("\\CLR_POLARITY");
+ port("\\EN", 1);
+ port("\\SET", param("\\WIDTH"));
+ port("\\CLR", param("\\WIDTH"));
+ port("\\D", param("\\WIDTH"));
+ port("\\Q", param("\\WIDTH"));
+ check_expected();
+ return;
+ }
+
if (cell->type == "$fsm") {
param("\\NAME");
param_bool("\\CLK_POLARITY");
@@ -605,7 +836,7 @@ namespace {
param_bool("\\CLK_POLARITY");
param("\\PRIORITY");
port("\\CLK", 1);
- port("\\EN", 1);
+ port("\\EN", param("\\WIDTH"));
port("\\ADDR", param("\\ABITS"));
port("\\DATA", param("\\WIDTH"));
check_expected();
@@ -625,7 +856,7 @@ namespace {
port("\\RD_ADDR", param("\\RD_PORTS") * param("\\ABITS"));
port("\\RD_DATA", param("\\RD_PORTS") * param("\\WIDTH"));
port("\\WR_CLK", param("\\WR_PORTS"));
- port("\\WR_EN", param("\\WR_PORTS"));
+ port("\\WR_EN", param("\\WR_PORTS") * param("\\WIDTH"));
port("\\WR_ADDR", param("\\WR_PORTS") * param("\\ABITS"));
port("\\WR_DATA", param("\\WR_PORTS") * param("\\WIDTH"));
check_expected();
@@ -639,11 +870,18 @@ namespace {
return;
}
- if (cell->type == "$_INV_") { check_gate("AY"); return; }
- if (cell->type == "$_AND_") { check_gate("ABY"); return; }
- if (cell->type == "$_OR_") { check_gate("ABY"); return; }
- if (cell->type == "$_XOR_") { check_gate("ABY"); return; }
- if (cell->type == "$_MUX_") { check_gate("ABSY"); return; }
+ if (cell->type == "$_NOT_") { check_gate("AY"); return; }
+ if (cell->type == "$_AND_") { check_gate("ABY"); return; }
+ if (cell->type == "$_NAND_") { check_gate("ABY"); return; }
+ if (cell->type == "$_OR_") { check_gate("ABY"); return; }
+ if (cell->type == "$_NOR_") { check_gate("ABY"); return; }
+ if (cell->type == "$_XOR_") { check_gate("ABY"); return; }
+ if (cell->type == "$_XNOR_") { check_gate("ABY"); return; }
+ if (cell->type == "$_MUX_") { check_gate("ABSY"); return; }
+ if (cell->type == "$_AOI3_") { check_gate("ABCY"); return; }
+ if (cell->type == "$_OAI3_") { check_gate("ABCY"); return; }
+ if (cell->type == "$_AOI4_") { check_gate("ABCDY"); return; }
+ if (cell->type == "$_OAI4_") { check_gate("ABCDY"); return; }
if (cell->type == "$_SR_NN_") { check_gate("SRQ"); return; }
if (cell->type == "$_SR_NP_") { check_gate("SRQ"); return; }
@@ -674,6 +912,15 @@ namespace {
if (cell->type == "$_DLATCH_N_") { check_gate("EDQ"); return; }
if (cell->type == "$_DLATCH_P_") { check_gate("EDQ"); return; }
+ if (cell->type == "$_DLATCHSR_NNN_") { check_gate("ESRDQ"); return; }
+ if (cell->type == "$_DLATCHSR_NNP_") { check_gate("ESRDQ"); return; }
+ if (cell->type == "$_DLATCHSR_NPN_") { check_gate("ESRDQ"); return; }
+ if (cell->type == "$_DLATCHSR_NPP_") { check_gate("ESRDQ"); return; }
+ if (cell->type == "$_DLATCHSR_PNN_") { check_gate("ESRDQ"); return; }
+ if (cell->type == "$_DLATCHSR_PNP_") { check_gate("ESRDQ"); return; }
+ if (cell->type == "$_DLATCHSR_PPN_") { check_gate("ESRDQ"); return; }
+ if (cell->type == "$_DLATCHSR_PPP_") { check_gate("ESRDQ"); return; }
+
error(__LINE__);
}
};
@@ -683,90 +930,93 @@ namespace {
void RTLIL::Module::check()
{
#ifndef NDEBUG
- for (auto &it : wires) {
- assert(it.first == it.second->name);
- assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
- assert(it.second->width >= 0);
- assert(it.second->port_id >= 0);
- for (auto &it2 : it.second->attributes) {
- assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$'));
- }
+ std::vector<bool> ports_declared;
+ for (auto &it : wires_) {
+ log_assert(this == it.second->module);
+ log_assert(it.first == it.second->name);
+ log_assert(!it.first.empty());
+ log_assert(it.second->width >= 0);
+ log_assert(it.second->port_id >= 0);
+ for (auto &it2 : it.second->attributes)
+ log_assert(!it2.first.empty());
+ if (it.second->port_id) {
+ log_assert(SIZE(ports) >= it.second->port_id);
+ log_assert(ports.at(it.second->port_id-1) == it.first);
+ log_assert(it.second->port_input || it.second->port_output);
+ if (SIZE(ports_declared) < it.second->port_id)
+ ports_declared.resize(it.second->port_id);
+ log_assert(ports_declared[it.second->port_id-1] == false);
+ ports_declared[it.second->port_id-1] = true;
+ } else
+ log_assert(!it.second->port_input && !it.second->port_output);
}
+ for (auto port_declared : ports_declared)
+ log_assert(port_declared == true);
+ log_assert(SIZE(ports) == SIZE(ports_declared));
for (auto &it : memories) {
- assert(it.first == it.second->name);
- assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
- assert(it.second->width >= 0);
- assert(it.second->size >= 0);
- for (auto &it2 : it.second->attributes) {
- assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$'));
- }
+ log_assert(it.first == it.second->name);
+ log_assert(!it.first.empty());
+ log_assert(it.second->width >= 0);
+ log_assert(it.second->size >= 0);
+ for (auto &it2 : it.second->attributes)
+ log_assert(!it2.first.empty());
}
- for (auto &it : cells) {
- assert(it.first == it.second->name);
- assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
- assert(it.second->type.size() > 0 && (it.second->type[0] == '\\' || it.second->type[0] == '$'));
- for (auto &it2 : it.second->connections) {
- assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$'));
+ for (auto &it : cells_) {
+ log_assert(this == it.second->module);
+ log_assert(it.first == it.second->name);
+ log_assert(!it.first.empty());
+ log_assert(!it.second->type.empty());
+ for (auto &it2 : it.second->connections()) {
+ log_assert(!it2.first.empty());
it2.second.check();
}
- for (auto &it2 : it.second->attributes) {
- assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$'));
- }
- for (auto &it2 : it.second->parameters) {
- assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$'));
- }
- if (it.second->type[0] == '$' && it.second->type.substr(0, 3) != "$__" && it.second->type.substr(0, 8) != "$paramod") {
- InternalCellChecker checker(this, it.second);
- checker.check();
- }
+ for (auto &it2 : it.second->attributes)
+ log_assert(!it2.first.empty());
+ for (auto &it2 : it.second->parameters)
+ log_assert(!it2.first.empty());
+ InternalCellChecker checker(this, it.second);
+ checker.check();
}
for (auto &it : processes) {
- assert(it.first == it.second->name);
- assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
+ log_assert(it.first == it.second->name);
+ log_assert(!it.first.empty());
// FIXME: More checks here..
}
- for (auto &it : connections) {
- assert(it.first.width == it.second.width);
+ for (auto &it : connections_) {
+ log_assert(it.first.size() == it.second.size());
it.first.check();
it.second.check();
}
- for (auto &it : attributes) {
- assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
- }
+ for (auto &it : attributes)
+ log_assert(!it.first.empty());
#endif
}
void RTLIL::Module::optimize()
{
- for (auto &it : cells)
- it.second->optimize();
- for (auto &it : processes)
- it.second->optimize();
- for (auto &it : connections) {
- it.first.optimize();
- it.second.optimize();
- }
}
void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const
{
- new_mod->name = name;
- new_mod->connections = connections;
+ log_assert(new_mod->refcount_wires_ == 0);
+ log_assert(new_mod->refcount_cells_ == 0);
+
+ new_mod->connections_ = connections_;
new_mod->attributes = attributes;
- for (auto &it : wires)
- new_mod->wires[it.first] = new RTLIL::Wire(*it.second);
+ for (auto &it : wires_)
+ new_mod->addWire(it.first, it.second);
for (auto &it : memories)
new_mod->memories[it.first] = new RTLIL::Memory(*it.second);
- for (auto &it : cells)
- new_mod->cells[it.first] = new RTLIL::Cell(*it.second);
+ for (auto &it : cells_)
+ new_mod->addCell(it.first, it.second);
for (auto &it : processes)
new_mod->processes[it.first] = it.second->clone();
@@ -776,45 +1026,223 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const
RTLIL::Module *mod;
void operator()(RTLIL::SigSpec &sig)
{
- for (auto &c : sig.chunks)
+ std::vector<RTLIL::SigChunk> chunks = sig.chunks();
+ for (auto &c : chunks)
if (c.wire != NULL)
- c.wire = mod->wires.at(c.wire->name);
+ c.wire = mod->wires_.at(c.wire->name);
+ sig = chunks;
}
};
RewriteSigSpecWorker rewriteSigSpecWorker;
rewriteSigSpecWorker.mod = new_mod;
new_mod->rewrite_sigspecs(rewriteSigSpecWorker);
+ new_mod->fixup_ports();
}
RTLIL::Module *RTLIL::Module::clone() const
{
RTLIL::Module *new_mod = new RTLIL::Module;
+ new_mod->name = name;
cloneInto(new_mod);
return new_mod;
}
-RTLIL::Wire *RTLIL::Module::new_wire(int width, RTLIL::IdString name)
+bool RTLIL::Module::has_memories() const
{
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->width = width;
- wire->name = name;
- add(wire);
- return wire;
+ return !memories.empty();
+}
+
+bool RTLIL::Module::has_processes() const
+{
+ return !processes.empty();
+}
+
+bool RTLIL::Module::has_memories_warn() const
+{
+ if (!memories.empty())
+ log("Warning: Ignoring module %s because it contains memories (run 'memory' command first).\n", log_id(this));
+ return !memories.empty();
+}
+
+bool RTLIL::Module::has_processes_warn() const
+{
+ if (!processes.empty())
+ log("Warning: Ignoring module %s because it contains processes (run 'proc' command first).\n", log_id(this));
+ return !processes.empty();
+}
+
+std::vector<RTLIL::Wire*> RTLIL::Module::selected_wires() const
+{
+ std::vector<RTLIL::Wire*> result;
+ result.reserve(wires_.size());
+ for (auto &it : wires_)
+ if (design->selected(this, it.second))
+ result.push_back(it.second);
+ return result;
+}
+
+std::vector<RTLIL::Cell*> RTLIL::Module::selected_cells() const
+{
+ std::vector<RTLIL::Cell*> result;
+ result.reserve(wires_.size());
+ for (auto &it : cells_)
+ if (design->selected(this, it.second))
+ result.push_back(it.second);
+ return result;
}
void RTLIL::Module::add(RTLIL::Wire *wire)
{
- assert(!wire->name.empty());
- assert(count_id(wire->name) == 0);
- wires[wire->name] = wire;
+ log_assert(!wire->name.empty());
+ log_assert(count_id(wire->name) == 0);
+ log_assert(refcount_wires_ == 0);
+ wires_[wire->name] = wire;
+ wire->module = this;
}
void RTLIL::Module::add(RTLIL::Cell *cell)
{
- assert(!cell->name.empty());
- assert(count_id(cell->name) == 0);
- cells[cell->name] = cell;
+ log_assert(!cell->name.empty());
+ log_assert(count_id(cell->name) == 0);
+ log_assert(refcount_cells_ == 0);
+ cells_[cell->name] = cell;
+ cell->module = this;
+}
+
+namespace {
+ struct DeleteWireWorker
+ {
+ RTLIL::Module *module;
+ const std::set<RTLIL::Wire*> *wires_p;
+
+ void operator()(RTLIL::SigSpec &sig) {
+ std::vector<RTLIL::SigChunk> chunks = sig;
+ for (auto &c : chunks)
+ if (c.wire != NULL && wires_p->count(c.wire)) {
+ c.wire = module->addWire(NEW_ID, c.width);
+ c.offset = 0;
+ }
+ sig = chunks;
+ }
+ };
+}
+
+#if 0
+void RTLIL::Module::remove(RTLIL::Wire *wire)
+{
+ std::setPort<RTLIL::Wire*> wires_;
+ wires_.insert(wire);
+ remove(wires_);
+}
+#endif
+
+void RTLIL::Module::remove(const std::set<RTLIL::Wire*> &wires)
+{
+ log_assert(refcount_wires_ == 0);
+
+ DeleteWireWorker delete_wire_worker;
+ delete_wire_worker.module = this;
+ delete_wire_worker.wires_p = &wires;
+ rewrite_sigspecs(delete_wire_worker);
+
+ for (auto &it : wires) {
+ log_assert(wires_.count(it->name) != 0);
+ wires_.erase(it->name);
+ delete it;
+ }
+}
+
+void RTLIL::Module::remove(RTLIL::Cell *cell)
+{
+ while (!cell->connections_.empty())
+ cell->unsetPort(cell->connections_.begin()->first);
+
+ log_assert(cells_.count(cell->name) != 0);
+ log_assert(refcount_cells_ == 0);
+ cells_.erase(cell->name);
+ delete cell;
+}
+
+void RTLIL::Module::rename(RTLIL::Wire *wire, RTLIL::IdString new_name)
+{
+ log_assert(wires_[wire->name] == wire);
+ log_assert(refcount_wires_ == 0);
+ wires_.erase(wire->name);
+ wire->name = new_name;
+ add(wire);
+}
+
+void RTLIL::Module::rename(RTLIL::Cell *cell, RTLIL::IdString new_name)
+{
+ log_assert(cells_[cell->name] == cell);
+ log_assert(refcount_wires_ == 0);
+ cells_.erase(cell->name);
+ cell->name = new_name;
+ add(cell);
+}
+
+void RTLIL::Module::rename(RTLIL::IdString old_name, RTLIL::IdString new_name)
+{
+ log_assert(count_id(old_name) != 0);
+ if (wires_.count(old_name))
+ rename(wires_.at(old_name), new_name);
+ else if (cells_.count(old_name))
+ rename(cells_.at(old_name), new_name);
+ else
+ log_abort();
+}
+
+void RTLIL::Module::swap_names(RTLIL::Wire *w1, RTLIL::Wire *w2)
+{
+ log_assert(wires_[w1->name] == w1);
+ log_assert(wires_[w2->name] == w2);
+ log_assert(refcount_wires_ == 0);
+
+ wires_.erase(w1->name);
+ wires_.erase(w2->name);
+
+ std::swap(w1->name, w2->name);
+
+ wires_[w1->name] = w1;
+ wires_[w2->name] = w2;
+}
+
+void RTLIL::Module::swap_names(RTLIL::Cell *c1, RTLIL::Cell *c2)
+{
+ log_assert(cells_[c1->name] == c1);
+ log_assert(cells_[c2->name] == c2);
+ log_assert(refcount_cells_ == 0);
+
+ cells_.erase(c1->name);
+ cells_.erase(c2->name);
+
+ std::swap(c1->name, c2->name);
+
+ cells_[c1->name] = c1;
+ cells_[c2->name] = c2;
+}
+
+RTLIL::IdString RTLIL::Module::uniquify(RTLIL::IdString name)
+{
+ int index = 0;
+ return uniquify(name, index);
+}
+
+RTLIL::IdString RTLIL::Module::uniquify(RTLIL::IdString name, int &index)
+{
+ if (index == 0) {
+ if (count_id(name) == 0)
+ return name;
+ index++;
+ }
+
+ while (1) {
+ RTLIL::IdString new_name = stringf("%s_%d", name.c_str(), index);
+ if (count_id(new_name) == 0)
+ return new_name;
+ index++;
+ }
}
static bool fixup_ports_compare(const RTLIL::Wire *a, const RTLIL::Wire *b)
@@ -829,28 +1257,459 @@ static bool fixup_ports_compare(const RTLIL::Wire *a, const RTLIL::Wire *b)
return a->port_id < b->port_id;
}
+void RTLIL::Module::connect(const RTLIL::SigSig &conn)
+{
+ for (auto mon : monitors)
+ mon->notify_connect(this, conn);
+
+ if (design)
+ for (auto mon : design->monitors)
+ mon->notify_connect(this, conn);
+
+ connections_.push_back(conn);
+}
+
+void RTLIL::Module::connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs)
+{
+ connect(RTLIL::SigSig(lhs, rhs));
+}
+
+void RTLIL::Module::new_connections(const std::vector<RTLIL::SigSig> &new_conn)
+{
+ for (auto mon : monitors)
+ mon->notify_connect(this, new_conn);
+
+ if (design)
+ for (auto mon : design->monitors)
+ mon->notify_connect(this, new_conn);
+
+ connections_ = new_conn;
+}
+
+const std::vector<RTLIL::SigSig> &RTLIL::Module::connections() const
+{
+ return connections_;
+}
+
void RTLIL::Module::fixup_ports()
{
std::vector<RTLIL::Wire*> all_ports;
- for (auto &w : wires)
+ for (auto &w : wires_)
if (w.second->port_input || w.second->port_output)
all_ports.push_back(w.second);
else
w.second->port_id = 0;
std::sort(all_ports.begin(), all_ports.end(), fixup_ports_compare);
- for (size_t i = 0; i < all_ports.size(); i++)
+
+ ports.clear();
+ for (size_t i = 0; i < all_ports.size(); i++) {
+ ports.push_back(all_ports[i]->name);
all_ports[i]->port_id = i+1;
+ }
+}
+
+RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, int width)
+{
+ RTLIL::Wire *wire = new RTLIL::Wire;
+ wire->name = name;
+ wire->width = width;
+ add(wire);
+ return wire;
}
+RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, const RTLIL::Wire *other)
+{
+ RTLIL::Wire *wire = addWire(name);
+ wire->width = other->width;
+ wire->start_offset = other->start_offset;
+ wire->port_id = other->port_id;
+ wire->port_input = other->port_input;
+ wire->port_output = other->port_output;
+ wire->upto = other->upto;
+ wire->attributes = other->attributes;
+ return wire;
+}
+
+RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, RTLIL::IdString type)
+{
+ RTLIL::Cell *cell = new RTLIL::Cell;
+ cell->name = name;
+ cell->type = type;
+ add(cell);
+ return cell;
+}
+
+RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *other)
+{
+ RTLIL::Cell *cell = addCell(name, other->type);
+ cell->connections_ = other->connections_;
+ cell->parameters = other->parameters;
+ cell->attributes = other->attributes;
+ return cell;
+}
+
+#define DEF_METHOD(_func, _y_size, _type) \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed) { \
+ RTLIL::Cell *cell = addCell(name, _type); \
+ cell->parameters["\\A_SIGNED"] = is_signed; \
+ cell->parameters["\\A_WIDTH"] = sig_a.size(); \
+ cell->parameters["\\Y_WIDTH"] = sig_y.size(); \
+ cell->setPort("\\A", sig_a); \
+ cell->setPort("\\Y", sig_y); \
+ return cell; \
+ } \
+ RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed) { \
+ RTLIL::SigSpec sig_y = addWire(NEW_ID, _y_size); \
+ add ## _func(name, sig_a, sig_y, is_signed); \
+ return sig_y; \
+ }
+DEF_METHOD(Not, sig_a.size(), "$not")
+DEF_METHOD(Pos, sig_a.size(), "$pos")
+DEF_METHOD(Neg, sig_a.size(), "$neg")
+DEF_METHOD(ReduceAnd, 1, "$reduce_and")
+DEF_METHOD(ReduceOr, 1, "$reduce_or")
+DEF_METHOD(ReduceXor, 1, "$reduce_xor")
+DEF_METHOD(ReduceXnor, 1, "$reduce_xnor")
+DEF_METHOD(ReduceBool, 1, "$reduce_bool")
+DEF_METHOD(LogicNot, 1, "$logic_not")
+#undef DEF_METHOD
+
+#define DEF_METHOD(_func, _y_size, _type) \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed) { \
+ RTLIL::Cell *cell = addCell(name, _type); \
+ cell->parameters["\\A_SIGNED"] = is_signed; \
+ cell->parameters["\\B_SIGNED"] = is_signed; \
+ cell->parameters["\\A_WIDTH"] = sig_a.size(); \
+ cell->parameters["\\B_WIDTH"] = sig_b.size(); \
+ cell->parameters["\\Y_WIDTH"] = sig_y.size(); \
+ cell->setPort("\\A", sig_a); \
+ cell->setPort("\\B", sig_b); \
+ cell->setPort("\\Y", sig_y); \
+ return cell; \
+ } \
+ RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed) { \
+ RTLIL::SigSpec sig_y = addWire(NEW_ID, _y_size); \
+ add ## _func(name, sig_a, sig_b, sig_y, is_signed); \
+ return sig_y; \
+ }
+DEF_METHOD(And, std::max(sig_a.size(), sig_b.size()), "$and")
+DEF_METHOD(Or, std::max(sig_a.size(), sig_b.size()), "$or")
+DEF_METHOD(Xor, std::max(sig_a.size(), sig_b.size()), "$xor")
+DEF_METHOD(Xnor, std::max(sig_a.size(), sig_b.size()), "$xnor")
+DEF_METHOD(Shl, sig_a.size(), "$shl")
+DEF_METHOD(Shr, sig_a.size(), "$shr")
+DEF_METHOD(Sshl, sig_a.size(), "$sshl")
+DEF_METHOD(Sshr, sig_a.size(), "$sshr")
+DEF_METHOD(Shift, sig_a.size(), "$shift")
+DEF_METHOD(Shiftx, sig_a.size(), "$shiftx")
+DEF_METHOD(Lt, 1, "$lt")
+DEF_METHOD(Le, 1, "$le")
+DEF_METHOD(Eq, 1, "$eq")
+DEF_METHOD(Ne, 1, "$ne")
+DEF_METHOD(Eqx, 1, "$eqx")
+DEF_METHOD(Nex, 1, "$nex")
+DEF_METHOD(Ge, 1, "$ge")
+DEF_METHOD(Gt, 1, "$gt")
+DEF_METHOD(Add, std::max(sig_a.size(), sig_b.size()), "$add")
+DEF_METHOD(Sub, std::max(sig_a.size(), sig_b.size()), "$sub")
+DEF_METHOD(Mul, std::max(sig_a.size(), sig_b.size()), "$mul")
+DEF_METHOD(Div, std::max(sig_a.size(), sig_b.size()), "$div")
+DEF_METHOD(Mod, std::max(sig_a.size(), sig_b.size()), "$mod")
+DEF_METHOD(LogicAnd, 1, "$logic_and")
+DEF_METHOD(LogicOr, 1, "$logic_or")
+#undef DEF_METHOD
+
+#define DEF_METHOD(_func, _type, _pmux) \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y) { \
+ RTLIL::Cell *cell = addCell(name, _type); \
+ cell->parameters["\\WIDTH"] = sig_a.size(); \
+ if (_pmux) cell->parameters["\\S_WIDTH"] = sig_s.size(); \
+ cell->setPort("\\A", sig_a); \
+ cell->setPort("\\B", sig_b); \
+ cell->setPort("\\S", sig_s); \
+ cell->setPort("\\Y", sig_y); \
+ return cell; \
+ } \
+ RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s) { \
+ RTLIL::SigSpec sig_y = addWire(NEW_ID, sig_a.size()); \
+ add ## _func(name, sig_a, sig_b, sig_s, sig_y); \
+ return sig_y; \
+ }
+DEF_METHOD(Mux, "$mux", 0)
+DEF_METHOD(Pmux, "$pmux", 1)
+#undef DEF_METHOD
+
+#define DEF_METHOD_2(_func, _type, _P1, _P2) \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2) { \
+ RTLIL::Cell *cell = addCell(name, _type); \
+ cell->setPort("\\" #_P1, sig1); \
+ cell->setPort("\\" #_P2, sig2); \
+ return cell; \
+ } \
+ RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1) { \
+ RTLIL::SigBit sig2 = addWire(NEW_ID); \
+ add ## _func(name, sig1, sig2); \
+ return sig2; \
+ }
+#define DEF_METHOD_3(_func, _type, _P1, _P2, _P3) \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3) { \
+ RTLIL::Cell *cell = addCell(name, _type); \
+ cell->setPort("\\" #_P1, sig1); \
+ cell->setPort("\\" #_P2, sig2); \
+ cell->setPort("\\" #_P3, sig3); \
+ return cell; \
+ } \
+ RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2) { \
+ RTLIL::SigBit sig3 = addWire(NEW_ID); \
+ add ## _func(name, sig1, sig2, sig3); \
+ return sig3; \
+ }
+#define DEF_METHOD_4(_func, _type, _P1, _P2, _P3, _P4) \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4) { \
+ RTLIL::Cell *cell = addCell(name, _type); \
+ cell->setPort("\\" #_P1, sig1); \
+ cell->setPort("\\" #_P2, sig2); \
+ cell->setPort("\\" #_P3, sig3); \
+ cell->setPort("\\" #_P4, sig4); \
+ return cell; \
+ } \
+ RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3) { \
+ RTLIL::SigBit sig4 = addWire(NEW_ID); \
+ add ## _func(name, sig1, sig2, sig3, sig4); \
+ return sig4; \
+ }
+#define DEF_METHOD_5(_func, _type, _P1, _P2, _P3, _P4, _P5) \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4, RTLIL::SigBit sig5) { \
+ RTLIL::Cell *cell = addCell(name, _type); \
+ cell->setPort("\\" #_P1, sig1); \
+ cell->setPort("\\" #_P2, sig2); \
+ cell->setPort("\\" #_P3, sig3); \
+ cell->setPort("\\" #_P4, sig4); \
+ cell->setPort("\\" #_P5, sig5); \
+ return cell; \
+ } \
+ RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4) { \
+ RTLIL::SigBit sig5 = addWire(NEW_ID); \
+ add ## _func(name, sig1, sig2, sig3, sig4, sig5); \
+ return sig5; \
+ }
+DEF_METHOD_2(NotGate, "$_NOT_", A, Y)
+DEF_METHOD_3(AndGate, "$_AND_", A, B, Y)
+DEF_METHOD_3(NandGate, "$_NAND_", A, B, Y)
+DEF_METHOD_3(OrGate, "$_OR_", A, B, Y)
+DEF_METHOD_3(NorGate, "$_NOR_", A, B, Y)
+DEF_METHOD_3(XorGate, "$_XOR_", A, B, Y)
+DEF_METHOD_3(XnorGate, "$_XNOR_", A, B, Y)
+DEF_METHOD_4(MuxGate, "$_MUX_", A, B, S, Y)
+DEF_METHOD_4(Aoi3Gate, "$_AOI3_", A, B, C, Y)
+DEF_METHOD_4(Oai3Gate, "$_OAI3_", A, B, C, Y)
+DEF_METHOD_5(Aoi4Gate, "$_AOI4_", A, B, C, D, Y)
+DEF_METHOD_5(Oai4Gate, "$_OAI4_", A, B, C, D, Y)
+#undef DEF_METHOD_2
+#undef DEF_METHOD_3
+#undef DEF_METHOD_4
+#undef DEF_METHOD_5
+
+RTLIL::Cell* RTLIL::Module::addPow(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool a_signed, bool b_signed)
+{
+ RTLIL::Cell *cell = addCell(name, "$pow");
+ cell->parameters["\\A_SIGNED"] = a_signed;
+ cell->parameters["\\B_SIGNED"] = b_signed;
+ cell->parameters["\\A_WIDTH"] = sig_a.size();
+ cell->parameters["\\B_WIDTH"] = sig_b.size();
+ cell->parameters["\\Y_WIDTH"] = sig_y.size();
+ cell->setPort("\\A", sig_a);
+ cell->setPort("\\B", sig_b);
+ cell->setPort("\\Y", sig_y);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const offset)
+{
+ RTLIL::Cell *cell = addCell(name, "$slice");
+ cell->parameters["\\A_WIDTH"] = sig_a.size();
+ cell->parameters["\\Y_WIDTH"] = sig_y.size();
+ cell->parameters["\\OFFSET"] = offset;
+ cell->setPort("\\A", sig_a);
+ cell->setPort("\\Y", sig_y);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addConcat(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y)
+{
+ RTLIL::Cell *cell = addCell(name, "$concat");
+ cell->parameters["\\A_WIDTH"] = sig_a.size();
+ cell->parameters["\\B_WIDTH"] = sig_b.size();
+ cell->setPort("\\A", sig_a);
+ cell->setPort("\\B", sig_b);
+ cell->setPort("\\Y", sig_y);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addLut(RTLIL::IdString name, RTLIL::SigSpec sig_i, RTLIL::SigSpec sig_o, RTLIL::Const lut)
+{
+ RTLIL::Cell *cell = addCell(name, "$lut");
+ cell->parameters["\\LUT"] = lut;
+ cell->parameters["\\WIDTH"] = sig_i.size();
+ cell->setPort("\\A", sig_i);
+ cell->setPort("\\Y", sig_o);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en)
+{
+ RTLIL::Cell *cell = addCell(name, "$assert");
+ cell->setPort("\\A", sig_a);
+ cell->setPort("\\EN", sig_en);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addSr(RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity, bool clr_polarity)
+{
+ RTLIL::Cell *cell = addCell(name, "$sr");
+ cell->parameters["\\SET_POLARITY"] = set_polarity;
+ cell->parameters["\\CLR_POLARITY"] = clr_polarity;
+ cell->parameters["\\WIDTH"] = sig_q.size();
+ cell->setPort("\\SET", sig_set);
+ cell->setPort("\\CLR", sig_clr);
+ cell->setPort("\\Q", sig_q);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addDff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity)
+{
+ RTLIL::Cell *cell = addCell(name, "$dff");
+ cell->parameters["\\CLK_POLARITY"] = clk_polarity;
+ cell->parameters["\\WIDTH"] = sig_q.size();
+ cell->setPort("\\CLK", sig_clk);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addDffsr(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
+ RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity)
+{
+ RTLIL::Cell *cell = addCell(name, "$dffsr");
+ cell->parameters["\\CLK_POLARITY"] = clk_polarity;
+ cell->parameters["\\SET_POLARITY"] = set_polarity;
+ cell->parameters["\\CLR_POLARITY"] = clr_polarity;
+ cell->parameters["\\WIDTH"] = sig_q.size();
+ cell->setPort("\\CLK", sig_clk);
+ cell->setPort("\\SET", sig_set);
+ cell->setPort("\\CLR", sig_clr);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addAdff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
+ RTLIL::Const arst_value, bool clk_polarity, bool arst_polarity)
+{
+ RTLIL::Cell *cell = addCell(name, "$adff");
+ cell->parameters["\\CLK_POLARITY"] = clk_polarity;
+ cell->parameters["\\ARST_POLARITY"] = arst_polarity;
+ cell->parameters["\\ARST_VALUE"] = arst_value;
+ cell->parameters["\\WIDTH"] = sig_q.size();
+ cell->setPort("\\CLK", sig_clk);
+ cell->setPort("\\ARST", sig_arst);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addDlatch(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity)
+{
+ RTLIL::Cell *cell = addCell(name, "$dlatch");
+ cell->parameters["\\EN_POLARITY"] = en_polarity;
+ cell->parameters["\\WIDTH"] = sig_q.size();
+ cell->setPort("\\EN", sig_en);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addDlatchsr(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
+ RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, bool set_polarity, bool clr_polarity)
+{
+ RTLIL::Cell *cell = addCell(name, "$dlatchsr");
+ cell->parameters["\\EN_POLARITY"] = en_polarity;
+ cell->parameters["\\SET_POLARITY"] = set_polarity;
+ cell->parameters["\\CLR_POLARITY"] = clr_polarity;
+ cell->parameters["\\WIDTH"] = sig_q.size();
+ cell->setPort("\\EN", sig_en);
+ cell->setPort("\\SET", sig_set);
+ cell->setPort("\\CLR", sig_clr);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addDffGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity)
+{
+ RTLIL::Cell *cell = addCell(name, stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N'));
+ cell->setPort("\\C", sig_clk);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addDffsrGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
+ RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity)
+{
+ RTLIL::Cell *cell = addCell(name, stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N'));
+ cell->setPort("\\C", sig_clk);
+ cell->setPort("\\S", sig_set);
+ cell->setPort("\\R", sig_clr);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addAdffGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
+ bool arst_value, bool clk_polarity, bool arst_polarity)
+{
+ RTLIL::Cell *cell = addCell(name, stringf("$_DFF_%c%c%c_", clk_polarity ? 'P' : 'N', arst_polarity ? 'P' : 'N', arst_value ? '1' : '0'));
+ cell->setPort("\\C", sig_clk);
+ cell->setPort("\\R", sig_arst);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addDlatchGate(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity)
+{
+ RTLIL::Cell *cell = addCell(name, stringf("$_DLATCH_%c_", en_polarity ? 'P' : 'N'));
+ cell->setPort("\\E", sig_en);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
+ RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, bool set_polarity, bool clr_polarity)
+{
+ RTLIL::Cell *cell = addCell(name, stringf("$_DLATCHSR_%c%c%c_", en_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N'));
+ cell->setPort("\\E", sig_en);
+ cell->setPort("\\S", sig_set);
+ cell->setPort("\\R", sig_clr);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ return cell;
+}
+
+
RTLIL::Wire::Wire()
{
+ module = nullptr;
width = 1;
start_offset = 0;
port_id = 0;
port_input = false;
port_output = false;
+ upto = false;
}
RTLIL::Memory::Memory()
@@ -859,10 +1718,146 @@ RTLIL::Memory::Memory()
size = 0;
}
-void RTLIL::Cell::optimize()
+RTLIL::Cell::Cell() : module(nullptr)
+{
+}
+
+bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const
+{
+ return connections_.count(portname) != 0;
+}
+
+void RTLIL::Cell::unsetPort(RTLIL::IdString portname)
+{
+ RTLIL::SigSpec signal;
+ auto conn_it = connections_.find(portname);
+
+ if (conn_it != connections_.end())
+ {
+ for (auto mon : module->monitors)
+ mon->notify_connect(this, conn_it->first, conn_it->second, signal);
+
+ if (module->design)
+ for (auto mon : module->design->monitors)
+ mon->notify_connect(this, conn_it->first, conn_it->second, signal);
+
+ connections_.erase(conn_it);
+ }
+}
+
+void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
+{
+ auto conn_it = connections_.find(portname);
+
+ if (conn_it == connections_.end()) {
+ connections_[portname] = RTLIL::SigSpec();
+ conn_it = connections_.find(portname);
+ log_assert(conn_it != connections_.end());
+ }
+
+ for (auto mon : module->monitors)
+ mon->notify_connect(this, conn_it->first, conn_it->second, signal);
+
+ if (module->design)
+ for (auto mon : module->design->monitors)
+ mon->notify_connect(this, conn_it->first, conn_it->second, signal);
+
+ conn_it->second = signal;
+}
+
+const RTLIL::SigSpec &RTLIL::Cell::getPort(RTLIL::IdString portname) const
+{
+ return connections_.at(portname);
+}
+
+const std::map<RTLIL::IdString, RTLIL::SigSpec> &RTLIL::Cell::connections() const
+{
+ return connections_;
+}
+
+bool RTLIL::Cell::hasParam(RTLIL::IdString paramname) const
+{
+ return parameters.count(paramname);
+}
+
+void RTLIL::Cell::unsetParam(RTLIL::IdString paramname)
+{
+ parameters.erase(paramname);
+}
+
+void RTLIL::Cell::setParam(RTLIL::IdString paramname, RTLIL::Const value)
{
- for (auto &it : connections)
- it.second.optimize();
+ parameters[paramname] = value;
+}
+
+const RTLIL::Const &RTLIL::Cell::getParam(RTLIL::IdString paramname) const
+{
+ return parameters.at(paramname);
+}
+
+void RTLIL::Cell::check()
+{
+#ifndef NDEBUG
+ InternalCellChecker checker(NULL, this);
+ checker.check();
+#endif
+}
+
+void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
+{
+ if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" ||
+ type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:")
+ return;
+
+ if (type == "$mux" || type == "$pmux") {
+ parameters["\\WIDTH"] = SIZE(connections_["\\Y"]);
+ if (type == "$pmux")
+ parameters["\\S_WIDTH"] = SIZE(connections_["\\S"]);
+ check();
+ return;
+ }
+
+ if (type == "$lut") {
+ parameters["\\WIDTH"] = SIZE(connections_["\\A"]);
+ return;
+ }
+
+ if (type == "$fa") {
+ parameters["\\WIDTH"] = SIZE(connections_["\\Y"]);
+ return;
+ }
+
+ if (type == "$lcu") {
+ parameters["\\WIDTH"] = SIZE(connections_["\\CO"]);
+ return;
+ }
+
+ bool signedness_ab = !type.in("$slice", "$concat", "$macc");
+
+ if (connections_.count("\\A")) {
+ if (signedness_ab) {
+ if (set_a_signed)
+ parameters["\\A_SIGNED"] = true;
+ else if (parameters.count("\\A_SIGNED") == 0)
+ parameters["\\A_SIGNED"] = false;
+ }
+ parameters["\\A_WIDTH"] = SIZE(connections_["\\A"]);
+ }
+
+ if (connections_.count("\\B")) {
+ if (signedness_ab) {
+ if (set_b_signed)
+ parameters["\\B_SIGNED"] = true;
+ else if (parameters.count("\\B_SIGNED") == 0)
+ parameters["\\B_SIGNED"] = false;
+ }
+ parameters["\\B_WIDTH"] = SIZE(connections_["\\B"]);
+ }
+
+ if (connections_.count("\\Y"))
+ parameters["\\Y_WIDTH"] = SIZE(connections_["\\Y"]);
+
+ check();
}
RTLIL::SigChunk::SigChunk()
@@ -872,51 +1867,62 @@ RTLIL::SigChunk::SigChunk()
offset = 0;
}
-RTLIL::SigChunk::SigChunk(const RTLIL::Const &data)
+RTLIL::SigChunk::SigChunk(const RTLIL::Const &value)
{
wire = NULL;
- this->data = data;
- width = data.bits.size();
+ data = value.bits;
+ width = SIZE(data);
offset = 0;
}
-RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire, int width, int offset)
+RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire)
+{
+ log_assert(wire != nullptr);
+ this->wire = wire;
+ this->width = wire->width;
+ this->offset = 0;
+}
+
+RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire, int offset, int width)
{
+ log_assert(wire != nullptr);
this->wire = wire;
- this->width = width >= 0 ? width : wire->width;
+ this->width = width;
this->offset = offset;
}
RTLIL::SigChunk::SigChunk(const std::string &str)
{
wire = NULL;
- data = RTLIL::Const(str);
- width = data.bits.size();
+ data = RTLIL::Const(str).bits;
+ width = SIZE(data);
offset = 0;
}
RTLIL::SigChunk::SigChunk(int val, int width)
{
wire = NULL;
- data = RTLIL::Const(val, width);
- this->width = data.bits.size();
+ data = RTLIL::Const(val, width).bits;
+ this->width = SIZE(data);
offset = 0;
}
RTLIL::SigChunk::SigChunk(RTLIL::State bit, int width)
{
wire = NULL;
- data = RTLIL::Const(bit, width);
- this->width = data.bits.size();
+ data = RTLIL::Const(bit, width).bits;
+ this->width = SIZE(data);
offset = 0;
}
RTLIL::SigChunk::SigChunk(RTLIL::SigBit bit)
{
wire = bit.wire;
+ offset = 0;
if (wire == NULL)
- data = RTLIL::Const(bit.data);
- offset = bit.offset;
+ data = RTLIL::Const(bit.data).bits;
+ else
+ offset = bit.offset;
width = 1;
}
@@ -929,7 +1935,7 @@ RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const
ret.width = length;
} else {
for (int i = 0; i < length; i++)
- ret.data.bits.push_back(data.bits[offset+i]);
+ ret.data.push_back(data[offset+i]);
ret.width = length;
}
return ret;
@@ -940,6 +1946,7 @@ bool RTLIL::SigChunk::operator <(const RTLIL::SigChunk &other) const
if (wire && other.wire)
if (wire->name != other.wire->name)
return wire->name < other.wire->name;
+
if (wire != other.wire)
return wire < other.wire;
@@ -949,19 +1956,12 @@ bool RTLIL::SigChunk::operator <(const RTLIL::SigChunk &other) const
if (width != other.width)
return width < other.width;
- if (data.bits != other.data.bits)
- return data.bits < other.data.bits;
-
- return false;
+ return data < other.data;
}
bool RTLIL::SigChunk::operator ==(const RTLIL::SigChunk &other) const
{
- if (wire != other.wire || width != other.width || offset != other.offset)
- return false;
- if (data.bits != other.data.bits)
- return false;
- return true;
+ return wire == other.wire && width == other.width && offset == other.offset && data == other.data;
}
bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const
@@ -973,146 +1973,274 @@ bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const
RTLIL::SigSpec::SigSpec()
{
- width = 0;
+ width_ = 0;
+ hash_ = 0;
+}
+
+RTLIL::SigSpec::SigSpec(const RTLIL::SigSpec &other)
+{
+ *this = other;
+}
+
+RTLIL::SigSpec::SigSpec(std::initializer_list<RTLIL::SigSpec> parts)
+{
+ cover("kernel.rtlil.sigspec.init.list");
+
+ width_ = 0;
+ hash_ = 0;
+
+ std::vector<RTLIL::SigSpec> parts_vec(parts.begin(), parts.end());
+ for (auto it = parts_vec.rbegin(); it != parts_vec.rend(); it++)
+ append(*it);
+}
+
+const RTLIL::SigSpec &RTLIL::SigSpec::operator=(const RTLIL::SigSpec &other)
+{
+ cover("kernel.rtlil.sigspec.assign");
+
+ width_ = other.width_;
+ hash_ = other.hash_;
+ chunks_ = other.chunks_;
+ bits_.clear();
+
+ if (!other.bits_.empty())
+ {
+ RTLIL::SigChunk *last = NULL;
+ int last_end_offset = 0;
+
+ for (auto &bit : other.bits_) {
+ if (last && bit.wire == last->wire) {
+ if (bit.wire == NULL) {
+ last->data.push_back(bit.data);
+ last->width++;
+ continue;
+ } else if (last_end_offset == bit.offset) {
+ last_end_offset++;
+ last->width++;
+ continue;
+ }
+ }
+ chunks_.push_back(bit);
+ last = &chunks_.back();
+ last_end_offset = bit.offset + 1;
+ }
+
+ check();
+ }
+
+ return *this;
}
-RTLIL::SigSpec::SigSpec(const RTLIL::Const &data)
+RTLIL::SigSpec::SigSpec(const RTLIL::Const &value)
{
- chunks.push_back(RTLIL::SigChunk(data));
- width = chunks.back().width;
+ cover("kernel.rtlil.sigspec.init.const");
+
+ chunks_.push_back(RTLIL::SigChunk(value));
+ width_ = chunks_.back().width;
+ hash_ = 0;
check();
}
RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk)
{
- chunks.push_back(chunk);
- width = chunks.back().width;
+ cover("kernel.rtlil.sigspec.init.chunk");
+
+ chunks_.push_back(chunk);
+ width_ = chunks_.back().width;
+ hash_ = 0;
+ check();
+}
+
+RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire)
+{
+ cover("kernel.rtlil.sigspec.init.wire");
+
+ chunks_.push_back(RTLIL::SigChunk(wire));
+ width_ = chunks_.back().width;
+ hash_ = 0;
check();
}
-RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int width, int offset)
+RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width)
{
- chunks.push_back(RTLIL::SigChunk(wire, width, offset));
- this->width = chunks.back().width;
+ cover("kernel.rtlil.sigspec.init.wire_part");
+
+ chunks_.push_back(RTLIL::SigChunk(wire, offset, width));
+ width_ = chunks_.back().width;
+ hash_ = 0;
check();
}
RTLIL::SigSpec::SigSpec(const std::string &str)
{
- chunks.push_back(RTLIL::SigChunk(str));
- width = chunks.back().width;
+ cover("kernel.rtlil.sigspec.init.str");
+
+ chunks_.push_back(RTLIL::SigChunk(str));
+ width_ = chunks_.back().width;
+ hash_ = 0;
check();
}
RTLIL::SigSpec::SigSpec(int val, int width)
{
- chunks.push_back(RTLIL::SigChunk(val, width));
- this->width = width;
+ cover("kernel.rtlil.sigspec.init.int");
+
+ chunks_.push_back(RTLIL::SigChunk(val, width));
+ width_ = width;
+ hash_ = 0;
check();
}
RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width)
{
- chunks.push_back(RTLIL::SigChunk(bit, width));
- this->width = width;
+ cover("kernel.rtlil.sigspec.init.state");
+
+ chunks_.push_back(RTLIL::SigChunk(bit, width));
+ width_ = width;
+ hash_ = 0;
check();
}
RTLIL::SigSpec::SigSpec(RTLIL::SigBit bit, int width)
{
+ cover("kernel.rtlil.sigspec.init.bit");
+
if (bit.wire == NULL)
- chunks.push_back(RTLIL::SigChunk(bit.data, width));
+ chunks_.push_back(RTLIL::SigChunk(bit.data, width));
else
for (int i = 0; i < width; i++)
- chunks.push_back(bit);
- this->width = width;
+ chunks_.push_back(bit);
+ width_ = width;
+ hash_ = 0;
+ check();
+}
+
+RTLIL::SigSpec::SigSpec(std::vector<RTLIL::SigChunk> chunks)
+{
+ cover("kernel.rtlil.sigspec.init.stdvec_chunks");
+
+ width_ = 0;
+ hash_ = 0;
+ for (auto &c : chunks)
+ append(c);
check();
}
RTLIL::SigSpec::SigSpec(std::vector<RTLIL::SigBit> bits)
{
- chunks.reserve(bits.size());
+ cover("kernel.rtlil.sigspec.init.stdvec_bits");
+
+ width_ = 0;
+ hash_ = 0;
for (auto &bit : bits)
- chunks.push_back(bit);
- this->width = bits.size();
+ append_bit(bit);
check();
}
-void RTLIL::SigSpec::expand()
+RTLIL::SigSpec::SigSpec(std::set<RTLIL::SigBit> bits)
{
- std::vector<RTLIL::SigChunk> new_chunks;
- for (size_t i = 0; i < chunks.size(); i++) {
- for (int j = 0; j < chunks[i].width; j++)
- new_chunks.push_back(chunks[i].extract(j, 1));
- }
- chunks.swap(new_chunks);
+ cover("kernel.rtlil.sigspec.init.stdset_bits");
+
+ width_ = 0;
+ hash_ = 0;
+ for (auto &bit : bits)
+ append_bit(bit);
check();
}
-void RTLIL::SigSpec::optimize()
+void RTLIL::SigSpec::pack() const
{
- std::vector<RTLIL::SigChunk> new_chunks;
- for (auto &c : chunks)
- if (new_chunks.size() == 0) {
- new_chunks.push_back(c);
- } else {
- RTLIL::SigChunk &cc = new_chunks.back();
- if (c.wire == NULL && cc.wire == NULL)
- cc.data.bits.insert(cc.data.bits.end(), c.data.bits.begin(), c.data.bits.end());
- if (c.wire == cc.wire && (c.wire == NULL || cc.offset + cc.width == c.offset))
- cc.width += c.width;
- else
- new_chunks.push_back(c);
+ RTLIL::SigSpec *that = (RTLIL::SigSpec*)this;
+
+ if (that->bits_.empty())
+ return;
+
+ cover("kernel.rtlil.sigspec.convert.pack");
+ log_assert(that->chunks_.empty());
+
+ std::vector<RTLIL::SigBit> old_bits;
+ old_bits.swap(that->bits_);
+
+ RTLIL::SigChunk *last = NULL;
+ int last_end_offset = 0;
+
+ for (auto &bit : old_bits) {
+ if (last && bit.wire == last->wire) {
+ if (bit.wire == NULL) {
+ last->data.push_back(bit.data);
+ last->width++;
+ continue;
+ } else if (last_end_offset == bit.offset) {
+ last_end_offset++;
+ last->width++;
+ continue;
+ }
}
- chunks.swap(new_chunks);
+ that->chunks_.push_back(bit);
+ last = &that->chunks_.back();
+ last_end_offset = bit.offset + 1;
+ }
+
check();
}
-RTLIL::SigSpec RTLIL::SigSpec::optimized() const
+void RTLIL::SigSpec::unpack() const
{
- RTLIL::SigSpec ret = *this;
- ret.optimize();
- return ret;
+ RTLIL::SigSpec *that = (RTLIL::SigSpec*)this;
+
+ if (that->chunks_.empty())
+ return;
+
+ cover("kernel.rtlil.sigspec.convert.unpack");
+ log_assert(that->bits_.empty());
+
+ that->bits_.reserve(that->width_);
+ for (auto &c : that->chunks_)
+ for (int i = 0; i < c.width; i++)
+ that->bits_.push_back(RTLIL::SigBit(c, i));
+
+ that->chunks_.clear();
+ that->hash_ = 0;
}
-bool RTLIL::SigChunk::compare(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b)
+#define DJB2(_hash, _value) do { (_hash) = (((_hash) << 5) + (_hash)) + (_value); } while (0)
+
+void RTLIL::SigSpec::hash() const
{
- if (a.wire != b.wire) {
- if (a.wire == NULL || b.wire == NULL)
- return a.wire < b.wire;
- else if (a.wire->name != b.wire->name)
- return a.wire->name < b.wire->name;
- else
- return a.wire < b.wire;
- }
- if (a.offset != b.offset)
- return a.offset < b.offset;
- if (a.width != b.width)
- return a.width < b.width;
- return a.data.bits < b.data.bits;
+ RTLIL::SigSpec *that = (RTLIL::SigSpec*)this;
+
+ if (that->hash_ != 0)
+ return;
+
+ cover("kernel.rtlil.sigspec.hash");
+ that->pack();
+
+ that->hash_ = 5381;
+ for (auto &c : that->chunks_)
+ if (c.wire == NULL) {
+ for (auto &v : c.data)
+ DJB2(that->hash_, v);
+ } else {
+ DJB2(that->hash_, c.wire->name.index_);
+ DJB2(that->hash_, c.offset);
+ DJB2(that->hash_, c.width);
+ }
+
+ if (that->hash_ == 0)
+ that->hash_ = 1;
}
void RTLIL::SigSpec::sort()
{
- expand();
- std::sort(chunks.begin(), chunks.end(), RTLIL::SigChunk::compare);
- optimize();
+ unpack();
+ cover("kernel.rtlil.sigspec.sort");
+ std::sort(bits_.begin(), bits_.end());
}
void RTLIL::SigSpec::sort_and_unify()
{
- expand();
- std::sort(chunks.begin(), chunks.end(), RTLIL::SigChunk::compare);
- for (size_t i = 1; i < chunks.size(); i++) {
- RTLIL::SigChunk &ch1 = chunks[i-1];
- RTLIL::SigChunk &ch2 = chunks[i];
- if (!RTLIL::SigChunk::compare(ch1, ch2) && !RTLIL::SigChunk::compare(ch2, ch1)) {
- chunks.erase(chunks.begin()+i);
- width -= chunks[i].width;
- i--;
- }
- }
- optimize();
+ cover("kernel.rtlil.sigspec.sort_and_unify");
+ *this = this->to_sigbit_set();
}
void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with)
@@ -1122,29 +2250,42 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec
void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const
{
- int pos = 0, restart_pos = 0;
- assert(other == NULL || width == other->width);
- for (size_t i = 0; i < chunks.size(); i++) {
-restart:
- const RTLIL::SigChunk &ch1 = chunks[i];
- if (chunks[i].wire != NULL && pos >= restart_pos)
- for (size_t j = 0, poff = 0; j < pattern.chunks.size(); j++) {
- const RTLIL::SigChunk &ch2 = pattern.chunks[j];
- assert(ch2.wire != NULL);
- if (ch1.wire == ch2.wire) {
- int lower = std::max(ch1.offset, ch2.offset);
- int upper = std::min(ch1.offset + ch1.width, ch2.offset + ch2.width);
- if (lower < upper) {
- restart_pos = pos+upper-ch1.offset;
- other->replace(pos+lower-ch1.offset, with.extract(poff+lower-ch2.offset, upper-lower));
- goto restart;
- }
- }
- poff += ch2.width;
- }
- pos += chunks[i].width;
+ log_assert(pattern.width_ == with.width_);
+
+ pattern.unpack();
+ with.unpack();
+
+ std::map<RTLIL::SigBit, RTLIL::SigBit> rules;
+
+ for (int i = 0; i < SIZE(pattern.bits_); i++)
+ if (pattern.bits_[i].wire != NULL)
+ rules[pattern.bits_[i]] = with.bits_[i];
+
+ replace(rules, other);
+}
+
+void RTLIL::SigSpec::replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules)
+{
+ replace(rules, this);
+}
+
+void RTLIL::SigSpec::replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const
+{
+ cover("kernel.rtlil.sigspec.replace");
+
+ log_assert(other != NULL);
+ log_assert(width_ == other->width_);
+
+ unpack();
+ other->unpack();
+
+ for (int i = 0; i < SIZE(bits_); i++) {
+ auto it = rules.find(bits_[i]);
+ if (it != rules.end())
+ other->bits_[i] = it->second;
}
- check();
+
+ other->check();
}
void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern)
@@ -1160,49 +2301,91 @@ void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other
void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other)
{
- int pos = 0;
- assert(other == NULL || width == other->width);
- for (size_t i = 0; i < chunks.size(); i++) {
-restart:
- const RTLIL::SigChunk &ch1 = chunks[i];
- if (chunks[i].wire != NULL)
- for (size_t j = 0; j < pattern.chunks.size(); j++) {
- const RTLIL::SigChunk &ch2 = pattern.chunks[j];
- assert(ch2.wire != NULL);
- if (ch1.wire == ch2.wire) {
- int lower = std::max(ch1.offset, ch2.offset);
- int upper = std::min(ch1.offset + ch1.width, ch2.offset + ch2.width);
- if (lower < upper) {
- if (other)
- other->remove(pos+lower-ch1.offset, upper-lower);
- remove(pos+lower-ch1.offset, upper-lower);
- if (i == chunks.size())
- break;
- goto restart;
- }
- }
- }
- pos += chunks[i].width;
+ std::set<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_set();
+ remove2(pattern_bits, other);
+}
+
+void RTLIL::SigSpec::remove(const std::set<RTLIL::SigBit> &pattern)
+{
+ remove2(pattern, NULL);
+}
+
+void RTLIL::SigSpec::remove(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const
+{
+ RTLIL::SigSpec tmp = *this;
+ tmp.remove2(pattern, other);
+}
+
+void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other)
+{
+ if (other)
+ cover("kernel.rtlil.sigspec.remove_other");
+ else
+ cover("kernel.rtlil.sigspec.remove");
+
+ unpack();
+
+ if (other != NULL) {
+ log_assert(width_ == other->width_);
+ other->unpack();
+ }
+
+ std::vector<RTLIL::SigBit> new_bits, new_other_bits;
+
+ new_bits.resize(SIZE(bits_));
+ if (other != NULL)
+ new_other_bits.resize(SIZE(bits_));
+
+ int k = 0;
+ for (int i = 0; i < SIZE(bits_); i++) {
+ if (bits_[i].wire != NULL && pattern.count(bits_[i]))
+ continue;
+ if (other != NULL)
+ new_other_bits[k] = other->bits_[i];
+ new_bits[k++] = bits_[i];
+ }
+
+ new_bits.resize(k);
+ if (other != NULL)
+ new_other_bits.resize(k);
+
+ bits_.swap(new_bits);
+ width_ = SIZE(bits_);
+
+ if (other != NULL) {
+ other->bits_.swap(new_other_bits);
+ other->width_ = SIZE(other->bits_);
}
+
check();
}
-RTLIL::SigSpec RTLIL::SigSpec::extract(RTLIL::SigSpec pattern, RTLIL::SigSpec *other) const
+RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other) const
{
- assert(other == NULL || width == other->width);
+ std::set<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_set();
+ return extract(pattern_bits, other);
+}
+
+RTLIL::SigSpec RTLIL::SigSpec::extract(const std::set<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other) const
+{
+ if (other)
+ cover("kernel.rtlil.sigspec.extract_other");
+ else
+ cover("kernel.rtlil.sigspec.extract");
+
+ log_assert(other == NULL || width_ == other->width_);
- std::set<RTLIL::SigBit> pat = pattern.to_sigbit_set();
std::vector<RTLIL::SigBit> bits_match = to_sigbit_vector();
RTLIL::SigSpec ret;
if (other) {
- std::vector<RTLIL::SigBit> bits_other = other ? other->to_sigbit_vector() : bits_match;
- for (int i = 0; i < width; i++)
- if (bits_match[i].wire && pat.count(bits_match[i]))
+ std::vector<RTLIL::SigBit> bits_other = other->to_sigbit_vector();
+ for (int i = 0; i < width_; i++)
+ if (bits_match[i].wire && pattern.count(bits_match[i]))
ret.append_bit(bits_other[i]);
} else {
- for (int i = 0; i < width; i++)
- if (bits_match[i].wire && pat.count(bits_match[i]))
+ for (int i = 0; i < width_; i++)
+ if (bits_match[i].wire && pattern.count(bits_match[i]))
ret.append_bit(bits_match[i]);
}
@@ -1212,259 +2395,326 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(RTLIL::SigSpec pattern, RTLIL::SigSpec *o
void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with)
{
- int pos = 0;
- assert(offset >= 0);
- assert(with.width >= 0);
- assert(offset+with.width <= width);
- remove(offset, with.width);
- for (size_t i = 0; i < chunks.size(); i++) {
- if (pos == offset) {
- chunks.insert(chunks.begin()+i, with.chunks.begin(), with.chunks.end());
- width += with.width;
- check();
- return;
- }
- pos += chunks[i].width;
- }
- assert(pos == offset);
- chunks.insert(chunks.end(), with.chunks.begin(), with.chunks.end());
- width += with.width;
+ cover("kernel.rtlil.sigspec.replace_pos");
+
+ unpack();
+ with.unpack();
+
+ log_assert(offset >= 0);
+ log_assert(with.width_ >= 0);
+ log_assert(offset+with.width_ <= width_);
+
+ for (int i = 0; i < with.width_; i++)
+ bits_.at(offset + i) = with.bits_.at(i);
+
check();
}
void RTLIL::SigSpec::remove_const()
{
- for (size_t i = 0; i < chunks.size(); i++) {
- if (chunks[i].wire != NULL)
- continue;
- width -= chunks[i].width;
- chunks.erase(chunks.begin() + (i--));
+ if (packed())
+ {
+ cover("kernel.rtlil.sigspec.remove_const.packed");
+
+ std::vector<RTLIL::SigChunk> new_chunks;
+ new_chunks.reserve(SIZE(chunks_));
+
+ width_ = 0;
+ for (auto &chunk : chunks_)
+ if (chunk.wire != NULL) {
+ new_chunks.push_back(chunk);
+ width_ += chunk.width;
+ }
+
+ chunks_.swap(new_chunks);
+ }
+ else
+ {
+ cover("kernel.rtlil.sigspec.remove_const.unpacked");
+
+ std::vector<RTLIL::SigBit> new_bits;
+ new_bits.reserve(width_);
+
+ for (auto &bit : bits_)
+ if (bit.wire != NULL)
+ new_bits.push_back(bit);
+
+ bits_.swap(new_bits);
+ width_ = bits_.size();
}
+
check();
}
void RTLIL::SigSpec::remove(int offset, int length)
{
- int pos = 0;
- assert(offset >= 0);
- assert(length >= 0);
- assert(offset+length <= width);
- for (size_t i = 0; i < chunks.size(); i++) {
- int orig_width = chunks[i].width;
- if (pos+chunks[i].width > offset && pos < offset+length) {
- int off = offset - pos;
- int len = length;
- if (off < 0) {
- len += off;
- off = 0;
- }
- if (len > chunks[i].width-off)
- len = chunks[i].width-off;
- RTLIL::SigChunk lsb_chunk = chunks[i].extract(0, off);
- RTLIL::SigChunk msb_chunk = chunks[i].extract(off+len, chunks[i].width-off-len);
- if (lsb_chunk.width == 0 && msb_chunk.width == 0) {
- chunks.erase(chunks.begin()+i);
- i--;
- } else if (lsb_chunk.width == 0 && msb_chunk.width != 0) {
- chunks[i] = msb_chunk;
- } else if (lsb_chunk.width != 0 && msb_chunk.width == 0) {
- chunks[i] = lsb_chunk;
- } else if (lsb_chunk.width != 0 && msb_chunk.width != 0) {
- chunks[i] = lsb_chunk;
- chunks.insert(chunks.begin()+i+1, msb_chunk);
- i++;
- } else
- assert(0);
- width -= len;
- }
- pos += orig_width;
- }
+ cover("kernel.rtlil.sigspec.remove_pos");
+
+ unpack();
+
+ log_assert(offset >= 0);
+ log_assert(length >= 0);
+ log_assert(offset + length <= width_);
+
+ bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length);
+ width_ = bits_.size();
+
check();
}
RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const
{
- int pos = 0;
- RTLIL::SigSpec ret;
- assert(offset >= 0);
- assert(length >= 0);
- assert(offset+length <= width);
- for (size_t i = 0; i < chunks.size(); i++) {
- if (pos+chunks[i].width > offset && pos < offset+length) {
- int off = offset - pos;
- int len = length;
- if (off < 0) {
- len += off;
- off = 0;
- }
- if (len > chunks[i].width-off)
- len = chunks[i].width-off;
- ret.chunks.push_back(chunks[i].extract(off, len));
- ret.width += len;
- offset += len;
- length -= len;
- }
- pos += chunks[i].width;
- }
- assert(length == 0);
- ret.check();
- return ret;
+ unpack();
+ cover("kernel.rtlil.sigspec.extract_pos");
+ return std::vector<RTLIL::SigBit>(bits_.begin() + offset, bits_.begin() + offset + length);
}
void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal)
{
- for (size_t i = 0; i < signal.chunks.size(); i++) {
- chunks.push_back(signal.chunks[i]);
- width += signal.chunks[i].width;
+ if (signal.width_ == 0)
+ return;
+
+ if (width_ == 0) {
+ *this = signal;
+ return;
}
- // check();
-}
-void RTLIL::SigSpec::append_bit(const RTLIL::SigBit &bit)
-{
- if (chunks.size() == 0)
- chunks.push_back(bit);
+ cover("kernel.rtlil.sigspec.append");
+
+ if (packed() != signal.packed()) {
+ pack();
+ signal.pack();
+ }
+
+ if (packed())
+ for (auto &other_c : signal.chunks_)
+ {
+ auto &my_last_c = chunks_.back();
+ if (my_last_c.wire == NULL && other_c.wire == NULL) {
+ auto &this_data = my_last_c.data;
+ auto &other_data = other_c.data;
+ this_data.insert(this_data.end(), other_data.begin(), other_data.end());
+ my_last_c.width += other_c.width;
+ } else
+ if (my_last_c.wire == other_c.wire && my_last_c.offset + my_last_c.width == other_c.offset) {
+ my_last_c.width += other_c.width;
+ } else
+ chunks_.push_back(other_c);
+ }
else
- if (bit.wire == NULL)
- if (chunks.back().wire == NULL)
- chunks.back().data.bits.push_back(bit.data);
- else
- chunks.push_back(bit);
- else
- if (chunks.back().wire == bit.wire && chunks.back().offset + chunks.back().width == bit.offset)
- chunks.back().width++;
- else
- chunks.push_back(bit);
- width++;
- // check();
+ bits_.insert(bits_.end(), signal.bits_.begin(), signal.bits_.end());
+
+ width_ += signal.width_;
+ check();
}
-bool RTLIL::SigSpec::combine(RTLIL::SigSpec signal, RTLIL::State freeState, bool override)
+void RTLIL::SigSpec::append_bit(const RTLIL::SigBit &bit)
{
- bool no_collisions = true;
-
- assert(width == signal.width);
- expand();
- signal.expand();
+ if (packed())
+ {
+ cover("kernel.rtlil.sigspec.append_bit.packed");
- for (size_t i = 0; i < chunks.size(); i++) {
- bool self_free = chunks[i].wire == NULL && chunks[i].data.bits[0] == freeState;
- bool other_free = signal.chunks[i].wire == NULL && signal.chunks[i].data.bits[0] == freeState;
- if (!self_free && !other_free) {
- if (override)
- chunks[i] = signal.chunks[i];
+ if (chunks_.size() == 0)
+ chunks_.push_back(bit);
+ else
+ if (bit.wire == NULL)
+ if (chunks_.back().wire == NULL) {
+ chunks_.back().data.push_back(bit.data);
+ chunks_.back().width++;
+ } else
+ chunks_.push_back(bit);
else
- chunks[i] = RTLIL::SigChunk(RTLIL::State::Sx, 1);
- no_collisions = false;
- }
- if (self_free && !other_free)
- chunks[i] = signal.chunks[i];
+ if (chunks_.back().wire == bit.wire && chunks_.back().offset + chunks_.back().width == bit.offset)
+ chunks_.back().width++;
+ else
+ chunks_.push_back(bit);
+ }
+ else
+ {
+ cover("kernel.rtlil.sigspec.append_bit.unpacked");
+ bits_.push_back(bit);
}
- optimize();
- return no_collisions;
+ width_++;
+ check();
}
void RTLIL::SigSpec::extend(int width, bool is_signed)
{
- if (this->width > width)
- remove(width, this->width - width);
+ cover("kernel.rtlil.sigspec.extend");
+
+ pack();
+
+ if (width_ > width)
+ remove(width, width_ - width);
- if (this->width < width) {
- RTLIL::SigSpec padding = this->width > 0 ? extract(this->width - 1, 1) : RTLIL::SigSpec(RTLIL::State::S0);
+ if (width_ < width) {
+ RTLIL::SigSpec padding = width_ > 0 ? extract(width_ - 1, 1) : RTLIL::SigSpec(RTLIL::State::S0);
if (!is_signed && padding != RTLIL::SigSpec(RTLIL::State::Sx) && padding != RTLIL::SigSpec(RTLIL::State::Sz) &&
padding != RTLIL::SigSpec(RTLIL::State::Sa) && padding != RTLIL::SigSpec(RTLIL::State::Sm))
padding = RTLIL::SigSpec(RTLIL::State::S0);
- while (this->width < width)
+ while (width_ < width)
append(padding);
}
-
- optimize();
}
void RTLIL::SigSpec::extend_u0(int width, bool is_signed)
{
- if (this->width > width)
- remove(width, this->width - width);
+ cover("kernel.rtlil.sigspec.extend_u0");
+
+ pack();
+
+ if (width_ > width)
+ remove(width, width_ - width);
- if (this->width < width) {
- RTLIL::SigSpec padding = this->width > 0 ? extract(this->width - 1, 1) : RTLIL::SigSpec(RTLIL::State::S0);
+ if (width_ < width) {
+ RTLIL::SigSpec padding = width_ > 0 ? extract(width_ - 1, 1) : RTLIL::SigSpec(RTLIL::State::S0);
if (!is_signed)
padding = RTLIL::SigSpec(RTLIL::State::S0);
- while (this->width < width)
+ while (width_ < width)
append(padding);
}
- optimize();
}
+RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const
+{
+ cover("kernel.rtlil.sigspec.repeat");
+
+ RTLIL::SigSpec sig;
+ for (int i = 0; i < num; i++)
+ sig.append(*this);
+ return sig;
+}
+
+#ifndef NDEBUG
void RTLIL::SigSpec::check() const
{
- int w = 0;
- for (size_t i = 0; i < chunks.size(); i++) {
- const RTLIL::SigChunk chunk = chunks[i];
- if (chunk.wire == NULL) {
- assert(chunk.offset == 0);
- assert(chunk.data.bits.size() == (size_t)chunk.width);
- } else {
- assert(chunk.offset >= 0);
- assert(chunk.width >= 0);
- assert(chunk.offset + chunk.width <= chunk.wire->width);
- assert(chunk.data.bits.size() == 0);
+ if (width_ > 64)
+ {
+ cover("kernel.rtlil.sigspec.check.skip");
+ }
+ else if (packed())
+ {
+ cover("kernel.rtlil.sigspec.check.packed");
+
+ int w = 0;
+ for (size_t i = 0; i < chunks_.size(); i++) {
+ const RTLIL::SigChunk chunk = chunks_[i];
+ if (chunk.wire == NULL) {
+ if (i > 0)
+ log_assert(chunks_[i-1].wire != NULL);
+ log_assert(chunk.offset == 0);
+ log_assert(chunk.data.size() == (size_t)chunk.width);
+ } else {
+ if (i > 0 && chunks_[i-1].wire == chunk.wire)
+ log_assert(chunk.offset != chunks_[i-1].offset + chunks_[i-1].width);
+ log_assert(chunk.offset >= 0);
+ log_assert(chunk.width >= 0);
+ log_assert(chunk.offset + chunk.width <= chunk.wire->width);
+ log_assert(chunk.data.size() == 0);
+ }
+ w += chunk.width;
}
- w += chunk.width;
+ log_assert(w == width_);
+ log_assert(bits_.empty());
+ }
+ else
+ {
+ cover("kernel.rtlil.sigspec.check.unpacked");
+
+ log_assert(width_ == SIZE(bits_));
+ log_assert(chunks_.empty());
}
- assert(w == width);
}
+#endif
bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const
{
- if (width != other.width)
- return width < other.width;
+ cover("kernel.rtlil.sigspec.comp_lt");
+
+ if (this == &other)
+ return false;
- RTLIL::SigSpec a = *this, b = other;
- a.optimize();
- b.optimize();
+ if (width_ != other.width_)
+ return width_ < other.width_;
- if (a.chunks.size() != b.chunks.size())
- return a.chunks.size() < b.chunks.size();
+ pack();
+ other.pack();
- for (size_t i = 0; i < a.chunks.size(); i++)
- if (a.chunks[i] != b.chunks[i])
- return a.chunks[i] < b.chunks[i];
+ if (chunks_.size() != other.chunks_.size())
+ return chunks_.size() < other.chunks_.size();
+ hash();
+ other.hash();
+
+ if (hash_ != other.hash_)
+ return hash_ < other.hash_;
+
+ for (size_t i = 0; i < chunks_.size(); i++)
+ if (chunks_[i] != other.chunks_[i]) {
+ cover("kernel.rtlil.sigspec.comp_lt.hash_collision");
+ return chunks_[i] < other.chunks_[i];
+ }
+
+ cover("kernel.rtlil.sigspec.comp_lt.equal");
return false;
}
bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const
{
- if (width != other.width)
+ cover("kernel.rtlil.sigspec.comp_eq");
+
+ if (this == &other)
+ return true;
+
+ if (width_ != other.width_)
+ return false;
+
+ pack();
+ other.pack();
+
+ if (chunks_.size() != chunks_.size())
return false;
- RTLIL::SigSpec a = *this, b = other;
- a.optimize();
- b.optimize();
+ hash();
+ other.hash();
- if (a.chunks.size() != b.chunks.size())
+ if (hash_ != other.hash_)
return false;
- for (size_t i = 0; i < a.chunks.size(); i++)
- if (a.chunks[i] != b.chunks[i])
+ for (size_t i = 0; i < chunks_.size(); i++)
+ if (chunks_[i] != other.chunks_[i]) {
+ cover("kernel.rtlil.sigspec.comp_eq.hash_collision");
return false;
+ }
+ cover("kernel.rtlil.sigspec.comp_eq.equal");
return true;
}
-bool RTLIL::SigSpec::operator !=(const RTLIL::SigSpec &other) const
+bool RTLIL::SigSpec::is_wire() const
{
- if (*this == other)
- return false;
- return true;
+ cover("kernel.rtlil.sigspec.is_wire");
+
+ pack();
+ return SIZE(chunks_) == 1 && chunks_[0].wire && chunks_[0].wire->width == width_;
+}
+
+bool RTLIL::SigSpec::is_chunk() const
+{
+ cover("kernel.rtlil.sigspec.is_chunk");
+
+ pack();
+ return SIZE(chunks_) == 1;
}
bool RTLIL::SigSpec::is_fully_const() const
{
- for (auto it = chunks.begin(); it != chunks.end(); it++)
+ cover("kernel.rtlil.sigspec.is_fully_const");
+
+ pack();
+ for (auto it = chunks_.begin(); it != chunks_.end(); it++)
if (it->width > 0 && it->wire != NULL)
return false;
return true;
@@ -1472,11 +2722,14 @@ bool RTLIL::SigSpec::is_fully_const() const
bool RTLIL::SigSpec::is_fully_def() const
{
- for (auto it = chunks.begin(); it != chunks.end(); it++) {
+ cover("kernel.rtlil.sigspec.is_fully_def");
+
+ pack();
+ for (auto it = chunks_.begin(); it != chunks_.end(); it++) {
if (it->width > 0 && it->wire != NULL)
return false;
- for (size_t i = 0; i < it->data.bits.size(); i++)
- if (it->data.bits[i] != RTLIL::State::S0 && it->data.bits[i] != RTLIL::State::S1)
+ for (size_t i = 0; i < it->data.size(); i++)
+ if (it->data[i] != RTLIL::State::S0 && it->data[i] != RTLIL::State::S1)
return false;
}
return true;
@@ -1484,11 +2737,14 @@ bool RTLIL::SigSpec::is_fully_def() const
bool RTLIL::SigSpec::is_fully_undef() const
{
- for (auto it = chunks.begin(); it != chunks.end(); it++) {
+ cover("kernel.rtlil.sigspec.is_fully_undef");
+
+ pack();
+ for (auto it = chunks_.begin(); it != chunks_.end(); it++) {
if (it->width > 0 && it->wire != NULL)
return false;
- for (size_t i = 0; i < it->data.bits.size(); i++)
- if (it->data.bits[i] != RTLIL::State::Sx && it->data.bits[i] != RTLIL::State::Sz)
+ for (size_t i = 0; i < it->data.size(); i++)
+ if (it->data[i] != RTLIL::State::Sx && it->data[i] != RTLIL::State::Sz)
return false;
}
return true;
@@ -1496,10 +2752,13 @@ bool RTLIL::SigSpec::is_fully_undef() const
bool RTLIL::SigSpec::has_marked_bits() const
{
- for (auto it = chunks.begin(); it != chunks.end(); it++)
+ cover("kernel.rtlil.sigspec.has_marked_bits");
+
+ pack();
+ for (auto it = chunks_.begin(); it != chunks_.end(); it++)
if (it->width > 0 && it->wire == NULL) {
- for (size_t i = 0; i < it->data.bits.size(); i++)
- if (it->data.bits[i] == RTLIL::State::Sm)
+ for (size_t i = 0; i < it->data.size(); i++)
+ if (it->data[i] == RTLIL::State::Sm)
return true;
}
return false;
@@ -1507,52 +2766,79 @@ bool RTLIL::SigSpec::has_marked_bits() const
bool RTLIL::SigSpec::as_bool() const
{
- assert(is_fully_const());
- SigSpec sig = *this;
- sig.optimize();
- if (sig.width)
- return sig.chunks[0].data.as_bool();
+ cover("kernel.rtlil.sigspec.as_bool");
+
+ pack();
+ log_assert(is_fully_const() && SIZE(chunks_) <= 1);
+ if (width_)
+ return RTLIL::Const(chunks_[0].data).as_bool();
return false;
}
-int RTLIL::SigSpec::as_int() const
+int RTLIL::SigSpec::as_int(bool is_signed) const
{
- assert(is_fully_const());
- SigSpec sig = *this;
- sig.optimize();
- if (sig.width)
- return sig.chunks[0].data.as_int();
+ cover("kernel.rtlil.sigspec.as_int");
+
+ pack();
+ log_assert(is_fully_const() && SIZE(chunks_) <= 1);
+ if (width_)
+ return RTLIL::Const(chunks_[0].data).as_int(is_signed);
return 0;
}
std::string RTLIL::SigSpec::as_string() const
{
+ cover("kernel.rtlil.sigspec.as_string");
+
+ pack();
std::string str;
- for (size_t i = chunks.size(); i > 0; i--) {
- const RTLIL::SigChunk &chunk = chunks[i-1];
+ for (size_t i = chunks_.size(); i > 0; i--) {
+ const RTLIL::SigChunk &chunk = chunks_[i-1];
if (chunk.wire != NULL)
for (int j = 0; j < chunk.width; j++)
str += "?";
else
- str += chunk.data.as_string();
+ str += RTLIL::Const(chunk.data).as_string();
}
return str;
}
RTLIL::Const RTLIL::SigSpec::as_const() const
{
- assert(is_fully_const());
- SigSpec sig = *this;
- sig.optimize();
- if (sig.width)
- return sig.chunks[0].data;
+ cover("kernel.rtlil.sigspec.as_const");
+
+ pack();
+ log_assert(is_fully_const() && SIZE(chunks_) <= 1);
+ if (width_)
+ return chunks_[0].data;
return RTLIL::Const();
}
+RTLIL::Wire *RTLIL::SigSpec::as_wire() const
+{
+ cover("kernel.rtlil.sigspec.as_wire");
+
+ pack();
+ log_assert(is_wire());
+ return chunks_[0].wire;
+}
+
+RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const
+{
+ cover("kernel.rtlil.sigspec.as_chunk");
+
+ pack();
+ log_assert(is_chunk());
+ return chunks_[0];
+}
+
bool RTLIL::SigSpec::match(std::string pattern) const
{
+ cover("kernel.rtlil.sigspec.match");
+
+ pack();
std::string str = as_string();
- assert(pattern.size() == str.size());
+ log_assert(pattern.size() == str.size());
for (size_t i = 0; i < pattern.size(); i++) {
if (pattern[i] == ' ')
@@ -1571,8 +2857,11 @@ bool RTLIL::SigSpec::match(std::string pattern) const
std::set<RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_set() const
{
+ cover("kernel.rtlil.sigspec.to_sigbit_set");
+
+ pack();
std::set<RTLIL::SigBit> sigbits;
- for (auto &c : chunks)
+ for (auto &c : chunks_)
for (int i = 0; i < c.width; i++)
sigbits.insert(RTLIL::SigBit(c, i));
return sigbits;
@@ -1580,18 +2869,35 @@ std::set<RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_set() const
std::vector<RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_vector() const
{
- std::vector<RTLIL::SigBit> sigbits;
- sigbits.reserve(width);
- for (auto &c : chunks)
- for (int i = 0; i < c.width; i++)
- sigbits.push_back(RTLIL::SigBit(c, i));
- return sigbits;
+ cover("kernel.rtlil.sigspec.to_sigbit_vector");
+
+ unpack();
+ return bits_;
+}
+
+std::map<RTLIL::SigBit, RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_map(const RTLIL::SigSpec &other) const
+{
+ cover("kernel.rtlil.sigspec.to_sigbit_map");
+
+ unpack();
+ other.unpack();
+
+ log_assert(width_ == other.width_);
+
+ std::map<RTLIL::SigBit, RTLIL::SigBit> new_map;
+ for (int i = 0; i < width_; i++)
+ new_map[bits_[i]] = other.bits_[i];
+
+ return new_map;
}
RTLIL::SigBit RTLIL::SigSpec::to_single_sigbit() const
{
- log_assert(width == 1);
- for (auto &c : chunks)
+ cover("kernel.rtlil.sigspec.to_single_sigbit");
+
+ pack();
+ log_assert(width_ == 1);
+ for (auto &c : chunks_)
if (c.width)
return RTLIL::SigBit(c);
log_abort();
@@ -1614,6 +2920,8 @@ static int sigspec_parse_get_dummy_line_num()
bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str)
{
+ cover("kernel.rtlil.sigspec.parse");
+
std::vector<std::string> tokens;
sigspec_parse_split(tokens, str, ',');
@@ -1627,6 +2935,7 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri
continue;
if ('0' <= netname[0] && netname[0] <= '9') {
+ cover("kernel.rtlil.sigspec.parse.const");
AST::get_line_num = sigspec_parse_get_dummy_line_num;
AST::AstNode *ast = VERILOG_FRONTEND::const2ast(netname);
if (ast == NULL)
@@ -1639,10 +2948,12 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri
if (module == NULL)
return false;
+ cover("kernel.rtlil.sigspec.parse.net");
+
if (netname[0] != '$' && netname[0] != '\\')
netname = "\\" + netname;
- if (module->wires.count(netname) == 0) {
+ if (module->wires_.count(netname) == 0) {
size_t indices_pos = netname.size()-1;
if (indices_pos > 2 && netname[indices_pos] == ']')
{
@@ -1659,23 +2970,25 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri
}
}
- if (module->wires.count(netname) == 0)
+ if (module->wires_.count(netname) == 0)
return false;
- RTLIL::Wire *wire = module->wires.at(netname);
+ RTLIL::Wire *wire = module->wires_.at(netname);
if (!indices.empty()) {
std::vector<std::string> index_tokens;
sigspec_parse_split(index_tokens, indices.substr(1, indices.size()-2), ':');
- if (index_tokens.size() == 1)
- sig.append(RTLIL::SigSpec(wire, 1, atoi(index_tokens.at(0).c_str())));
- else {
+ if (index_tokens.size() == 1) {
+ cover("kernel.rtlil.sigspec.parse.bit_sel");
+ sig.append(RTLIL::SigSpec(wire, atoi(index_tokens.at(0).c_str())));
+ } else {
+ cover("kernel.rtlil.sigspec.parse.part_sel");
int a = atoi(index_tokens.at(0).c_str());
int b = atoi(index_tokens.at(1).c_str());
if (a > b) {
int tmp = a;
a = b, b = tmp;
}
- sig.append(RTLIL::SigSpec(wire, b-a+1, a));
+ sig.append(RTLIL::SigSpec(wire, a, b-a+1));
}
} else
sig.append(wire);
@@ -1689,13 +3002,15 @@ bool RTLIL::SigSpec::parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL
if (str.empty() || str[0] != '@')
return parse(sig, module, str);
+ cover("kernel.rtlil.sigspec.parse.sel");
+
str = RTLIL::escape_id(str.substr(1));
if (design->selection_vars.count(str) == 0)
return false;
sig = RTLIL::SigSpec();
RTLIL::Selection &sel = design->selection_vars.at(str);
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (sel.selected_member(module->name, it.first))
sig.append(it.second);
@@ -1705,20 +3020,23 @@ bool RTLIL::SigSpec::parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL
bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str)
{
if (str == "0") {
- sig = RTLIL::SigSpec(RTLIL::State::S0, lhs.width);
+ cover("kernel.rtlil.sigspec.parse.rhs_zeros");
+ sig = RTLIL::SigSpec(RTLIL::State::S0, lhs.width_);
return true;
}
if (str == "~0") {
- sig = RTLIL::SigSpec(RTLIL::State::S1, lhs.width);
+ cover("kernel.rtlil.sigspec.parse.rhs_ones");
+ sig = RTLIL::SigSpec(RTLIL::State::S1, lhs.width_);
return true;
}
- if (lhs.chunks.size() == 1) {
+ if (lhs.chunks_.size() == 1) {
char *p = (char*)str.c_str(), *endptr;
long long int val = strtoll(p, &endptr, 10);
if (endptr && endptr != p && *endptr == 0) {
- sig = RTLIL::SigSpec(val, lhs.width);
+ sig = RTLIL::SigSpec(val, lhs.width_);
+ cover("kernel.rtlil.sigspec.parse.rhs_dec");
return true;
}
}
@@ -1732,18 +3050,6 @@ RTLIL::CaseRule::~CaseRule()
delete *it;
}
-void RTLIL::CaseRule::optimize()
-{
- for (auto it : switches)
- it->optimize();
- for (auto &it : compare)
- it.optimize();
- for (auto &it : actions) {
- it.first.optimize();
- it.second.optimize();
- }
-}
-
RTLIL::CaseRule *RTLIL::CaseRule::clone() const
{
RTLIL::CaseRule *new_caserule = new RTLIL::CaseRule;
@@ -1760,13 +3066,6 @@ RTLIL::SwitchRule::~SwitchRule()
delete *it;
}
-void RTLIL::SwitchRule::optimize()
-{
- signal.optimize();
- for (auto it : cases)
- it->optimize();
-}
-
RTLIL::SwitchRule *RTLIL::SwitchRule::clone() const
{
RTLIL::SwitchRule *new_switchrule = new RTLIL::SwitchRule;
@@ -1778,15 +3077,6 @@ RTLIL::SwitchRule *RTLIL::SwitchRule::clone() const
}
-void RTLIL::SyncRule::optimize()
-{
- signal.optimize();
- for (auto &it : actions) {
- it.first.optimize();
- it.second.optimize();
- }
-}
-
RTLIL::SyncRule *RTLIL::SyncRule::clone() const
{
RTLIL::SyncRule *new_syncrule = new RTLIL::SyncRule;
@@ -1802,13 +3092,6 @@ RTLIL::Process::~Process()
delete *it;
}
-void RTLIL::Process::optimize()
-{
- root_case.optimize();
- for (auto it : syncs)
- it->optimize();
-}
-
RTLIL::Process *RTLIL::Process::clone() const
{
RTLIL::Process *new_proc = new RTLIL::Process;
@@ -1827,3 +3110,5 @@ RTLIL::Process *RTLIL::Process::clone() const
return new_proc;
}
+YOSYS_NAMESPACE_END
+
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index caadf198..a0ae8f08 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -17,20 +17,16 @@
*
*/
+#include "kernel/yosys.h"
+
#ifndef RTLIL_H
#define RTLIL_H
-#include <map>
-#include <set>
-#include <vector>
-#include <string>
-#include <assert.h>
-
-std::string stringf(const char *fmt, ...);
+YOSYS_NAMESPACE_BEGIN
namespace RTLIL
{
- enum State {
+ enum State : unsigned char {
S0 = 0,
S1 = 1,
Sx = 2, // undefined value or conflict
@@ -39,7 +35,7 @@ namespace RTLIL
Sm = 5 // marker (used internally by some passes)
};
- enum SyncType {
+ enum SyncType : unsigned char {
ST0 = 0, // level sensitive: 0
ST1 = 1, // level sensitive: 1
STp = 2, // edge sensitive: posedge
@@ -49,17 +45,16 @@ namespace RTLIL
STi = 6 // init
};
- enum ConstFlags {
+ enum ConstFlags : unsigned char {
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
};
- extern int autoidx;
-
struct Const;
struct Selection;
+ struct Monitor;
struct Design;
struct Module;
struct Wire;
@@ -67,6 +62,8 @@ namespace RTLIL
struct Cell;
struct SigChunk;
struct SigBit;
+ struct SigSpecIterator;
+ struct SigSpecConstIterator;
struct SigSpec;
struct CaseRule;
struct SwitchRule;
@@ -75,79 +72,207 @@ namespace RTLIL
typedef std::pair<SigSpec, SigSpec> SigSig;
-#ifdef NDEBUG
- typedef std::string IdString;
-#else
- struct IdString : public std::string {
- IdString() { }
- IdString(std::string str) : std::string(str) {
- check();
+ struct IdString
+ {
+ // the global id string cache
+
+ struct char_ptr_cmp {
+ bool operator()(const char *a, const char *b) const {
+ for (int i = 0; a[i] || b[i]; i++)
+ if (a[i] != b[i])
+ return a[i] < b[i];
+ return false;
+ }
+ };
+
+ static std::vector<int> global_refcount_storage_;
+ static std::vector<char*> global_id_storage_;
+ static std::map<char*, int, char_ptr_cmp> global_id_index_;
+ static std::vector<int> global_free_idx_list_;
+
+ static inline int get_reference(int idx)
+ {
+ global_refcount_storage_.at(idx)++;
+ return idx;
}
- IdString(const char *s) : std::string(s) {
- check();
+
+ static inline int get_reference(const char *p)
+ {
+ if (p[0]) {
+ log_assert(p[1] != 0);
+ log_assert(p[0] == '$' || p[0] == '\\');
+ }
+
+ auto it = global_id_index_.find((char*)p);
+ if (it != global_id_index_.end()) {
+ global_refcount_storage_.at(it->second)++;
+ return it->second;
+ }
+
+ if (global_free_idx_list_.empty()) {
+ log_assert(global_id_storage_.size() < 0x40000000);
+ global_free_idx_list_.push_back(global_id_storage_.size());
+ global_id_storage_.push_back(nullptr);
+ global_refcount_storage_.push_back(0);
+ }
+
+ int idx = global_free_idx_list_.back();
+ global_free_idx_list_.pop_back();
+ global_id_storage_.at(idx) = strdup(p);
+ global_id_index_[global_id_storage_.at(idx)] = idx;
+ global_refcount_storage_.at(idx)++;
+ return idx;
}
- IdString &operator=(const std::string &str) {
- std::string::operator=(str);
- check();
- return *this;
+
+ static inline void put_reference(int idx)
+ {
+ log_assert(global_refcount_storage_.at(idx) > 0);
+
+ if (--global_refcount_storage_.at(idx) != 0)
+ return;
+
+ global_id_index_.erase(global_id_storage_.at(idx));
+ free(global_id_storage_.at(idx));
+ global_id_storage_.at(idx) = nullptr;
+ global_free_idx_list_.push_back(idx);
}
- IdString &operator=(const char *s) {
- std::string::operator=(s);
- check();
- return *this;
+
+ // the actual IdString object is just is a single int
+
+ int index_;
+
+ IdString() : index_(get_reference("")) { }
+ IdString(const char *str) : index_(get_reference(str)) { }
+ IdString(const IdString &str) : index_(get_reference(str.index_)) { }
+ IdString(const std::string &str) : index_(get_reference(str.c_str())) { }
+ ~IdString() { put_reference(index_); }
+
+ void operator=(const IdString &rhs) {
+ put_reference(index_);
+ index_ = get_reference(rhs.index_);
+ }
+
+ void operator=(const char *rhs) {
+ IdString id(rhs);
+ *this = id;
+ }
+
+ void operator=(const std::string &rhs) {
+ IdString id(rhs);
+ *this = id;
+ }
+
+ const char *c_str() const {
+ return global_id_storage_.at(index_);
}
- bool operator<(const IdString &rhs) {
- check(), rhs.check();
- return std::string(*this) < std::string(rhs);
+
+ std::string str() const {
+ return std::string(global_id_storage_.at(index_));
}
- void check() const {
- assert(empty() || (size() >= 2 && (at(0) == '$' || at(0) == '\\')));
+
+ bool operator<(IdString rhs) const {
+ return index_ < rhs.index_;
}
+
+ bool operator==(IdString rhs) const { return index_ == rhs.index_; }
+ bool operator!=(IdString rhs) const { return index_ != rhs.index_; }
+
+ // The methods below are just convinience functions for better compatibility with std::string.
+
+ bool operator==(const std::string &rhs) const { return str() == rhs; }
+ bool operator!=(const std::string &rhs) const { return str() != rhs; }
+
+ bool operator==(const char *rhs) const { return strcmp(c_str(), rhs) == 0; }
+ bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; }
+
+ char operator[](size_t i) const {
+ const char *p = c_str();
+ for (; i != 0; i--, p++)
+ log_assert(*p != 0);
+ return *p;
+ }
+
+ std::string substr(size_t pos = 0, size_t len = std::string::npos) const {
+ if (len == std::string::npos || len >= strlen(c_str() + pos))
+ return std::string(c_str() + pos);
+ else
+ return std::string(c_str() + pos, len);
+ }
+
+ size_t size() const {
+ return str().size();
+ }
+
+ bool empty() const {
+ return c_str()[0] == 0;
+ }
+
+ void clear() {
+ *this = IdString();
+ }
+
+ // The following is a helper key_compare class. Instead of for example std::set<Cell*>
+ // use std::set<Cell*, IdString::compare_ptr_by_name<Cell>> if the order of cells in the
+ // set has an influence on the algorithm.
+
+ template<typename T> struct compare_ptr_by_name {
+ bool operator()(const T *a, const T *b) {
+ return (a == nullptr || b == nullptr) ? (a < b) : (a->name < b->name);
+ }
+ };
+
+ // often one needs to check if a given IdString is part of a list (for example a list
+ // of cell types). the following functions helps with that.
+
+ template<typename T, typename... Args>
+ bool in(T first, Args... rest) {
+ return in(first) || in(rest...);
+ }
+
+ bool in(IdString rhs) { return *this == rhs; }
+ bool in(const char *rhs) { return *this == rhs; }
+ bool in(const std::string &rhs) { return *this == rhs; }
+ bool in(const std::set<IdString> &rhs) { return rhs.count(*this) != 0; }
};
-#endif
- static IdString escape_id(std::string str) __attribute__((unused));
- static IdString escape_id(std::string str) {
+ static inline std::string escape_id(std::string str) {
if (str.size() > 0 && str[0] != '\\' && str[0] != '$')
return "\\" + str;
return str;
}
- static std::string unescape_id(std::string str) __attribute__((unused));
- static std::string unescape_id(std::string str) {
+ static inline std::string unescape_id(std::string str) {
if (str.size() > 1 && str[0] == '\\' && str[1] != '$')
return str.substr(1);
return str;
}
- static const char *id2cstr(std::string str) __attribute__((unused));
- static const char *id2cstr(std::string str) {
- if (str.size() > 1 && str[0] == '\\' && str[1] != '$')
- return str.c_str() + 1;
- return str.c_str();
+ static inline std::string unescape_id(RTLIL::IdString str) {
+ return unescape_id(str.str());
}
- static IdString new_id(std::string file, int line, std::string func) __attribute__((unused));
- static IdString new_id(std::string file, int line, std::string func) {
- std::string str = "$auto$";
- size_t pos = file.find_last_of('/');
- str += pos != std::string::npos ? file.substr(pos+1) : file;
- str += stringf(":%d:%s$%d", line, func.c_str(), autoidx++);
- return str;
+ static inline const char *id2cstr(const RTLIL::IdString &str) {
+ return log_id(str);
}
-#define NEW_ID \
- RTLIL::new_id(__FILE__, __LINE__, __FUNCTION__)
-
-#define NEW_WIRE(_mod, _width) \
- (_mod)->new_wire(_width, NEW_ID)
-
- template <typename T> struct sort_by_name {
+ template <typename T> struct sort_by_name_id {
bool operator()(T *a, T *b) const {
return a->name < b->name;
}
};
+ template <typename T> struct sort_by_name_str {
+ bool operator()(T *a, T *b) const {
+ return strcmp(a->name.c_str(), b->name.c_str()) < 0;
+ }
+ };
+
+ struct sort_by_id_str {
+ bool operator()(RTLIL::IdString a, RTLIL::IdString b) const {
+ return strcmp(a.c_str(), b.c_str()) < 0;
+ }
+ };
+
// see calc.cc for the implementation of this functions
RTLIL::Const const_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
@@ -169,6 +294,8 @@ namespace RTLIL
RTLIL::Const const_shr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_sshl (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_sshr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_shift (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_shiftx (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_lt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_le (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
@@ -187,77 +314,245 @@ namespace RTLIL
RTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
- RTLIL::Const const_bu0 (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+
+
+ // This iterator-range-pair is used for Design::modules(), Module::wires() and Module::cells().
+ // It maintains a reference counter that is used to make sure that the container is not modified while being iterated over.
+
+ template<typename T>
+ struct ObjIterator
+ {
+ typename std::map<RTLIL::IdString, T>::iterator it;
+ std::map<RTLIL::IdString, T> *list_p;
+ int *refcount_p;
+
+ ObjIterator() : list_p(nullptr), refcount_p(nullptr) {
+ }
+
+ ObjIterator(decltype(list_p) list_p, int *refcount_p) : list_p(list_p), refcount_p(refcount_p) {
+ if (list_p->empty()) {
+ this->list_p = nullptr;
+ this->refcount_p = nullptr;
+ } else {
+ it = list_p->begin();
+ (*refcount_p)++;
+ }
+ }
+
+ ObjIterator(const RTLIL::ObjIterator<T> &other) {
+ it = other.it;
+ list_p = other.list_p;
+ refcount_p = other.refcount_p;
+ if (refcount_p)
+ (*refcount_p)++;
+ }
+
+ ObjIterator &operator=(const RTLIL::ObjIterator<T> &other) {
+ if (refcount_p)
+ (*refcount_p)--;
+ it = other.it;
+ list_p = other.list_p;
+ refcount_p = other.refcount_p;
+ if (refcount_p)
+ (*refcount_p)++;
+ return *this;
+ }
+
+ ~ObjIterator() {
+ if (refcount_p)
+ (*refcount_p)--;
+ }
+
+ inline T operator*() const {
+ log_assert(list_p != nullptr);
+ return it->second;
+ }
+
+ inline bool operator!=(const RTLIL::ObjIterator<T> &other) const {
+ if (list_p == nullptr || other.list_p == nullptr)
+ return list_p != other.list_p;
+ return it != other.it;
+ }
+
+ inline void operator++() {
+ log_assert(list_p != nullptr);
+ if (++it == list_p->end()) {
+ (*refcount_p)--;
+ list_p = nullptr;
+ refcount_p = nullptr;
+ }
+ }
+ };
+
+ template<typename T>
+ struct ObjRange
+ {
+ std::map<RTLIL::IdString, T> *list_p;
+ int *refcount_p;
+
+ ObjRange(decltype(list_p) list_p, int *refcount_p) : list_p(list_p), refcount_p(refcount_p) { }
+ RTLIL::ObjIterator<T> begin() { return RTLIL::ObjIterator<T>(list_p, refcount_p); }
+ RTLIL::ObjIterator<T> end() { return RTLIL::ObjIterator<T>(); }
+
+ size_t size() const {
+ return list_p->size();
+ }
+
+ operator std::set<T>() const {
+ std::set<T> result;
+ for (auto &it : *list_p)
+ result.insert(it.second);
+ return result;
+ }
+
+ operator std::vector<T>() const {
+ std::vector<T> result;
+ result.reserve(list_p->size());
+ for (auto &it : *list_p)
+ result.push_back(it.second);
+ return result;
+ }
+
+ std::set<T> to_set() const { return *this; }
+ std::vector<T> to_vector() const { return *this; }
+ };
};
-struct RTLIL::Const {
+struct RTLIL::Const
+{
int flags;
std::vector<RTLIL::State> bits;
+
Const();
Const(std::string str);
Const(int val, int width = 32);
Const(RTLIL::State bit, int width = 1);
- Const(std::vector<RTLIL::State> bits) : bits(bits) { flags = CONST_FLAG_NONE; };
+ Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; };
+ Const(const std::vector<bool> &bits);
+
bool operator <(const RTLIL::Const &other) const;
bool operator ==(const RTLIL::Const &other) const;
bool operator !=(const RTLIL::Const &other) const;
+
bool as_bool() const;
- int as_int() const;
+ int as_int(bool is_signed = false) const;
std::string as_string() const;
+
std::string decode_string() const;
+
+ inline int size() const { return bits.size(); }
};
-struct RTLIL::Selection {
+struct RTLIL::Selection
+{
bool full_selection;
std::set<RTLIL::IdString> selected_modules;
std::map<RTLIL::IdString, std::set<RTLIL::IdString>> selected_members;
+
Selection(bool full = true) : full_selection(full) { }
+
bool selected_module(RTLIL::IdString mod_name) const;
bool selected_whole_module(RTLIL::IdString mod_name) const;
bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const;
void optimize(RTLIL::Design *design);
+
template<typename T1> void select(T1 *module) {
if (!full_selection && selected_modules.count(module->name) == 0) {
selected_modules.insert(module->name);
selected_members.erase(module->name);
}
}
+
template<typename T1, typename T2> void select(T1 *module, T2 *member) {
if (!full_selection && selected_modules.count(module->name) == 0)
selected_members[module->name].insert(member->name);
}
+
bool empty() const {
return !full_selection && selected_modules.empty() && selected_members.empty();
}
};
-struct RTLIL::Design {
- std::map<RTLIL::IdString, RTLIL::Module*> modules;
+struct RTLIL::Monitor
+{
+ virtual ~Monitor() { }
+ virtual void notify_module_add(RTLIL::Module*) { }
+ virtual void notify_module_del(RTLIL::Module*) { }
+ virtual void notify_connect(RTLIL::Cell*, const RTLIL::IdString&, const RTLIL::SigSpec&, RTLIL::SigSpec&) { }
+ virtual void notify_connect(RTLIL::Module*, const RTLIL::SigSig&) { }
+ virtual void notify_connect(RTLIL::Module*, const std::vector<RTLIL::SigSig>&) { }
+ virtual void notify_blackout(RTLIL::Module*) { }
+};
+
+struct RTLIL::Design
+{
+ std::set<RTLIL::Monitor*> monitors;
+ std::map<std::string, std::string> scratchpad;
+
+ int refcount_modules_;
+ std::map<RTLIL::IdString, RTLIL::Module*> modules_;
+
std::vector<RTLIL::Selection> selection_stack;
std::map<RTLIL::IdString, RTLIL::Selection> selection_vars;
std::string selected_active_module;
+
+ Design();
~Design();
+
+ RTLIL::ObjRange<RTLIL::Module*> modules();
+ RTLIL::Module *module(RTLIL::IdString name);
+
+ bool has(RTLIL::IdString id) const {
+ return modules_.count(id) != 0;
+ }
+
+ void add(RTLIL::Module *module);
+ RTLIL::Module *addModule(RTLIL::IdString name);
+ void remove(RTLIL::Module *module);
+
+ void scratchpad_unset(std::string varname);
+
+ void scratchpad_set_int(std::string varname, int value);
+ void scratchpad_set_bool(std::string varname, bool value);
+ void scratchpad_set_string(std::string varname, std::string value);
+
+ int scratchpad_get_int(std::string varname, int default_value = 0) const;
+ bool scratchpad_get_bool(std::string varname, bool default_value = false) const;
+ std::string scratchpad_get_string(std::string varname, std::string default_value = std::string()) const;
+
void check();
void optimize();
+
bool selected_module(RTLIL::IdString mod_name) const;
bool selected_whole_module(RTLIL::IdString mod_name) const;
bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const;
+
+ bool selected_module(RTLIL::Module *mod) const;
+ bool selected_whole_module(RTLIL::Module *mod) const;
+
bool full_selection() const {
return selection_stack.back().full_selection;
}
+
template<typename T1> bool selected(T1 *module) const {
return selected_module(module->name);
}
+
template<typename T1, typename T2> bool selected(T1 *module, T2 *member) const {
return selected_member(module->name, member->name);
}
+
template<typename T1, typename T2> void select(T1 *module, T2 *member) {
if (selection_stack.size() > 0) {
RTLIL::Selection &sel = selection_stack.back();
sel.select(module, member);
}
}
+
+ std::vector<RTLIL::Module*> selected_modules() const;
+ std::vector<RTLIL::Module*> selected_whole_modules() const;
+ std::vector<RTLIL::Module*> selected_whole_modules_warn() const;
};
#define RTLIL_ATTRIBUTE_MEMBERS \
@@ -271,159 +566,536 @@ struct RTLIL::Design {
return attributes.at(id).as_bool(); \
}
-struct RTLIL::Module {
+struct RTLIL::Module
+{
+protected:
+ void add(RTLIL::Wire *wire);
+ void add(RTLIL::Cell *cell);
+
+public:
+ RTLIL::Design *design;
+ std::set<RTLIL::Monitor*> monitors;
+
+ int refcount_wires_;
+ int refcount_cells_;
+
+ std::map<RTLIL::IdString, RTLIL::Wire*> wires_;
+ std::map<RTLIL::IdString, RTLIL::Cell*> cells_;
+ std::vector<RTLIL::SigSig> connections_;
+
RTLIL::IdString name;
std::set<RTLIL::IdString> avail_parameters;
- std::map<RTLIL::IdString, RTLIL::Wire*> wires;
std::map<RTLIL::IdString, RTLIL::Memory*> memories;
- std::map<RTLIL::IdString, RTLIL::Cell*> cells;
std::map<RTLIL::IdString, RTLIL::Process*> processes;
- std::vector<RTLIL::SigSig> connections;
RTLIL_ATTRIBUTE_MEMBERS
+
+ Module();
virtual ~Module();
virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
virtual size_t count_id(RTLIL::IdString id);
virtual void check();
virtual void optimize();
- RTLIL::Wire *new_wire(int width, RTLIL::IdString name);
- void add(RTLIL::Wire *wire);
- void add(RTLIL::Cell *cell);
+
+ void connect(const RTLIL::SigSig &conn);
+ void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs);
+ void new_connections(const std::vector<RTLIL::SigSig> &new_conn);
+ const std::vector<RTLIL::SigSig> &connections() const;
+
+ std::vector<RTLIL::IdString> ports;
void fixup_ports();
template<typename T> void rewrite_sigspecs(T functor);
void cloneInto(RTLIL::Module *new_mod) const;
virtual RTLIL::Module *clone() const;
+ bool has_memories() const;
+ bool has_processes() const;
+
+ bool has_memories_warn() const;
+ bool has_processes_warn() const;
+
+ std::vector<RTLIL::Wire*> selected_wires() const;
+ std::vector<RTLIL::Cell*> selected_cells() const;
+
+ template<typename T> bool selected(T *member) const {
+ return design->selected_member(name, member->name);
+ }
+
+ RTLIL::Wire* wire(RTLIL::IdString id) { return wires_.count(id) ? wires_.at(id) : nullptr; }
+ RTLIL::Cell* cell(RTLIL::IdString id) { return cells_.count(id) ? cells_.at(id) : nullptr; }
+
+ RTLIL::ObjRange<RTLIL::Wire*> wires() { return RTLIL::ObjRange<RTLIL::Wire*>(&wires_, &refcount_wires_); }
+ RTLIL::ObjRange<RTLIL::Cell*> cells() { return RTLIL::ObjRange<RTLIL::Cell*>(&cells_, &refcount_cells_); }
+
+ // Removing wires is expensive. If you have to remove wires, remove them all at once.
+ void remove(const std::set<RTLIL::Wire*> &wires);
+ void remove(RTLIL::Cell *cell);
+
+ void rename(RTLIL::Wire *wire, RTLIL::IdString new_name);
+ void rename(RTLIL::Cell *cell, RTLIL::IdString new_name);
+ void rename(RTLIL::IdString old_name, RTLIL::IdString new_name);
+
+ void swap_names(RTLIL::Wire *w1, RTLIL::Wire *w2);
+ void swap_names(RTLIL::Cell *c1, RTLIL::Cell *c2);
+
+ RTLIL::IdString uniquify(RTLIL::IdString name);
+ RTLIL::IdString uniquify(RTLIL::IdString name, int &index);
+
+ RTLIL::Wire *addWire(RTLIL::IdString name, int width = 1);
+ RTLIL::Wire *addWire(RTLIL::IdString name, const RTLIL::Wire *other);
+
+ RTLIL::Cell *addCell(RTLIL::IdString name, RTLIL::IdString type);
+ RTLIL::Cell *addCell(RTLIL::IdString name, const RTLIL::Cell *other);
+
+ // The add* methods create a cell and return the created cell. All signals must exist in advance.
+
+ RTLIL::Cell* addNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addPos (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addNeg (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
+
+ RTLIL::Cell* addAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+
+ RTLIL::Cell* addReduceAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addReduceOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addReduceXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addReduceXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addReduceBool (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
+
+ RTLIL::Cell* addShl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addShr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addSshl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addSshr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addShift (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addShiftx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+
+ RTLIL::Cell* addLt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addLe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addEq (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addNe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addEqx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addNex (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addGe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addGt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+
+ RTLIL::Cell* addAdd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addSub (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addMul (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addDiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addMod (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addPow (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool a_signed = false, bool b_signed = false);
+
+ RTLIL::Cell* addLogicNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addLogicAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+ RTLIL::Cell* addLogicOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
+
+ RTLIL::Cell* addMux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y);
+ RTLIL::Cell* addPmux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y);
+
+ RTLIL::Cell* addSlice (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const offset);
+ RTLIL::Cell* addConcat (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y);
+ RTLIL::Cell* addLut (RTLIL::IdString name, RTLIL::SigSpec sig_i, RTLIL::SigSpec sig_o, RTLIL::Const lut);
+ RTLIL::Cell* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en);
+
+ RTLIL::Cell* addSr (RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity = true, bool clr_polarity = true);
+ RTLIL::Cell* addDff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true);
+ RTLIL::Cell* addDffsr (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
+ RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true);
+ RTLIL::Cell* addAdff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
+ RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true);
+ RTLIL::Cell* addDlatch (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true);
+ RTLIL::Cell* addDlatchsr (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
+ RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true);
+
+ RTLIL::Cell* addNotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y);
+ RTLIL::Cell* addAndGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+ RTLIL::Cell* addNandGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+ RTLIL::Cell* addOrGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+ RTLIL::Cell* addNorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+ RTLIL::Cell* addXorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+ RTLIL::Cell* addXnorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+ RTLIL::Cell* addMuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y);
+ RTLIL::Cell* addAoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y);
+ RTLIL::Cell* addOai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y);
+ RTLIL::Cell* addAoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y);
+ RTLIL::Cell* addOai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y);
+
+ RTLIL::Cell* addDffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true);
+ RTLIL::Cell* addDffsrGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
+ RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true);
+ RTLIL::Cell* addAdffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
+ bool arst_value = false, bool clk_polarity = true, bool arst_polarity = true);
+ RTLIL::Cell* addDlatchGate (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true);
+ RTLIL::Cell* addDlatchsrGate (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
+ RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true);
+
+ // The methods without the add* prefix create a cell and an output signal. They return the newly created output signal.
+
+ RTLIL::SigSpec Not (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
+ RTLIL::SigSpec Pos (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
+ RTLIL::SigSpec Bu0 (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
+ RTLIL::SigSpec Neg (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
+
+ RTLIL::SigSpec And (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Or (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Xor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Xnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+
+ RTLIL::SigSpec ReduceAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
+ RTLIL::SigSpec ReduceOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
+ RTLIL::SigSpec ReduceXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
+ RTLIL::SigSpec ReduceXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
+ RTLIL::SigSpec ReduceBool (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
+
+ RTLIL::SigSpec Shl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Shr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Sshl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Sshr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Shift (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Shiftx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+
+ RTLIL::SigSpec Lt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Le (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Eq (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Ne (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Eqx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Nex (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Ge (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Gt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+
+ RTLIL::SigSpec Add (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Sub (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Mul (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Div (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Mod (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec Pow (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool a_signed = false, bool b_signed = false);
+
+ RTLIL::SigSpec LogicNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
+ RTLIL::SigSpec LogicAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+ RTLIL::SigSpec LogicOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
+
+ RTLIL::SigSpec Mux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s);
+ RTLIL::SigSpec Pmux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s);
+
+ RTLIL::SigBit NotGate (RTLIL::IdString name, RTLIL::SigBit sig_a);
+ RTLIL::SigBit AndGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
+ RTLIL::SigBit NandGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
+ RTLIL::SigBit OrGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
+ RTLIL::SigBit NorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
+ RTLIL::SigBit XorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
+ RTLIL::SigBit XnorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
+ RTLIL::SigBit MuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s);
+ RTLIL::SigBit Aoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c);
+ RTLIL::SigBit Oai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c);
+ RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d);
+ RTLIL::SigBit Oai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d);
};
-struct RTLIL::Wire {
+struct RTLIL::Wire
+{
+protected:
+ // use module->addWire() and module->remove() to create or destroy wires
+ friend struct RTLIL::Module;
+ Wire();
+ ~Wire() { };
+
+public:
+ // do not simply copy wires
+ Wire(RTLIL::Wire &other) = delete;
+ void operator=(RTLIL::Wire &other) = delete;
+
+ RTLIL::Module *module;
RTLIL::IdString name;
int width, start_offset, port_id;
- bool port_input, port_output;
+ bool port_input, port_output, upto;
RTLIL_ATTRIBUTE_MEMBERS
- Wire();
};
-struct RTLIL::Memory {
+struct RTLIL::Memory
+{
+ Memory();
+
RTLIL::IdString name;
int width, start_offset, size;
RTLIL_ATTRIBUTE_MEMBERS
- Memory();
};
-struct RTLIL::Cell {
+struct RTLIL::Cell
+{
+protected:
+ // use module->addCell() and module->remove() to create or destroy cells
+ friend struct RTLIL::Module;
+ Cell();
+
+public:
+ // do not simply copy cells
+ Cell(RTLIL::Cell &other) = delete;
+ void operator=(RTLIL::Cell &other) = delete;
+
+ RTLIL::Module *module;
RTLIL::IdString name;
RTLIL::IdString type;
- std::map<RTLIL::IdString, RTLIL::SigSpec> connections;
+ std::map<RTLIL::IdString, RTLIL::SigSpec> connections_;
std::map<RTLIL::IdString, RTLIL::Const> parameters;
RTLIL_ATTRIBUTE_MEMBERS
- void optimize();
+
+ // access cell ports
+ bool hasPort(RTLIL::IdString portname) const;
+ void unsetPort(RTLIL::IdString portname);
+ void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal);
+ const RTLIL::SigSpec &getPort(RTLIL::IdString portname) const;
+ const std::map<RTLIL::IdString, RTLIL::SigSpec> &connections() const;
+
+ // access cell parameters
+ bool hasParam(RTLIL::IdString paramname) const;
+ void unsetParam(RTLIL::IdString paramname);
+ void setParam(RTLIL::IdString paramname, RTLIL::Const value);
+ const RTLIL::Const &getParam(RTLIL::IdString paramname) const;
+
+ void check();
+ void fixup_parameters(bool set_a_signed = false, bool set_b_signed = false);
template<typename T> void rewrite_sigspecs(T functor);
};
-struct RTLIL::SigChunk {
+struct RTLIL::SigChunk
+{
RTLIL::Wire *wire;
- RTLIL::Const data; // only used if wire == NULL, LSB at index 0
+ std::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0
int width, offset;
+
SigChunk();
- SigChunk(const RTLIL::Const &data);
- SigChunk(RTLIL::Wire *wire, int width, int offset);
+ SigChunk(const RTLIL::Const &value);
+ SigChunk(RTLIL::Wire *wire);
+ SigChunk(RTLIL::Wire *wire, int offset, int width = 1);
SigChunk(const std::string &str);
SigChunk(int val, int width = 32);
SigChunk(RTLIL::State bit, int width = 1);
SigChunk(RTLIL::SigBit bit);
+
RTLIL::SigChunk extract(int offset, int length) const;
+
bool operator <(const RTLIL::SigChunk &other) const;
bool operator ==(const RTLIL::SigChunk &other) const;
bool operator !=(const RTLIL::SigChunk &other) const;
- static bool compare(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b);
};
-struct RTLIL::SigBit {
+struct RTLIL::SigBit
+{
RTLIL::Wire *wire;
- RTLIL::State data;
- int offset;
- SigBit() : wire(NULL), data(RTLIL::State::S0), offset(0) { }
- SigBit(RTLIL::State bit) : wire(NULL), data(bit), offset(0) { }
- SigBit(RTLIL::Wire *wire) : wire(wire), data(RTLIL::State::S0), offset(0) { assert(!wire || wire->width == 1); }
- SigBit(RTLIL::Wire *wire, int offset) : wire(wire), data(RTLIL::State::S0), offset(offset) { }
- SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire), data(chunk.wire ? RTLIL::State::S0 : chunk.data.bits[0]), offset(chunk.offset) { assert(chunk.width == 1); }
- SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire), data(chunk.wire ? RTLIL::State::S0 : chunk.data.bits[index]), offset(chunk.wire ? chunk.offset + index : 0) { }
+ union {
+ RTLIL::State data; // used if wire == NULL
+ int offset; // used if wire != NULL
+ };
+
+ SigBit() : wire(NULL), data(RTLIL::State::S0) { }
+ SigBit(RTLIL::State bit) : wire(NULL), data(bit) { }
+ SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); }
+ SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire); }
+ SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; }
+ SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; }
SigBit(const RTLIL::SigSpec &sig);
+
bool operator <(const RTLIL::SigBit &other) const {
- return (wire != other.wire) ? (wire < other.wire) : wire ? (offset < other.offset) : (data < other.data);
+ if (wire == other.wire)
+ return wire ? (offset < other.offset) : (data < other.data);
+ if (wire != nullptr && other.wire != nullptr)
+ return wire->name < other.wire->name;
+ return wire < other.wire;
}
+
bool operator ==(const RTLIL::SigBit &other) const {
return (wire == other.wire) && (wire ? (offset == other.offset) : (data == other.data));
}
+
bool operator !=(const RTLIL::SigBit &other) const {
return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data));
}
};
-struct RTLIL::SigSpec {
- std::vector<RTLIL::SigChunk> chunks; // LSB at index 0
- int width;
+struct RTLIL::SigSpecIterator
+{
+ RTLIL::SigSpec *sig_p;
+ int index;
+
+ inline RTLIL::SigBit &operator*() const;
+ inline bool operator!=(const RTLIL::SigSpecIterator &other) const { return index != other.index; }
+ inline void operator++() { index++; }
+};
+
+struct RTLIL::SigSpecConstIterator
+{
+ const RTLIL::SigSpec *sig_p;
+ int index;
+
+ inline const RTLIL::SigBit &operator*() const;
+ inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; }
+ inline void operator++() { index++; }
+};
+
+struct RTLIL::SigSpec
+{
+private:
+ int width_;
+ unsigned long hash_;
+ std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0
+ std::vector<RTLIL::SigBit> bits_; // LSB at index 0
+
+ void pack() const;
+ void unpack() const;
+ void hash() const;
+
+ inline bool packed() const {
+ return bits_.empty();
+ }
+
+ inline void inline_unpack() const {
+ if (!chunks_.empty())
+ unpack();
+ }
+
+public:
SigSpec();
- SigSpec(const RTLIL::Const &data);
+ SigSpec(const RTLIL::SigSpec &other);
+ SigSpec(std::initializer_list<RTLIL::SigSpec> parts);
+ const RTLIL::SigSpec &operator=(const RTLIL::SigSpec &other);
+
+ SigSpec(const RTLIL::Const &value);
SigSpec(const RTLIL::SigChunk &chunk);
- SigSpec(RTLIL::Wire *wire, int width = -1, int offset = 0);
+ SigSpec(RTLIL::Wire *wire);
+ SigSpec(RTLIL::Wire *wire, int offset, int width = 1);
SigSpec(const std::string &str);
SigSpec(int val, int width = 32);
SigSpec(RTLIL::State bit, int width = 1);
SigSpec(RTLIL::SigBit bit, int width = 1);
+ SigSpec(std::vector<RTLIL::SigChunk> chunks);
SigSpec(std::vector<RTLIL::SigBit> bits);
- void expand();
- void optimize();
- RTLIL::SigSpec optimized() const;
+ SigSpec(std::set<RTLIL::SigBit> bits);
+
+ SigSpec(RTLIL::SigSpec &&other) {
+ width_ = other.width_;
+ hash_ = other.hash_;
+ chunks_ = std::move(other.chunks_);
+ bits_ = std::move(other.bits_);
+ }
+
+ const RTLIL::SigSpec &operator=(RTLIL::SigSpec &&other) {
+ width_ = other.width_;
+ hash_ = other.hash_;
+ chunks_ = std::move(other.chunks_);
+ bits_ = std::move(other.bits_);
+ return *this;
+ }
+
+ inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }
+ inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }
+
+ inline int size() const { return width_; }
+
+ inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); }
+ inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); }
+
+ inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; }
+ inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; }
+
+ inline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; }
+ inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; }
+
void sort();
void sort_and_unify();
+
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with);
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const;
+
+ void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules);
+ void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;
+
+ void replace(int offset, const RTLIL::SigSpec &with);
+
void remove(const RTLIL::SigSpec &pattern);
void remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const;
void remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other);
- RTLIL::SigSpec extract(RTLIL::SigSpec pattern, RTLIL::SigSpec *other = NULL) const;
- void replace(int offset, const RTLIL::SigSpec &with);
+
+ void remove(const std::set<RTLIL::SigBit> &pattern);
+ void remove(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const;
+ void remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);
+
+ void remove(int offset, int length = 1);
void remove_const();
- void remove(int offset, int length);
- RTLIL::SigSpec extract(int offset, int length) const;
+
+ RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;
+ RTLIL::SigSpec extract(const std::set<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;
+ RTLIL::SigSpec extract(int offset, int length = 1) const;
+
void append(const RTLIL::SigSpec &signal);
void append_bit(const RTLIL::SigBit &bit);
- bool combine(RTLIL::SigSpec signal, RTLIL::State freeState = RTLIL::State::Sz, bool override = false);
+
void extend(int width, bool is_signed = false);
void extend_u0(int width, bool is_signed = false);
- void check() const;
+
+ RTLIL::SigSpec repeat(int num) const;
+
bool operator <(const RTLIL::SigSpec &other) const;
bool operator ==(const RTLIL::SigSpec &other) const;
- bool operator !=(const RTLIL::SigSpec &other) const;
+ inline bool operator !=(const RTLIL::SigSpec &other) const { return !(*this == other); }
+
+ bool is_wire() const;
+ bool is_chunk() const;
+
bool is_fully_const() const;
bool is_fully_def() const;
bool is_fully_undef() const;
bool has_marked_bits() const;
+
bool as_bool() const;
- int as_int() const;
+ int as_int(bool is_signed = false) const;
std::string as_string() const;
RTLIL::Const as_const() const;
+ RTLIL::Wire *as_wire() const;
+ RTLIL::SigChunk as_chunk() const;
+
bool match(std::string pattern) const;
+
std::set<RTLIL::SigBit> to_sigbit_set() const;
std::vector<RTLIL::SigBit> to_sigbit_vector() const;
+ std::map<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_map(const RTLIL::SigSpec &other) const;
RTLIL::SigBit to_single_sigbit() const;
+
static bool parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str);
static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
+
+ operator std::vector<RTLIL::SigChunk>() const { return chunks(); }
+ operator std::vector<RTLIL::SigBit>() const { return bits(); }
+
+#ifndef NDEBUG
+ void check() const;
+#else
+ inline void check() const { }
+#endif
};
+inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
+ return (*sig_p)[index];
+}
+
+inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const {
+ return (*sig_p)[index];
+}
+
inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {
- assert(sig.width == 1 && sig.chunks.size() == 1);
- *this = SigBit(sig.chunks[0]);
+ log_assert(sig.size() == 1 && sig.chunks().size() == 1);
+ *this = SigBit(sig.chunks().front());
}
-struct RTLIL::CaseRule {
+struct RTLIL::CaseRule
+{
std::vector<RTLIL::SigSpec> compare;
std::vector<RTLIL::SigSig> actions;
std::vector<RTLIL::SwitchRule*> switches;
+
~CaseRule();
void optimize();
@@ -431,34 +1103,36 @@ struct RTLIL::CaseRule {
RTLIL::CaseRule *clone() const;
};
-struct RTLIL::SwitchRule {
+struct RTLIL::SwitchRule
+{
RTLIL::SigSpec signal;
RTLIL_ATTRIBUTE_MEMBERS
std::vector<RTLIL::CaseRule*> cases;
+
~SwitchRule();
- void optimize();
template<typename T> void rewrite_sigspecs(T functor);
RTLIL::SwitchRule *clone() const;
};
-struct RTLIL::SyncRule {
+struct RTLIL::SyncRule
+{
RTLIL::SyncType type;
RTLIL::SigSpec signal;
std::vector<RTLIL::SigSig> actions;
- void optimize();
template<typename T> void rewrite_sigspecs(T functor);
RTLIL::SyncRule *clone() const;
};
-struct RTLIL::Process {
+struct RTLIL::Process
+{
RTLIL::IdString name;
RTLIL_ATTRIBUTE_MEMBERS
RTLIL::CaseRule root_case;
std::vector<RTLIL::SyncRule*> syncs;
+
~Process();
- void optimize();
template<typename T> void rewrite_sigspecs(T functor);
RTLIL::Process *clone() const;
@@ -467,11 +1141,11 @@ struct RTLIL::Process {
template<typename T>
void RTLIL::Module::rewrite_sigspecs(T functor)
{
- for (auto &it : cells)
+ for (auto &it : cells_)
it.second->rewrite_sigspecs(functor);
for (auto &it : processes)
it.second->rewrite_sigspecs(functor);
- for (auto &it : connections) {
+ for (auto &it : connections_) {
functor(it.first);
functor(it.second);
}
@@ -479,7 +1153,7 @@ void RTLIL::Module::rewrite_sigspecs(T functor)
template<typename T>
void RTLIL::Cell::rewrite_sigspecs(T functor) {
- for (auto &it : connections)
+ for (auto &it : connections_)
functor(it.second);
}
@@ -521,4 +1195,6 @@ void RTLIL::Process::rewrite_sigspecs(T functor)
it->rewrite_sigspecs(functor);
}
+YOSYS_NAMESPACE_END
+
#endif
diff --git a/kernel/satgen.h b/kernel/satgen.h
index 840700cb..692c6e7f 100644
--- a/kernel/satgen.h
+++ b/kernel/satgen.h
@@ -23,14 +23,10 @@
#include "kernel/rtlil.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
+#include "kernel/macc.h"
-#ifdef YOSYS_ENABLE_MINISAT
-# include "libs/ezsat/ezminisat.h"
+#include "libs/ezsat/ezminisat.h"
typedef ezMiniSAT ezDefaultSAT;
-#else
-# include "libs/ezsat/ezsat.h"
-typedef ezSAT ezDefaultSAT;
-#endif
struct SatGen
{
@@ -57,21 +53,19 @@ struct SatGen
{
log_assert(!undef_mode || model_undef);
sigmap->apply(sig);
- sig.expand();
std::vector<int> vec;
- vec.reserve(sig.chunks.size());
+ vec.reserve(SIZE(sig));
- for (auto &c : sig.chunks)
- if (c.wire == NULL) {
- RTLIL::State bit = c.data.bits.at(0);
+ for (auto &bit : sig)
+ if (bit.wire == NULL) {
if (model_undef && dup_undef && bit == RTLIL::State::Sx)
- vec.push_back(ez->literal());
+ vec.push_back(ez->frozen_literal());
else
vec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->TRUE : ez->FALSE);
} else {
- std::string name = pf + stringf(c.wire->width == 1 ? "%s" : "%s [%d]", RTLIL::id2cstr(c.wire->name), c.offset);
- vec.push_back(ez->literal(name));
+ std::string name = pf + stringf(bit.wire->width == 1 ? "%s" : "%s [%d]", RTLIL::id2cstr(bit.wire->name), bit.offset);
+ vec.push_back(ez->frozen_literal(name));
}
return vec;
}
@@ -123,7 +117,7 @@ struct SatGen
if (timestep_rhs < 0)
timestep_rhs = timestep_lhs;
- assert(lhs.width == rhs.width);
+ log_assert(lhs.size() == rhs.size());
std::vector<int> vec_lhs = importSigSpec(lhs, timestep_lhs);
std::vector<int> vec_rhs = importSigSpec(rhs, timestep_rhs);
@@ -135,7 +129,7 @@ struct SatGen
std::vector<int> undef_rhs = importUndefSigSpec(rhs, timestep_rhs);
std::vector<int> eq_bits;
- for (int i = 0; i < lhs.width; i++)
+ for (int i = 0; i < lhs.size(); i++)
eq_bits.push_back(ez->AND(ez->IFF(undef_lhs.at(i), undef_rhs.at(i)),
ez->IFF(ez->OR(vec_lhs.at(i), undef_lhs.at(i)), ez->OR(vec_rhs.at(i), undef_rhs.at(i)))));
return ez->expression(ezSAT::OpAnd, eq_bits);
@@ -170,20 +164,33 @@ struct SatGen
void undefGating(std::vector<int> &vec_y, std::vector<int> &vec_yy, std::vector<int> &vec_undef)
{
- assert(model_undef);
- ez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(vec_y, vec_yy))));
+ log_assert(model_undef);
+ log_assert(vec_y.size() == vec_yy.size());
+ if (vec_y.size() > vec_undef.size()) {
+ std::vector<int> trunc_y(vec_y.begin(), vec_y.begin() + vec_undef.size());
+ std::vector<int> trunc_yy(vec_yy.begin(), vec_yy.begin() + vec_undef.size());
+ ez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(trunc_y, trunc_yy))));
+ } else {
+ log_assert(vec_y.size() == vec_undef.size());
+ ez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(vec_y, vec_yy))));
+ }
+ }
+
+ void undefGating(int y, int yy, int undef)
+ {
+ ez->assume(ez->OR(undef, ez->IFF(y, yy)));
}
bool importCell(RTLIL::Cell *cell, int timestep = -1)
{
bool arith_undef_handled = false;
- bool is_arith_compare = cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt";
+ bool is_arith_compare = cell->type.in("$lt", "$le", "$ge", "$gt");
- if (model_undef && (cell->type == "$add" || cell->type == "$sub" || cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod" || is_arith_compare))
+ if (model_undef && (cell->type.in("$add", "$sub", "$mul", "$div", "$mod") || is_arith_compare))
{
- std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
if (is_arith_compare)
extendSignalWidth(undef_a, undef_b, cell, true);
else
@@ -194,7 +201,7 @@ struct SatGen
int undef_y_bit = ez->OR(undef_any_a, undef_any_b);
if (cell->type == "$div" || cell->type == "$mod") {
- std::vector<int> b = importSigSpec(cell->connections.at("\\B"), timestep);
+ std::vector<int> b = importSigSpec(cell->getPort("\\B"), timestep);
undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b)));
}
@@ -210,24 +217,27 @@ struct SatGen
arith_undef_handled = true;
}
- if (cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_" ||
- cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor" ||
- cell->type == "$add" || cell->type == "$sub")
+ if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_",
+ "$and", "$or", "$xor", "$xnor", "$add", "$sub"))
{
- std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(a, b, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
if (cell->type == "$and" || cell->type == "$_AND_")
ez->assume(ez->vec_eq(ez->vec_and(a, b), yy));
+ if (cell->type == "$_NAND_")
+ ez->assume(ez->vec_eq(ez->vec_not(ez->vec_and(a, b)), yy));
if (cell->type == "$or" || cell->type == "$_OR_")
ez->assume(ez->vec_eq(ez->vec_or(a, b), yy));
+ if (cell->type == "$_NOR_")
+ ez->assume(ez->vec_eq(ez->vec_not(ez->vec_or(a, b)), yy));
if (cell->type == "$xor" || cell->type == "$_XOR_")
ez->assume(ez->vec_eq(ez->vec_xor(a, b), yy));
- if (cell->type == "$xnor")
+ if (cell->type == "$xnor" || cell->type == "$_XNOR_")
ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(a, b)), yy));
if (cell->type == "$add")
ez->assume(ez->vec_eq(ez->vec_add(a, b), yy));
@@ -236,24 +246,24 @@ struct SatGen
if (model_undef && !arith_undef_handled)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(undef_a, undef_b, undef_y, cell, false);
- if (cell->type == "$and" || cell->type == "$_AND_") {
+ if (cell->type.in("$and", "$_AND_", "$_NAND_")) {
std::vector<int> a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a));
std::vector<int> b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b));
std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b0)));
ez->assume(ez->vec_eq(yX, undef_y));
}
- else if (cell->type == "$or" || cell->type == "$_OR_") {
+ else if (cell->type.in("$or", "$_OR_", "$_NOR_")) {
std::vector<int> a1 = ez->vec_and(a, ez->vec_not(undef_a));
std::vector<int> b1 = ez->vec_and(b, ez->vec_not(undef_b));
std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b1)));
ez->assume(ez->vec_eq(yX, undef_y));
}
- else if (cell->type == "$xor" || cell->type == "$_XOR_" || cell->type == "$xnor") {
+ else if (cell->type.in("$xor", "$xnor", "$_XOR_", "$_XNOR_")) {
std::vector<int> yX = ez->vec_or(undef_a, undef_b);
ez->assume(ez->vec_eq(yX, undef_y));
}
@@ -264,25 +274,91 @@ struct SatGen
}
else if (model_undef)
{
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ undefGating(y, yy, undef_y);
+ }
+ return true;
+ }
+
+ if (cell->type.in("$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_"))
+ {
+ bool aoi_mode = cell->type.in("$_AOI3_", "$_AOI4_");
+ bool three_mode = cell->type.in("$_AOI3_", "$_OAI3_");
+
+ int a = importDefSigSpec(cell->getPort("\\A"), timestep).at(0);
+ int b = importDefSigSpec(cell->getPort("\\B"), timestep).at(0);
+ int c = importDefSigSpec(cell->getPort("\\C"), timestep).at(0);
+ int d = three_mode ? (aoi_mode ? ez->TRUE : ez->FALSE) : importDefSigSpec(cell->getPort("\\D"), timestep).at(0);
+ int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0);
+ int yy = model_undef ? ez->literal() : y;
+
+ if (cell->type.in("$_AOI3_", "$_AOI4_"))
+ ez->assume(ez->IFF(ez->NOT(ez->OR(ez->AND(a, b), ez->AND(c, d))), yy));
+ else
+ ez->assume(ez->IFF(ez->NOT(ez->AND(ez->OR(a, b), ez->OR(c, d))), yy));
+
+ if (model_undef)
+ {
+ int undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep).at(0);
+ int undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep).at(0);
+ int undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep).at(0);
+ int undef_d = three_mode ? ez->FALSE : importUndefSigSpec(cell->getPort("\\D"), timestep).at(0);
+ int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0);
+
+ if (aoi_mode)
+ {
+ int a0 = ez->AND(ez->NOT(a), ez->NOT(undef_a));
+ int b0 = ez->AND(ez->NOT(b), ez->NOT(undef_b));
+ int c0 = ez->AND(ez->NOT(c), ez->NOT(undef_c));
+ int d0 = ez->AND(ez->NOT(d), ez->NOT(undef_d));
+
+ int ab = ez->AND(a, b), cd = ez->AND(c, d);
+ int undef_ab = ez->AND(ez->OR(undef_a, undef_b), ez->NOT(ez->OR(a0, b0)));
+ int undef_cd = ez->AND(ez->OR(undef_c, undef_d), ez->NOT(ez->OR(c0, d0)));
+
+ int ab1 = ez->AND(ab, ez->NOT(undef_ab));
+ int cd1 = ez->AND(cd, ez->NOT(undef_cd));
+ int yX = ez->AND(ez->OR(undef_ab, undef_cd), ez->NOT(ez->OR(ab1, cd1)));
+
+ ez->assume(ez->IFF(yX, undef_y));
+ }
+ else
+ {
+ int a1 = ez->AND(a, ez->NOT(undef_a));
+ int b1 = ez->AND(b, ez->NOT(undef_b));
+ int c1 = ez->AND(c, ez->NOT(undef_c));
+ int d1 = ez->AND(d, ez->NOT(undef_d));
+
+ int ab = ez->OR(a, b), cd = ez->OR(c, d);
+ int undef_ab = ez->AND(ez->OR(undef_a, undef_b), ez->NOT(ez->OR(a1, b1)));
+ int undef_cd = ez->AND(ez->OR(undef_c, undef_d), ez->NOT(ez->OR(c1, d1)));
+
+ int ab0 = ez->AND(ez->NOT(ab), ez->NOT(undef_ab));
+ int cd0 = ez->AND(ez->NOT(cd), ez->NOT(undef_cd));
+ int yX = ez->AND(ez->OR(undef_ab, undef_cd), ez->NOT(ez->OR(ab0, cd0)));
+
+ ez->assume(ez->IFF(yX, undef_y));
+ }
+
undefGating(y, yy, undef_y);
}
+
return true;
}
- if (cell->type == "$_INV_" || cell->type == "$not")
+ if (cell->type == "$_NOT_" || cell->type == "$not")
{
- std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidthUnary(a, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
ez->assume(ez->vec_eq(ez->vec_not(a), yy));
if (model_undef) {
- std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
- extendSignalWidthUnary(undef_a, undef_y, cell, true);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ extendSignalWidthUnary(undef_a, undef_y, cell, false);
ez->assume(ez->vec_eq(undef_a, undef_y));
undefGating(y, yy, undef_y);
}
@@ -291,20 +367,20 @@ struct SatGen
if (cell->type == "$_MUX_" || cell->type == "$mux")
{
- std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> s = importDefSigSpec(cell->connections.at("\\S"), timestep);
- std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> s = importDefSigSpec(cell->getPort("\\S"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy));
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> undef_s = importUndefSigSpec(cell->connections.at("\\S"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a, b));
std::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b));
@@ -315,12 +391,12 @@ struct SatGen
return true;
}
- if (cell->type == "$pmux" || cell->type == "$safe_pmux")
+ if (cell->type == "$pmux")
{
- std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> s = importDefSigSpec(cell->connections.at("\\S"), timestep);
- std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> s = importDefSigSpec(cell->getPort("\\S"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@@ -329,16 +405,14 @@ struct SatGen
std::vector<int> part_of_b(b.begin()+i*a.size(), b.begin()+(i+1)*a.size());
tmp = ez->vec_ite(s.at(i), part_of_b, tmp);
}
- if (cell->type == "$safe_pmux")
- tmp = ez->vec_ite(ez->onehot(s, true), tmp, a);
ez->assume(ez->vec_eq(tmp, yy));
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> undef_s = importUndefSigSpec(cell->connections.at("\\S"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
int maybe_one_hot = ez->FALSE;
int maybe_many_hot = ez->FALSE;
@@ -369,12 +443,6 @@ struct SatGen
int maybe_a = ez->NOT(maybe_one_hot);
- if (cell->type == "$safe_pmux") {
- maybe_a = ez->OR(maybe_a, maybe_many_hot);
- bits_set = ez->vec_ite(sure_many_hot, ez->vec_or(a, undef_a), bits_set);
- bits_clr = ez->vec_ite(sure_many_hot, ez->vec_or(ez->vec_not(a), undef_a), bits_clr);
- }
-
bits_set = ez->vec_ite(maybe_a, ez->vec_or(bits_set, ez->vec_or(bits_set, ez->vec_or(a, undef_a))), bits_set);
bits_clr = ez->vec_ite(maybe_a, ez->vec_or(bits_clr, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(a), undef_a))), bits_clr);
@@ -386,8 +454,8 @@ struct SatGen
if (cell->type == "$pos" || cell->type == "$neg")
{
- std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidthUnary(a, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@@ -401,9 +469,9 @@ struct SatGen
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
- extendSignalWidthUnary(undef_a, undef_y, cell, true);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ extendSignalWidthUnary(undef_a, undef_y, cell);
if (cell->type == "$pos") {
ez->assume(ez->vec_eq(undef_a, undef_y));
@@ -421,8 +489,8 @@ struct SatGen
if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_xor" ||
cell->type == "$reduce_xnor" || cell->type == "$reduce_bool" || cell->type == "$logic_not")
{
- std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@@ -441,8 +509,8 @@ struct SatGen
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
int aX = ez->expression(ezSAT::OpOr, undef_a);
if (cell->type == "$reduce_and") {
@@ -468,12 +536,12 @@ struct SatGen
if (cell->type == "$logic_and" || cell->type == "$logic_or")
{
- std::vector<int> vec_a = importDefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> vec_b = importDefSigSpec(cell->connections.at("\\B"), timestep);
+ std::vector<int> vec_a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> vec_b = importDefSigSpec(cell->getPort("\\B"), timestep);
int a = ez->expression(ez->OpOr, vec_a);
int b = ez->expression(ez->OpOr, vec_b);
- std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@@ -486,9 +554,9 @@ struct SatGen
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
int a0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_a), ez->expression(ezSAT::OpOr, undef_a)));
int b0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_b), ez->expression(ezSAT::OpOr, undef_b)));
@@ -515,16 +583,16 @@ struct SatGen
if (cell->type == "$lt" || cell->type == "$le" || cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" || cell->type == "$ge" || cell->type == "$gt")
{
bool is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool();
- std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(a, b, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
if (model_undef && (cell->type == "$eqx" || cell->type == "$nex")) {
- std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
extendSignalWidth(undef_a, undef_b, cell, true);
a = ez->vec_or(a, undef_a);
b = ez->vec_or(b, undef_b);
@@ -547,9 +615,9 @@ struct SatGen
if (model_undef && (cell->type == "$eqx" || cell->type == "$nex"))
{
- std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(undef_a, undef_b, cell, true);
if (cell->type == "$eqx")
@@ -564,9 +632,9 @@ struct SatGen
}
else if (model_undef && (cell->type == "$eq" || cell->type == "$ne"))
{
- std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(undef_a, undef_b, cell, true);
int undef_any_a = ez->expression(ezSAT::OpOr, undef_a);
@@ -588,7 +656,7 @@ struct SatGen
else
{
if (model_undef) {
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
undefGating(y, yy, undef_y);
}
log_assert(!model_undef || arith_undef_handled);
@@ -596,59 +664,73 @@ struct SatGen
return true;
}
- if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr")
+ if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx")
{
- std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
- char shift_left = cell->type == "$shl" || cell->type == "$sshl";
- bool sign_extend = cell->type == "$sshr" && cell->parameters["\\A_SIGNED"].as_bool();
+ int extend_bit = ez->FALSE;
+
+ if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool())
+ extend_bit = a.back();
while (y.size() < a.size())
y.push_back(ez->literal());
while (y.size() > a.size())
- a.push_back(cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->FALSE);
+ a.push_back(extend_bit);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
+ std::vector<int> shifted_a;
- std::vector<int> tmp = a;
- for (size_t i = 0; i < b.size(); i++)
- {
- std::vector<int> tmp_shifted(tmp.size());
- for (size_t j = 0; j < tmp.size(); j++) {
- int idx = j + (1 << (i > 30 ? 30 : i)) * (shift_left ? -1 : +1);
- tmp_shifted.at(j) = (0 <= idx && idx < int(tmp.size())) ? tmp.at(idx) : sign_extend ? tmp.back() : ez->FALSE;
- }
- tmp = ez->vec_ite(b.at(i), tmp_shifted, tmp);
- }
- ez->assume(ez->vec_eq(tmp, yy));
+ if (cell->type == "$shl" || cell->type == "$sshl")
+ shifted_a = ez->vec_shift_left(a, b, false, ez->FALSE, ez->FALSE);
+
+ if (cell->type == "$shr")
+ shifted_a = ez->vec_shift_right(a, b, false, ez->FALSE, ez->FALSE);
+
+ if (cell->type == "$sshr")
+ shifted_a = ez->vec_shift_right(a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->FALSE, ez->FALSE);
+
+ if (cell->type == "$shift" || cell->type == "$shiftx")
+ shifted_a = ez->vec_shift_right(a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->FALSE, ez->FALSE);
+
+ ez->assume(ez->vec_eq(shifted_a, yy));
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_a_shifted;
+
+ extend_bit = cell->type == "$shiftx" ? ez->TRUE : ez->FALSE;
+ if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool())
+ extend_bit = undef_a.back();
while (undef_y.size() < undef_a.size())
undef_y.push_back(ez->literal());
while (undef_y.size() > undef_a.size())
- undef_a.push_back(undef_a.back());
+ undef_a.push_back(extend_bit);
- tmp = undef_a;
- for (size_t i = 0; i < b.size(); i++)
- {
- std::vector<int> tmp_shifted(tmp.size());
- for (size_t j = 0; j < tmp.size(); j++) {
- int idx = j + (1 << (i > 30 ? 30 : i)) * (shift_left ? -1 : +1);
- tmp_shifted.at(j) = (0 <= idx && idx < int(tmp.size())) ? tmp.at(idx) : sign_extend ? tmp.back() : ez->FALSE;
- }
- tmp = ez->vec_ite(b.at(i), tmp_shifted, tmp);
- }
+ if (cell->type == "$shl" || cell->type == "$sshl")
+ undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->FALSE, ez->FALSE);
+
+ if (cell->type == "$shr")
+ undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->FALSE, ez->FALSE);
+
+ if (cell->type == "$sshr")
+ undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? undef_a.back() : ez->FALSE, ez->FALSE);
+
+ if (cell->type == "$shift")
+ undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->FALSE, ez->FALSE);
+
+ if (cell->type == "$shiftx")
+ undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->TRUE, ez->TRUE);
int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
std::vector<int> undef_all_y_bits(undef_y.size(), undef_any_b);
- ez->assume(ez->vec_eq(ez->vec_or(tmp, undef_all_y_bits), undef_y));
+ ez->assume(ez->vec_eq(ez->vec_or(undef_a_shifted, undef_all_y_bits), undef_y));
undefGating(y, yy, undef_y);
}
return true;
@@ -656,9 +738,9 @@ struct SatGen
if (cell->type == "$mul")
{
- std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(a, b, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@@ -675,17 +757,87 @@ struct SatGen
if (model_undef) {
log_assert(arith_undef_handled);
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
undefGating(y, yy, undef_y);
}
return true;
}
+ if (cell->type == "$macc")
+ {
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+
+ Macc macc;
+ macc.from_cell(cell);
+
+ std::vector<int> tmp(SIZE(y), ez->FALSE);
+
+ for (auto &port : macc.ports)
+ {
+ std::vector<int> in_a = importDefSigSpec(port.in_a, timestep);
+ std::vector<int> in_b = importDefSigSpec(port.in_b, timestep);
+
+ while (SIZE(in_a) < SIZE(y))
+ in_a.push_back(port.is_signed && !in_a.empty() ? in_a.back() : ez->FALSE);
+ in_a.resize(SIZE(y));
+
+ if (SIZE(in_b))
+ {
+ while (SIZE(in_b) < SIZE(y))
+ in_b.push_back(port.is_signed && !in_b.empty() ? in_b.back() : ez->FALSE);
+ in_b.resize(SIZE(y));
+
+ for (int i = 0; i < SIZE(in_b); i++) {
+ std::vector<int> shifted_a(in_a.size(), ez->FALSE);
+ for (int j = i; j < int(in_a.size()); j++)
+ shifted_a.at(j) = in_a.at(j-i);
+ if (port.do_subtract)
+ tmp = ez->vec_ite(in_b.at(i), ez->vec_sub(tmp, shifted_a), tmp);
+ else
+ tmp = ez->vec_ite(in_b.at(i), ez->vec_add(tmp, shifted_a), tmp);
+ }
+ }
+ else
+ {
+ if (port.do_subtract)
+ tmp = ez->vec_sub(tmp, in_a);
+ else
+ tmp = ez->vec_add(tmp, in_a);
+ }
+ }
+
+ for (int i = 0; i < SIZE(b); i++) {
+ std::vector<int> val(SIZE(y), ez->FALSE);
+ val.at(0) = b.at(i);
+ tmp = ez->vec_add(tmp, val);
+ }
+
+ if (model_undef)
+ {
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
+
+ int undef_any_a = ez->expression(ezSAT::OpOr, undef_a);
+ int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
+
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ ez->assume(ez->vec_eq(undef_y, std::vector<int>(SIZE(y), ez->OR(undef_any_a, undef_any_b))));
+
+ undefGating(y, tmp, undef_y);
+ }
+ else
+ ez->assume(ez->vec_eq(y, tmp));
+
+ return true;
+ }
+
if (cell->type == "$div" || cell->type == "$mod")
{
- std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
- std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(a, b, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@@ -739,11 +891,11 @@ struct SatGen
only_first_one.at(0) = ez->TRUE;
div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones);
} else {
- div_zero_result.insert(div_zero_result.end(), cell->connections.at("\\A").width, ez->TRUE);
+ div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->TRUE);
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->FALSE);
}
} else {
- int copy_a_bits = std::min(cell->connections.at("\\A").width, cell->connections.at("\\B").width);
+ int copy_a_bits = std::min(cell->getPort("\\A").size(), cell->getPort("\\B").size());
div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits);
if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool())
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), div_zero_result.back());
@@ -755,25 +907,209 @@ struct SatGen
if (model_undef) {
log_assert(arith_undef_handled);
- std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ undefGating(y, yy, undef_y);
+ }
+ return true;
+ }
+
+ if (cell->type == "$lut")
+ {
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+
+ std::vector<int> lut;
+ for (auto bit : cell->getParam("\\LUT").bits)
+ lut.push_back(bit == RTLIL::S1 ? ez->TRUE : ez->FALSE);
+ while (SIZE(lut) < (1 << SIZE(a)))
+ lut.push_back(ez->FALSE);
+ lut.resize(1 << SIZE(a));
+
+ if (model_undef)
+ {
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> t(lut), u(SIZE(t), ez->FALSE);
+
+ for (int i = SIZE(a)-1; i >= 0; i--)
+ {
+ std::vector<int> t0(t.begin(), t.begin() + SIZE(t)/2);
+ std::vector<int> t1(t.begin() + SIZE(t)/2, t.end());
+
+ std::vector<int> u0(u.begin(), u.begin() + SIZE(u)/2);
+ std::vector<int> u1(u.begin() + SIZE(u)/2, u.end());
+
+ t = ez->vec_ite(a[i], t1, t0);
+ u = ez->vec_ite(undef_a[i], ez->vec_or(ez->vec_xor(t0, t1), ez->vec_or(u0, u1)), ez->vec_ite(a[i], u1, u0));
+ }
+
+ log_assert(SIZE(t) == 1);
+ log_assert(SIZE(u) == 1);
+ undefGating(y, t, u);
+ ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort("\\Y"), timestep), u));
+ }
+ else
+ {
+ std::vector<int> t = lut;
+ for (int i = SIZE(a)-1; i >= 0; i--)
+ {
+ std::vector<int> t0(t.begin(), t.begin() + SIZE(t)/2);
+ std::vector<int> t1(t.begin() + SIZE(t)/2, t.end());
+ t = ez->vec_ite(a[i], t1, t0);
+ }
+
+ log_assert(SIZE(t) == 1);
+ ez->assume(ez->vec_eq(y, t));
+ }
+ return true;
+ }
+
+ if (cell->type == "$fa")
+ {
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> c = importDefSigSpec(cell->getPort("\\C"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> x = importDefSigSpec(cell->getPort("\\X"), timestep);
+
+ std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
+ std::vector<int> xx = model_undef ? ez->vec_var(x.size()) : x;
+
+ std::vector<int> t1 = ez->vec_xor(a, b);
+ ez->assume(ez->vec_eq(yy, ez->vec_xor(t1, c)));
+
+ std::vector<int> t2 = ez->vec_and(a, b);
+ std::vector<int> t3 = ez->vec_and(c, t1);
+ ez->assume(ez->vec_eq(xx, ez->vec_or(t2, t3)));
+
+ if (model_undef)
+ {
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep);
+
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_x = importUndefSigSpec(cell->getPort("\\X"), timestep);
+
+ ez->assume(ez->vec_eq(undef_y, ez->vec_or(ez->vec_or(undef_a, undef_b), undef_c)));
+ ez->assume(ez->vec_eq(undef_x, undef_y));
+
undefGating(y, yy, undef_y);
+ undefGating(x, xx, undef_x);
+ }
+ return true;
+ }
+
+ if (cell->type == "$lcu")
+ {
+ std::vector<int> p = importDefSigSpec(cell->getPort("\\P"), timestep);
+ std::vector<int> g = importDefSigSpec(cell->getPort("\\G"), timestep);
+ std::vector<int> ci = importDefSigSpec(cell->getPort("\\CI"), timestep);
+ std::vector<int> co = importDefSigSpec(cell->getPort("\\CO"), timestep);
+
+ std::vector<int> yy = model_undef ? ez->vec_var(co.size()) : co;
+
+ for (int i = 0; i < SIZE(co); i++)
+ ez->SET(yy[i], ez->OR(g[i], ez->AND(p[i], i ? yy[i-1] : ci[0])));
+
+ if (model_undef)
+ {
+ std::vector<int> undef_p = importUndefSigSpec(cell->getPort("\\P"), timestep);
+ std::vector<int> undef_g = importUndefSigSpec(cell->getPort("\\G"), timestep);
+ std::vector<int> undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep);
+ std::vector<int> undef_co = importUndefSigSpec(cell->getPort("\\CO"), timestep);
+
+ int undef_any_p = ez->expression(ezSAT::OpOr, undef_p);
+ int undef_any_g = ez->expression(ezSAT::OpOr, undef_g);
+ int undef_any_ci = ez->expression(ezSAT::OpOr, undef_ci);
+ int undef_co_bit = ez->OR(undef_any_p, undef_any_g, undef_any_ci);
+
+ std::vector<int> undef_co_bits(undef_co.size(), undef_co_bit);
+ ez->assume(ez->vec_eq(undef_co_bits, undef_co));
+
+ undefGating(co, yy, undef_co);
+ }
+ return true;
+ }
+
+ if (cell->type == "$alu")
+ {
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> x = importDefSigSpec(cell->getPort("\\X"), timestep);
+ std::vector<int> ci = importDefSigSpec(cell->getPort("\\CI"), timestep);
+ std::vector<int> bi = importDefSigSpec(cell->getPort("\\BI"), timestep);
+ std::vector<int> co = importDefSigSpec(cell->getPort("\\CO"), timestep);
+
+ extendSignalWidth(a, b, y, cell);
+ extendSignalWidth(a, b, x, cell);
+ extendSignalWidth(a, b, co, cell);
+
+ std::vector<int> def_y = model_undef ? ez->vec_var(y.size()) : y;
+ std::vector<int> def_x = model_undef ? ez->vec_var(x.size()) : x;
+ std::vector<int> def_co = model_undef ? ez->vec_var(co.size()) : co;
+
+ log_assert(SIZE(y) == SIZE(x));
+ log_assert(SIZE(y) == SIZE(co));
+ log_assert(SIZE(ci) == 1);
+ log_assert(SIZE(bi) == 1);
+
+ for (int i = 0; i < SIZE(y); i++)
+ {
+ int s1 = a.at(i), s2 = ez->XOR(b.at(i), bi.at(0)), s3 = i ? co.at(i-1) : ci.at(0);
+ ez->SET(def_x.at(i), ez->XOR(s1, s2));
+ ez->SET(def_y.at(i), ez->XOR(def_x.at(i), s3));
+ ez->SET(def_co.at(i), ez->OR(ez->AND(s1, s2), ez->AND(s1, s3), ez->AND(s2, s3)));
+ }
+
+ if (model_undef)
+ {
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep);
+ std::vector<int> undef_bi = importUndefSigSpec(cell->getPort("\\BI"), timestep);
+
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_x = importUndefSigSpec(cell->getPort("\\X"), timestep);
+ std::vector<int> undef_co = importUndefSigSpec(cell->getPort("\\CO"), timestep);
+
+ extendSignalWidth(undef_a, undef_b, undef_y, cell);
+ extendSignalWidth(undef_a, undef_b, undef_x, cell);
+ extendSignalWidth(undef_a, undef_b, undef_co, cell);
+
+ std::vector<int> all_inputs_undef;
+ all_inputs_undef.insert(all_inputs_undef.end(), undef_a.begin(), undef_a.end());
+ all_inputs_undef.insert(all_inputs_undef.end(), undef_b.begin(), undef_b.end());
+ all_inputs_undef.insert(all_inputs_undef.end(), undef_ci.begin(), undef_ci.end());
+ all_inputs_undef.insert(all_inputs_undef.end(), undef_bi.begin(), undef_bi.end());
+ int undef_any = ez->expression(ezSAT::OpOr, all_inputs_undef);
+
+ for (int i = 0; i < SIZE(undef_y); i++) {
+ ez->SET(undef_y.at(i), undef_any);
+ ez->SET(undef_x.at(i), ez->OR(undef_a.at(i), undef_b.at(i), undef_bi.at(0)));
+ ez->SET(undef_co.at(i), undef_any);
+ }
+
+ undefGating(y, def_y, undef_y);
+ undefGating(x, def_x, undef_x);
+ undefGating(co, def_co, undef_co);
}
return true;
}
if (cell->type == "$slice")
{
- RTLIL::SigSpec a = cell->connections.at("\\A");
- RTLIL::SigSpec y = cell->connections.at("\\Y");
- ez->assume(signals_eq(a.extract(cell->parameters.at("\\OFFSET").as_int(), y.width), y, timestep));
+ RTLIL::SigSpec a = cell->getPort("\\A");
+ RTLIL::SigSpec y = cell->getPort("\\Y");
+ ez->assume(signals_eq(a.extract(cell->parameters.at("\\OFFSET").as_int(), y.size()), y, timestep));
return true;
}
if (cell->type == "$concat")
{
- RTLIL::SigSpec a = cell->connections.at("\\A");
- RTLIL::SigSpec b = cell->connections.at("\\B");
- RTLIL::SigSpec y = cell->connections.at("\\Y");
+ RTLIL::SigSpec a = cell->getPort("\\A");
+ RTLIL::SigSpec b = cell->getPort("\\B");
+ RTLIL::SigSpec y = cell->getPort("\\Y");
RTLIL::SigSpec ab = a;
ab.append(b);
@@ -786,20 +1122,20 @@ struct SatGen
{
if (timestep == 1)
{
- initial_state.add((*sigmap)(cell->connections.at("\\Q")));
+ initial_state.add((*sigmap)(cell->getPort("\\Q")));
}
else
{
- std::vector<int> d = importDefSigSpec(cell->connections.at("\\D"), timestep-1);
- std::vector<int> q = importDefSigSpec(cell->connections.at("\\Q"), timestep);
+ std::vector<int> d = importDefSigSpec(cell->getPort("\\D"), timestep-1);
+ std::vector<int> q = importDefSigSpec(cell->getPort("\\Q"), timestep);
std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q;
ez->assume(ez->vec_eq(d, qq));
if (model_undef)
{
- std::vector<int> undef_d = importUndefSigSpec(cell->connections.at("\\D"), timestep-1);
- std::vector<int> undef_q = importUndefSigSpec(cell->connections.at("\\Q"), timestep);
+ std::vector<int> undef_d = importUndefSigSpec(cell->getPort("\\D"), timestep-1);
+ std::vector<int> undef_q = importUndefSigSpec(cell->getPort("\\Q"), timestep);
ez->assume(ez->vec_eq(undef_d, undef_q));
undefGating(q, qq, undef_q);
@@ -811,8 +1147,8 @@ struct SatGen
if (cell->type == "$assert")
{
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
- asserts_a[pf].append((*sigmap)(cell->connections.at("\\A")));
- asserts_en[pf].append((*sigmap)(cell->connections.at("\\EN")));
+ asserts_a[pf].append((*sigmap)(cell->getPort("\\A")));
+ asserts_en[pf].append((*sigmap)(cell->getPort("\\EN")));
return true;
}
@@ -823,4 +1159,3 @@ struct SatGen
};
#endif
-
diff --git a/kernel/sigtools.h b/kernel/sigtools.h
index ae6a00f8..32ef444a 100644
--- a/kernel/sigtools.h
+++ b/kernel/sigtools.h
@@ -20,14 +20,17 @@
#ifndef SIGTOOLS_H
#define SIGTOOLS_H
-#include "kernel/rtlil.h"
-#include "kernel/log.h"
-#include <assert.h>
-#include <set>
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
struct SigPool
{
- typedef std::pair<RTLIL::Wire*,int> bitDef_t;
+ struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
+ bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
+ bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
+ };
+
std::set<bitDef_t> bits;
void clear()
@@ -37,14 +40,9 @@ struct SigPool
void add(RTLIL::SigSpec sig)
{
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL)
- continue;
- assert(c.width == 1);
- bitDef_t bit(c.wire, c.offset);
- bits.insert(bit);
- }
+ for (auto &bit : sig)
+ if (bit.wire != NULL)
+ bits.insert(bit);
}
void add(const SigPool &other)
@@ -55,14 +53,9 @@ struct SigPool
void del(RTLIL::SigSpec sig)
{
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL)
- continue;
- assert(c.width == 1);
- bitDef_t bit(c.wire, c.offset);
- bits.erase(bit);
- }
+ for (auto &bit : sig)
+ if (bit.wire != NULL)
+ bits.erase(bit);
}
void del(const SigPool &other)
@@ -73,15 +66,10 @@ struct SigPool
void expand(RTLIL::SigSpec from, RTLIL::SigSpec to)
{
- from.expand();
- to.expand();
- assert(from.chunks.size() == to.chunks.size());
- for (size_t i = 0; i < from.chunks.size(); i++) {
- bitDef_t bit_from(from.chunks[i].wire, from.chunks[i].offset);
- bitDef_t bit_to(to.chunks[i].wire, to.chunks[i].offset);
- if (bit_from.first == NULL || bit_to.first == NULL)
- continue;
- if (bits.count(bit_from) > 0)
+ log_assert(SIZE(from) == SIZE(to));
+ for (int i = 0; i < SIZE(from); i++) {
+ bitDef_t bit_from(from[i]), bit_to(to[i]);
+ if (bit_from.first != NULL && bit_to.first != NULL && bits.count(bit_from) > 0)
bits.insert(bit_to);
}
}
@@ -89,73 +77,54 @@ struct SigPool
RTLIL::SigSpec extract(RTLIL::SigSpec sig)
{
RTLIL::SigSpec result;
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL)
- continue;
- bitDef_t bit(c.wire, c.offset);
- if (bits.count(bit) > 0)
- result.append(c);
- }
+ for (auto &bit : sig)
+ if (bit.wire != NULL && bits.count(bit))
+ result.append_bit(bit);
return result;
}
RTLIL::SigSpec remove(RTLIL::SigSpec sig)
{
RTLIL::SigSpec result;
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL)
- continue;
- bitDef_t bit(c.wire, c.offset);
- if (bits.count(bit) == 0)
- result.append(c);
- }
+ for (auto &bit : sig)
+ if (bit.wire != NULL && bits.count(bit) == 0)
+ result.append(bit);
return result;
}
+ bool check(RTLIL::SigBit bit)
+ {
+ return bit.wire != NULL && bits.count(bit);
+ }
+
bool check_any(RTLIL::SigSpec sig)
{
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL)
- continue;
- bitDef_t bit(c.wire, c.offset);
- if (bits.count(bit) != 0)
+ for (auto &bit : sig)
+ if (bit.wire != NULL && bits.count(bit))
return true;
- }
return false;
}
bool check_all(RTLIL::SigSpec sig)
{
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL)
- continue;
- bitDef_t bit(c.wire, c.offset);
- if (bits.count(bit) == 0)
+ for (auto &bit : sig)
+ if (bit.wire != NULL && bits.count(bit) == 0)
return false;
- }
return true;
}
RTLIL::SigSpec export_one()
{
- RTLIL::SigSpec sig;
- for (auto &bit : bits) {
- sig.append(RTLIL::SigSpec(bit.first, 1, bit.second));
- break;
- }
- return sig;
+ for (auto &bit : bits)
+ return RTLIL::SigSpec(bit.first, bit.second);
+ return RTLIL::SigSpec();
}
RTLIL::SigSpec export_all()
{
- RTLIL::SigSpec sig;
+ std::set<RTLIL::SigBit> sig;
for (auto &bit : bits)
- sig.append(RTLIL::SigSpec(bit.first, 1, bit.second));
- sig.sort_and_unify();
+ sig.insert(RTLIL::SigBit(bit.first, bit.second));
return sig;
}
@@ -168,7 +137,11 @@ struct SigPool
template <typename T, class Compare = std::less<T>>
struct SigSet
{
- typedef std::pair<RTLIL::Wire*,int> bitDef_t;
+ struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
+ bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
+ bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
+ };
+
std::map<bitDef_t, std::set<T, Compare>> bits;
void clear()
@@ -178,75 +151,46 @@ struct SigSet
void insert(RTLIL::SigSpec sig, T data)
{
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL)
- continue;
- assert(c.width == 1);
- bitDef_t bit(c.wire, c.offset);
- bits[bit].insert(data);
- }
+ for (auto &bit : sig)
+ if (bit.wire != NULL)
+ bits[bit].insert(data);
}
void insert(RTLIL::SigSpec sig, const std::set<T> &data)
{
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL)
- continue;
- assert(c.width == 1);
- bitDef_t bit(c.wire, c.offset);
- bits[bit].insert(data.begin(), data.end());
- }
+ for (auto &bit : sig)
+ if (bit.wire != NULL)
+ bits[bit].insert(data.begin(), data.end());
}
void erase(RTLIL::SigSpec sig)
{
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL)
- continue;
- assert(c.width == 1);
- bitDef_t bit(c.wire, c.offset);
- bits[bit].clear();
- }
+ for (auto &bit : sig)
+ if (bit.wire != NULL)
+ bits[bit].clear();
}
void erase(RTLIL::SigSpec sig, T data)
{
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL)
- continue;
- assert(c.width == 1);
- bitDef_t bit(c.wire, c.offset);
- bits[bit].erase(data);
- }
+ for (auto &bit : sig)
+ if (bit.wire != NULL)
+ bits[bit].erase(data);
}
void erase(RTLIL::SigSpec sig, const std::set<T> &data)
{
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL)
- continue;
- assert(c.width == 1);
- bitDef_t bit(c.wire, c.offset);
- bits[bit].erase(data.begin(), data.end());
- }
+ for (auto &bit : sig)
+ if (bit.wire != NULL)
+ bits[bit].erase(data.begin(), data.end());
}
void find(RTLIL::SigSpec sig, std::set<T> &result)
{
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL)
- continue;
- assert(c.width == 1);
- bitDef_t bit(c.wire, c.offset);
- for (auto &data : bits[bit])
- result.insert(data);
- }
+ for (auto &bit : sig)
+ if (bit.wire != NULL) {
+ auto &data = bits[bit];
+ result.insert(data.begin(), data.end());
+ }
}
std::set<T> find(RTLIL::SigSpec sig)
@@ -258,25 +202,22 @@ struct SigSet
bool has(RTLIL::SigSpec sig)
{
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL)
- continue;
- assert(c.width == 1);
- bitDef_t bit(c.wire, c.offset);
- if (bits.count(bit))
+ for (auto &bit : sig)
+ if (bit.wire != NULL && bits.count(bit))
return true;
- }
return false;
}
};
struct SigMap
{
- typedef std::pair<RTLIL::Wire*,int> bitDef_t;
+ struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
+ bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
+ bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
+ };
struct shared_bit_data_t {
- RTLIL::SigChunk chunk;
+ RTLIL::SigBit map_to;
std::set<bitDef_t> bits;
};
@@ -304,7 +245,7 @@ struct SigMap
clear();
for (auto &bit : other.bits) {
bits[bit.first] = new shared_bit_data_t;
- bits[bit.first]->chunk = bit.second->chunk;
+ bits[bit.first]->map_to = bit.second->map_to;
bits[bit.first]->bits = bit.second->bits;
}
}
@@ -332,29 +273,25 @@ struct SigMap
void set(RTLIL::Module *module)
{
clear();
- for (auto &it : module->connections)
+ for (auto &it : module->connections())
add(it.first, it.second);
}
// internal helper function
- void register_bit(const RTLIL::SigChunk &c)
+ void register_bit(const RTLIL::SigBit &bit)
{
- assert(c.width == 1);
- bitDef_t bit(c.wire, c.offset);
- if (c.wire && bits.count(bit) == 0) {
+ if (bit.wire && bits.count(bit) == 0) {
shared_bit_data_t *bd = new shared_bit_data_t;
- bd->chunk = c;
+ bd->map_to = bit;
bd->bits.insert(bit);
bits[bit] = bd;
}
}
// internal helper function
- void unregister_bit(const RTLIL::SigChunk &c)
+ void unregister_bit(const RTLIL::SigBit &bit)
{
- assert(c.width == 1);
- bitDef_t bit(c.wire, c.offset);
- if (c.wire && bits.count(bit) > 0) {
+ if (bit.wire && bits.count(bit) > 0) {
shared_bit_data_t *bd = bits[bit];
bd->bits.erase(bit);
if (bd->bits.size() == 0)
@@ -364,17 +301,13 @@ struct SigMap
}
// internal helper function
- void merge_bit(const RTLIL::SigChunk &c1, const RTLIL::SigChunk &c2)
+ void merge_bit(const RTLIL::SigBit &bit1, const RTLIL::SigBit &bit2)
{
- assert(c1.wire != NULL && c2.wire != NULL);
- assert(c1.width == 1 && c2.width == 1);
-
- bitDef_t b1(c1.wire, c1.offset);
- bitDef_t b2(c2.wire, c2.offset);
+ log_assert(bit1.wire != NULL && bit2.wire != NULL);
- shared_bit_data_t *bd1 = bits[b1];
- shared_bit_data_t *bd2 = bits[b2];
- assert(bd1 != NULL && bd2 != NULL);
+ shared_bit_data_t *bd1 = bits[bit1];
+ shared_bit_data_t *bd2 = bits[bit2];
+ log_assert(bd1 != NULL && bd2 != NULL);
if (bd1 == bd2)
return;
@@ -388,7 +321,7 @@ struct SigMap
}
else
{
- bd1->chunk = bd2->chunk;
+ bd1->map_to = bd2->map_to;
for (auto &bit : bd2->bits)
bits[bit] = bd1;
bd1->bits.insert(bd2->bits.begin(), bd2->bits.end());
@@ -397,81 +330,87 @@ struct SigMap
}
// internal helper function
- void set_bit(const RTLIL::SigChunk &c1, const RTLIL::SigChunk &c2)
+ void set_bit(const RTLIL::SigBit &bit1, const RTLIL::SigBit &bit2)
{
- assert(c1.wire != NULL);
- assert(c1.width == 1 && c2.width == 1);
- bitDef_t bit(c1.wire, c1.offset);
- assert(bits.count(bit) > 0);
- bits[bit]->chunk = c2;
+ log_assert(bit1.wire != NULL);
+ log_assert(bits.count(bit1) > 0);
+ bits[bit1]->map_to = bit2;
}
// internal helper function
- void map_bit(RTLIL::SigChunk &c)
+ void map_bit(RTLIL::SigBit &bit) const
{
- assert(c.width == 1);
- bitDef_t bit(c.wire, c.offset);
- if (c.wire && bits.count(bit) > 0)
- c = bits[bit]->chunk;
+ if (bit.wire && bits.count(bit) > 0)
+ bit = bits.at(bit)->map_to;
}
void add(RTLIL::SigSpec from, RTLIL::SigSpec to)
{
- from.expand();
- to.expand();
+ log_assert(SIZE(from) == SIZE(to));
- assert(from.chunks.size() == to.chunks.size());
- for (size_t i = 0; i < from.chunks.size(); i++)
+ for (int i = 0; i < SIZE(from); i++)
{
- RTLIL::SigChunk &cf = from.chunks[i];
- RTLIL::SigChunk &ct = to.chunks[i];
+ RTLIL::SigBit &bf = from[i];
+ RTLIL::SigBit &bt = to[i];
- if (cf.wire == NULL)
+ if (bf.wire == NULL)
continue;
- register_bit(cf);
- register_bit(ct);
+ register_bit(bf);
+ register_bit(bt);
- if (ct.wire != NULL)
- merge_bit(cf, ct);
+ if (bt.wire != NULL)
+ merge_bit(bf, bt);
else
- set_bit(cf, ct);
+ set_bit(bf, bt);
}
}
void add(RTLIL::SigSpec sig)
{
- sig.expand();
- for (size_t i = 0; i < sig.chunks.size(); i++)
- {
- RTLIL::SigChunk &c = sig.chunks[i];
- if (c.wire != NULL) {
- register_bit(c);
- set_bit(c, c);
- }
+ for (auto &bit : sig) {
+ register_bit(bit);
+ set_bit(bit, bit);
}
}
void del(RTLIL::SigSpec sig)
{
- sig.expand();
- for (auto &c : sig.chunks)
- unregister_bit(c);
+ for (auto &bit : sig)
+ unregister_bit(bit);
+ }
+
+ void apply(RTLIL::SigBit &bit) const
+ {
+ map_bit(bit);
+ }
+
+ void apply(RTLIL::SigSpec &sig) const
+ {
+ for (auto &bit : sig)
+ map_bit(bit);
}
- void apply(RTLIL::SigSpec &sig)
+ RTLIL::SigBit operator()(RTLIL::SigBit bit) const
{
- sig.expand();
- for (auto &c : sig.chunks)
- map_bit(c);
- sig.optimize();
+ apply(bit);
+ return bit;
}
- RTLIL::SigSpec operator()(RTLIL::SigSpec sig)
+ RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const
{
apply(sig);
return sig;
}
+
+ RTLIL::SigSpec operator()(RTLIL::Wire *wire) const
+ {
+ RTLIL::SigSpec sig(wire);
+ apply(sig);
+ return sig;
+ }
};
+YOSYS_NAMESPACE_END
+
#endif /* SIGTOOLS_H */
diff --git a/kernel/utils.h b/kernel/utils.h
new file mode 100644
index 00000000..a03caf80
--- /dev/null
+++ b/kernel/utils.h
@@ -0,0 +1,210 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+// This file contains various c++ utility routines and helper classes that
+// do not depend on any other components of yosys (except stuff like log_*).
+
+#include "kernel/yosys.h"
+
+#ifndef UTILS_H
+#define UTILS_H
+
+// ------------------------------------------------
+// A map-like container, but you can save and restore the state
+// ------------------------------------------------
+
+template<typename Key, typename T, typename Compare = std::less<Key>>
+struct stackmap
+{
+private:
+ std::vector<std::map<Key, T*, Compare>> backup_state;
+ std::map<Key, T, Compare> current_state;
+ static T empty_tuple;
+
+public:
+ stackmap() { }
+ stackmap(const std::map<Key, T, Compare> &other) : current_state(other) { }
+
+ template<typename Other>
+ void operator=(const Other &other)
+ {
+ for (auto &it : current_state)
+ if (!backup_state.empty() && backup_state.back().count(it.first) == 0)
+ backup_state.back()[it.first] = new T(it.second);
+ current_state.clear();
+
+ for (auto &it : other)
+ set(it.first, it.second);
+ }
+
+ bool has(const Key &k)
+ {
+ return current_state.count(k) != 0;
+ }
+
+ void set(const Key &k, const T &v)
+ {
+ if (!backup_state.empty() && backup_state.back().count(k) == 0)
+ backup_state.back()[k] = current_state.count(k) ? new T(current_state.at(k)) : nullptr;
+ current_state[k] = v;
+ }
+
+ void unset(const Key &k)
+ {
+ if (!backup_state.empty() && backup_state.back().count(k) == 0)
+ backup_state.back()[k] = current_state.count(k) ? new T(current_state.at(k)) : nullptr;
+ current_state.erase(k);
+ }
+
+ const T &get(const Key &k)
+ {
+ if (current_state.count(k) == 0)
+ return empty_tuple;
+ return current_state.at(k);
+ }
+
+ void reset(const Key &k)
+ {
+ for (int i = SIZE(backup_state)-1; i >= 0; i--)
+ if (backup_state[i].count(k) != 0) {
+ if (backup_state[i].at(k) == nullptr)
+ current_state.erase(k);
+ else
+ current_state[k] = *backup_state[i].at(k);
+ return;
+ }
+ current_state.erase(k);
+ }
+
+ const std::map<Key, T, Compare> &stdmap()
+ {
+ return current_state;
+ }
+
+ void save()
+ {
+ backup_state.resize(backup_state.size()+1);
+ }
+
+ void restore()
+ {
+ log_assert(!backup_state.empty());
+ for (auto &it : backup_state.back())
+ if (it.second != nullptr) {
+ current_state[it.first] = *it.second;
+ delete it.second;
+ } else
+ current_state.erase(it.first);
+ backup_state.pop_back();
+ }
+
+ ~stackmap()
+ {
+ while (!backup_state.empty())
+ restore();
+ }
+};
+
+
+// ------------------------------------------------
+// A simple class for topological sorting
+// ------------------------------------------------
+
+template<typename T>
+struct TopoSort
+{
+ bool analyze_loops, found_loops;
+ std::map<T, std::set<T>> database;
+ std::set<std::set<T>> loops;
+ std::vector<T> sorted;
+
+ TopoSort()
+ {
+ analyze_loops = true;
+ found_loops = false;
+ }
+
+ void node(T n)
+ {
+ if (database.count(n) == 0)
+ database[n] = std::set<T>();
+ }
+
+ void edge(T left, T right)
+ {
+ node(left);
+ database[right].insert(left);
+ }
+
+ void sort_worker(const T &n, std::set<T> &marked_cells, std::set<T> &active_cells, std::vector<T> &active_stack)
+ {
+ if (active_cells.count(n)) {
+ found_loops = true;
+ if (analyze_loops) {
+ std::set<T> loop;
+ for (int i = SIZE(active_stack)-1; i >= 0; i--) {
+ loop.insert(active_stack[i]);
+ if (active_stack[i] == n)
+ break;
+ }
+ loops.insert(loop);
+ }
+ return;
+ }
+
+ if (marked_cells.count(n))
+ return;
+
+ if (!database.at(n).empty())
+ {
+ if (analyze_loops)
+ active_stack.push_back(n);
+ active_cells.insert(n);
+
+ for (auto &left_n : database.at(n))
+ sort_worker(left_n, marked_cells, active_cells, active_stack);
+
+ if (analyze_loops)
+ active_stack.pop_back();
+ active_cells.erase(n);
+ }
+
+ marked_cells.insert(n);
+ sorted.push_back(n);
+ }
+
+ bool sort()
+ {
+ loops.clear();
+ sorted.clear();
+ found_loops = false;
+
+ std::set<T> marked_cells;
+ std::set<T> active_cells;
+ std::vector<T> active_stack;
+
+ for (auto &it : database)
+ sort_worker(it.first, marked_cells, active_cells, active_stack);
+
+ log_assert(SIZE(sorted) == SIZE(database));
+ return !found_loops;
+ }
+};
+
+#endif
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
new file mode 100644
index 00000000..0ecb4cda
--- /dev/null
+++ b/kernel/yosys.cc
@@ -0,0 +1,646 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+
+#ifdef YOSYS_ENABLE_READLINE
+# include <readline/readline.h>
+# include <readline/history.h>
+#endif
+
+#include <dlfcn.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+
+YOSYS_NAMESPACE_BEGIN
+
+int autoidx = 1;
+RTLIL::Design *yosys_design = NULL;
+
+#ifdef YOSYS_ENABLE_TCL
+Tcl_Interp *yosys_tcl_interp = NULL;
+#endif
+
+std::string stringf(const char *fmt, ...)
+{
+ std::string string;
+ va_list ap;
+
+ va_start(ap, fmt);
+ string = vstringf(fmt, ap);
+ va_end(ap);
+
+ return string;
+}
+
+std::string vstringf(const char *fmt, va_list ap)
+{
+ std::string string;
+ char *str = NULL;
+
+ if (vasprintf(&str, fmt, ap) < 0)
+ str = NULL;
+
+ if (str != NULL) {
+ string = str;
+ free(str);
+ }
+
+ return string;
+}
+
+int SIZE(RTLIL::Wire *wire)
+{
+ return wire->width;
+}
+
+void yosys_setup()
+{
+ Pass::init_register();
+ yosys_design = new RTLIL::Design;
+ log_push();
+}
+
+void yosys_shutdown()
+{
+ log_pop();
+
+ delete yosys_design;
+ yosys_design = NULL;
+
+ for (auto f : log_files)
+ if (f != stderr)
+ fclose(f);
+ log_errfile = NULL;
+ log_files.clear();
+
+ Pass::done_register();
+
+#ifdef YOSYS_ENABLE_TCL
+ if (yosys_tcl_interp != NULL) {
+ Tcl_DeleteInterp(yosys_tcl_interp);
+ Tcl_Finalize();
+ yosys_tcl_interp = NULL;
+ }
+#endif
+
+ for (auto &it : loaded_plugins)
+ dlclose(it.second);
+
+ loaded_plugins.clear();
+ loaded_plugin_aliases.clear();
+}
+
+RTLIL::IdString new_id(std::string file, int line, std::string func)
+{
+ std::string str = "$auto$";
+ size_t pos = file.find_last_of('/');
+ str += pos != std::string::npos ? file.substr(pos+1) : file;
+ str += stringf(":%d:%s$%d", line, func.c_str(), autoidx++);
+ return str;
+}
+
+RTLIL::Design *yosys_get_design()
+{
+ return yosys_design;
+}
+
+const char *create_prompt(RTLIL::Design *design, int recursion_counter)
+{
+ static char buffer[100];
+ std::string str = "\n";
+ if (recursion_counter > 1)
+ str += stringf("(%d) ", recursion_counter);
+ str += "yosys";
+ if (!design->selected_active_module.empty())
+ str += stringf(" [%s]", RTLIL::unescape_id(design->selected_active_module).c_str());
+ if (!design->selection_stack.empty() && !design->selection_stack.back().full_selection) {
+ if (design->selected_active_module.empty())
+ str += "*";
+ else if (design->selection_stack.back().selected_modules.size() != 1 || design->selection_stack.back().selected_members.size() != 0 ||
+ design->selection_stack.back().selected_modules.count(design->selected_active_module) == 0)
+ str += "*";
+ }
+ snprintf(buffer, 100, "%s> ", str.c_str());
+ return buffer;
+}
+
+#ifdef YOSYS_ENABLE_TCL
+static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
+{
+ std::vector<std::string> args;
+ for (int i = 1; i < argc; i++)
+ args.push_back(argv[i]);
+
+ if (args.size() >= 1 && args[0] == "-import") {
+ for (auto &it : pass_register) {
+ std::string tcl_command_name = it.first;
+ if (tcl_command_name == "proc")
+ tcl_command_name = "procs";
+ Tcl_CmdInfo info;
+ if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) {
+ log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str());
+ } else {
+ std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str());
+ Tcl_Eval(interp, tcl_script.c_str());
+ }
+ }
+ return TCL_OK;
+ }
+
+ if (args.size() == 1) {
+ Pass::call(yosys_get_design(), args[0]);
+ return TCL_OK;
+ }
+
+ Pass::call(yosys_get_design(), args);
+ return TCL_OK;
+}
+
+extern Tcl_Interp *yosys_get_tcl_interp()
+{
+ if (yosys_tcl_interp == NULL) {
+ yosys_tcl_interp = Tcl_CreateInterp();
+ Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL);
+ }
+ return yosys_tcl_interp;
+}
+
+struct TclPass : public Pass {
+ TclPass() : Pass("tcl", "execute a TCL script file") { }
+ virtual void help() {
+ log("\n");
+ log(" tcl <filename>\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");
+ log("\n");
+ log("The tcl command 'yosys -import' can be used to import all yosys\n");
+ log("commands directly as tcl commands to the tcl shell. The yosys\n");
+ log("command 'proc' is wrapped using the tcl command 'procs' in order\n");
+ log("to avoid a name collision with the tcl builting command 'proc'.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ 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()));
+ }
+} TclPass;
+#endif
+
+#if defined(__linux__)
+std::string proc_self_dirname ()
+{
+ char path [PATH_MAX];
+ ssize_t buflen = readlink("/proc/self/exe", path, sizeof(path));
+ if (buflen < 0) {
+ log_error("readlink(\"/proc/self/exe\") failed: %s\n", strerror(errno));
+ }
+ while (buflen > 0 && path[buflen-1] != '/')
+ buflen--;
+ return std::string(path, buflen);
+}
+#elif defined(__APPLE__)
+#include <mach-o/dyld.h>
+std::string proc_self_dirname ()
+{
+ char * path = NULL;
+ uint32_t buflen = 0;
+ while (_NSGetExecutablePath(path, &buflen) != 0)
+ path = (char *) realloc((void *) path, buflen);
+ while (buflen > 0 && path[buflen-1] != '/')
+ buflen--;
+ return std::string(path, buflen);
+}
+#elif defined(EMSCRIPTEN)
+std::string proc_self_dirname ()
+{
+ return "/";
+}
+#else
+ #error Dont know how to determine process executable base path!
+#endif
+
+std::string proc_share_dirname ()
+{
+ std::string proc_self_path = proc_self_dirname();
+ std::string proc_share_path = proc_self_path + "share/";
+ if (access(proc_share_path.c_str(), X_OK) == 0)
+ return proc_share_path;
+ proc_share_path = proc_self_path + "../share/yosys/";
+ if (access(proc_share_path.c_str(), X_OK) == 0)
+ return proc_share_path;
+ log_error("proc_share_dirname: unable to determine share/ directory!\n");
+}
+
+bool fgetline(FILE *f, std::string &buffer)
+{
+ buffer = "";
+ char block[4096];
+ while (1) {
+ if (fgets(block, 4096, f) == NULL)
+ return false;
+ buffer += block;
+ if (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) {
+ while (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r'))
+ buffer.resize(buffer.size()-1);
+ return true;
+ }
+ }
+}
+
+static void handle_label(std::string &command, bool &from_to_active, const std::string &run_from, const std::string &run_to)
+{
+ int pos = 0;
+ std::string label;
+
+ while (pos < SIZE(command) && (command[pos] == ' ' || command[pos] == '\t'))
+ pos++;
+
+ while (pos < SIZE(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
+ label += command[pos++];
+
+ if (label.back() == ':' && SIZE(label) > 1)
+ {
+ label = label.substr(0, SIZE(label)-1);
+ command = command.substr(pos);
+
+ if (label == run_from)
+ from_to_active = true;
+ else if (label == run_to || (run_from == run_to && !run_from.empty()))
+ from_to_active = false;
+ }
+}
+
+void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label)
+{
+ if (command == "auto") {
+ if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
+ command = "verilog";
+ else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv")
+ command = "verilog -sv";
+ else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
+ command = "ilang";
+ else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
+ command = "script";
+ else if (filename == "-")
+ command = "script";
+ else
+ log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str());
+ }
+
+ if (command == "script")
+ {
+ std::string run_from, run_to;
+ bool from_to_active = true;
+
+ if (from_to_label != NULL) {
+ size_t pos = from_to_label->find(':');
+ if (pos == std::string::npos) {
+ run_from = *from_to_label;
+ run_to = *from_to_label;
+ } else {
+ run_from = from_to_label->substr(0, pos);
+ run_to = from_to_label->substr(pos+1);
+ }
+ from_to_active = run_from.empty();
+ }
+
+ log("\n-- Executing script file `%s' --\n", filename.c_str());
+
+ FILE *f = stdin;
+
+ if (filename != "-")
+ f = fopen(filename.c_str(), "r");
+
+ if (f == NULL)
+ log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
+
+ FILE *backup_script_file = Frontend::current_script_file;
+ Frontend::current_script_file = f;
+
+ try {
+ std::string command;
+ while (fgetline(f, command)) {
+ while (!command.empty() && command[command.size()-1] == '\\') {
+ std::string next_line;
+ if (!fgetline(f, next_line))
+ break;
+ command.resize(command.size()-1);
+ command += next_line;
+ }
+ handle_label(command, from_to_active, run_from, run_to);
+ if (from_to_active)
+ Pass::call(design, command);
+ }
+
+ if (!command.empty()) {
+ handle_label(command, from_to_active, run_from, run_to);
+ if (from_to_active)
+ Pass::call(design, command);
+ }
+ }
+ catch (log_cmd_error_expection) {
+ Frontend::current_script_file = backup_script_file;
+ throw log_cmd_error_expection();
+ }
+
+ Frontend::current_script_file = backup_script_file;
+
+ if (filename != "-")
+ fclose(f);
+
+ if (backend_command != NULL && *backend_command == "auto")
+ *backend_command = "";
+
+ return;
+ }
+
+ if (filename == "-") {
+ log("\n-- Parsing stdin using frontend `%s' --\n", command.c_str());
+ } else {
+ log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
+ }
+
+ Frontend::frontend_call(design, NULL, filename, command);
+}
+
+void run_pass(std::string command, RTLIL::Design *design)
+{
+ log("\n-- Running pass `%s' --\n", command.c_str());
+
+ Pass::call(design, command);
+}
+
+void run_backend(std::string filename, std::string command, RTLIL::Design *design)
+{
+ if (command == "auto") {
+ if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
+ command = "verilog";
+ else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
+ command = "ilang";
+ else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif")
+ command = "blif";
+ else if (filename == "-")
+ command = "ilang";
+ else if (filename.empty())
+ return;
+ else
+ log_error("Can't guess backend for output file `%s' (missing -b option)!\n", filename.c_str());
+ }
+
+ if (filename.empty())
+ filename = "-";
+
+ if (filename == "-") {
+ log("\n-- Writing to stdout using backend `%s' --\n", command.c_str());
+ } else {
+ log("\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str());
+ }
+
+ Backend::backend_call(design, NULL, filename, command);
+}
+
+#ifdef YOSYS_ENABLE_READLINE
+static char *readline_cmd_generator(const char *text, int state)
+{
+ static std::map<std::string, Pass*>::iterator it;
+ static int len;
+
+ if (!state) {
+ it = pass_register.begin();
+ len = strlen(text);
+ }
+
+ for (; it != pass_register.end(); it++) {
+ if (it->first.substr(0, len) == text)
+ return strdup((it++)->first.c_str());
+ }
+ return NULL;
+}
+
+static char *readline_obj_generator(const char *text, int state)
+{
+ static std::vector<char*> obj_names;
+ static size_t idx;
+
+ if (!state)
+ {
+ idx = 0;
+ obj_names.clear();
+
+ RTLIL::Design *design = yosys_get_design();
+ int len = strlen(text);
+
+ if (design->selected_active_module.empty())
+ {
+ for (auto &it : design->modules_)
+ if (RTLIL::unescape_id(it.first).substr(0, len) == text)
+ obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
+ }
+ else
+ if (design->modules_.count(design->selected_active_module) > 0)
+ {
+ RTLIL::Module *module = design->modules_.at(design->selected_active_module);
+
+ for (auto &it : module->wires_)
+ if (RTLIL::unescape_id(it.first).substr(0, len) == text)
+ obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
+
+ for (auto &it : module->memories)
+ if (RTLIL::unescape_id(it.first).substr(0, len) == text)
+ obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
+
+ for (auto &it : module->cells_)
+ if (RTLIL::unescape_id(it.first).substr(0, len) == text)
+ obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
+
+ for (auto &it : module->processes)
+ if (RTLIL::unescape_id(it.first).substr(0, len) == text)
+ obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
+ }
+
+ std::sort(obj_names.begin(), obj_names.end());
+ }
+
+ if (idx < obj_names.size())
+ return strdup(obj_names[idx++]);
+
+ idx = 0;
+ obj_names.clear();
+ return NULL;
+}
+
+static char **readline_completion(const char *text, int start, int)
+{
+ if (start == 0)
+ return rl_completion_matches(text, readline_cmd_generator);
+ if (strncmp(rl_line_buffer, "read_", 5) && strncmp(rl_line_buffer, "write_", 6))
+ return rl_completion_matches(text, readline_obj_generator);
+ return NULL;
+}
+#endif
+
+void shell(RTLIL::Design *design)
+{
+ static int recursion_counter = 0;
+
+ recursion_counter++;
+ log_cmd_error_throw = true;
+
+#ifdef YOSYS_ENABLE_READLINE
+ rl_readline_name = "yosys";
+ rl_attempted_completion_function = readline_completion;
+ rl_basic_word_break_characters = " \t\n";
+#endif
+
+ char *command = NULL;
+#ifdef YOSYS_ENABLE_READLINE
+ while ((command = readline(create_prompt(design, recursion_counter))) != NULL)
+#else
+ char command_buffer[4096];
+ while ((command = fgets(command_buffer, 4096, stdin)) != NULL)
+#endif
+ {
+ if (command[strspn(command, " \t\r\n")] == 0)
+ continue;
+#ifdef YOSYS_ENABLE_READLINE
+ add_history(command);
+#endif
+
+ char *p = command + strspn(command, " \t\r\n");
+ if (!strncmp(p, "exit", 4)) {
+ p += 4;
+ p += strspn(p, " \t\r\n");
+ if (*p == 0)
+ break;
+ }
+
+ try {
+ log_assert(design->selection_stack.size() == 1);
+ Pass::call(design, command);
+ } catch (log_cmd_error_expection) {
+ while (design->selection_stack.size() > 1)
+ design->selection_stack.pop_back();
+ log_reset_stack();
+ }
+ }
+ if (command == NULL)
+ printf("exit\n");
+
+ recursion_counter--;
+ log_cmd_error_throw = false;
+}
+
+struct ShellPass : public Pass {
+ ShellPass() : Pass("shell", "enter interactive command mode") { }
+ virtual void help() {
+ log("\n");
+ log(" shell\n");
+ log("\n");
+ log("This command enters the interactive command mode. This can be useful\n");
+ log("in a script to interrupt the script at a certain point and allow for\n");
+ log("interactive inspection or manual synthesis of the design at this point.\n");
+ log("\n");
+ log("The command prompt of the interactive shell indicates the current\n");
+ log("selection (see 'help select'):\n");
+ log("\n");
+ log(" yosys>\n");
+ log(" the entire design is selected\n");
+ log("\n");
+ log(" yosys*>\n");
+ log(" only part of the design is selected\n");
+ log("\n");
+ log(" yosys [modname]>\n");
+ log(" the entire module 'modname' is selected using 'select -module modname'\n");
+ log("\n");
+ log(" yosys [modname]*>\n");
+ log(" only part of current module 'modname' is selected\n");
+ log("\n");
+ log("When in interactive shell, some errors (e.g. invalid command arguments)\n");
+ log("do not terminate yosys but return to the command prompt.\n");
+ log("\n");
+ log("This command is the default action if nothing else has been specified\n");
+ log("on the command line.\n");
+ log("\n");
+ log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ extra_args(args, 1, design, false);
+ shell(design);
+ }
+} ShellPass;
+
+#ifdef YOSYS_ENABLE_READLINE
+struct HistoryPass : public Pass {
+ HistoryPass() : Pass("history", "show last interactive commands") { }
+ virtual void help() {
+ log("\n");
+ log(" history\n");
+ log("\n");
+ log("This command prints all commands in the shell history buffer. This are\n");
+ log("all commands executed in an interactive session, but not the commands\n");
+ log("from executed scripts.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ extra_args(args, 1, design, false);
+ for(HIST_ENTRY **list = history_list(); *list != NULL; list++)
+ log("%s\n", (*list)->line);
+ }
+} HistoryPass;
+#endif
+
+struct ScriptPass : public Pass {
+ ScriptPass() : Pass("script", "execute commands from script file") { }
+ virtual void help() {
+ log("\n");
+ log(" script <filename> [<from_label>:<to_label>]\n");
+ log("\n");
+ log("This command executes the yosys commands in the specified file.\n");
+ log("\n");
+ log("The 2nd argument can be used to only execute the section of the\n");
+ log("file between the specified labels. An empty from label is synonymous\n");
+ log("for the beginning of the file and an empty to label is synonymous\n");
+ log("for the end of the file.\n");
+ log("\n");
+ log("If only one label is specified (without ':') then only the block\n");
+ log("marked with that label (until the next label) is executed.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ if (args.size() < 2)
+ log_cmd_error("Missing script file.\n");
+ else if (args.size() == 2)
+ run_frontend(args[1], "script", design, NULL, NULL);
+ else if (args.size() == 3)
+ run_frontend(args[1], "script", design, NULL, &args[2]);
+ else
+ extra_args(args, 2, design, false);
+ }
+} ScriptPass;
+
+YOSYS_NAMESPACE_END
+
diff --git a/kernel/yosys.h b/kernel/yosys.h
new file mode 100644
index 00000000..b571e177
--- /dev/null
+++ b/kernel/yosys.h
@@ -0,0 +1,149 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+
+// *** NOTE TO THE READER ***
+//
+// Maybe you have just opened this file in the hope to learn more about the
+// Yosys API. Let me congratulate you on this great decision! ;)
+//
+// If you want to know how the design is represented by Yosys in the memory,
+// you should read "kernel/rtlil.h".
+//
+// If you want to know how to register a command with Yosys, you could read
+// "kernel/register.h", but it would be easier to just look at a simple
+// example instead. A simple one would be "passes/cmds/log.cc".
+//
+// This header is very boring. It just defines some general things that
+// belong nowhere else and includes the interesting headers.
+//
+// Find more information in the "CodingReadme" file.
+
+
+#ifndef YOSYS_H
+#define YOSYS_H
+
+#include <map>
+#include <set>
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <functional>
+#include <initializer_list>
+
+#include <sstream>
+#include <fstream>
+#include <istream>
+#include <ostream>
+#include <iostream>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#define PRIVATE_NAMESPACE_BEGIN namespace {
+#define PRIVATE_NAMESPACE_END }
+
+#if 0
+# define YOSYS_NAMESPACE_BEGIN namespace Yosys {
+# define YOSYS_NAMESPACE_END }
+# define YOSYS_NAMESPACE_PREFIX Yosys::
+# define USING_YOSYS_NAMESPACE using namespace Yosys;
+#else
+# define YOSYS_NAMESPACE_BEGIN
+# define YOSYS_NAMESPACE_END
+# define YOSYS_NAMESPACE_PREFIX
+# define USING_YOSYS_NAMESPACE
+#endif
+
+#if __cplusplus >= 201103L
+# define OVERRIDE override
+# define FINAL final
+#else
+# define OVERRIDE
+# define FINAL
+#endif
+
+YOSYS_NAMESPACE_BEGIN
+
+namespace RTLIL {
+ struct IdString;
+ struct SigSpec;
+ struct Wire;
+ struct Cell;
+}
+
+std::string stringf(const char *fmt, ...);
+std::string vstringf(const char *fmt, va_list ap);
+template<typename T> int SIZE(const T &obj) { return obj.size(); }
+int SIZE(RTLIL::Wire *wire);
+
+YOSYS_NAMESPACE_END
+
+#include "kernel/log.h"
+#include "kernel/rtlil.h"
+#include "kernel/register.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+void yosys_setup();
+void yosys_shutdown();
+
+#ifdef YOSYS_ENABLE_TCL
+#include <tcl.h>
+Tcl_Interp *yosys_get_tcl_interp();
+#endif
+
+extern int autoidx;
+extern RTLIL::Design *yosys_design;
+
+RTLIL::IdString new_id(std::string file, int line, std::string func);
+
+#define NEW_ID \
+ YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__)
+
+#define ID(_str) \
+ ([]() { static YOSYS_NAMESPACE_PREFIX RTLIL::IdString _id(_str); return _id; })()
+
+RTLIL::Design *yosys_get_design();
+std::string proc_self_dirname();
+std::string proc_share_dirname();
+const char *create_prompt(RTLIL::Design *design, int recursion_counter);
+
+void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label);
+void run_pass(std::string command, RTLIL::Design *design);
+void run_backend(std::string filename, std::string command, RTLIL::Design *design);
+void shell(RTLIL::Design *design);
+
+// from kernel/version_*.o (cc source generated from Makefile)
+extern const char *yosys_version_str;
+
+// from passes/cmds/design.cc
+extern std::map<std::string, RTLIL::Design*> saved_designs;
+extern std::vector<RTLIL::Design*> pushed_designs;
+
+// from passes/cmds/pluginc.cc
+extern std::map<std::string, void*> loaded_plugins;
+extern std::map<std::string, std::string> loaded_plugin_aliases;
+void load_plugin(std::string filename, std::vector<std::string> aliases);
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/libs/ezsat/Makefile b/libs/ezsat/Makefile
index da2355a9..b1f86416 100644
--- a/libs/ezsat/Makefile
+++ b/libs/ezsat/Makefile
@@ -3,7 +3,8 @@ CC = clang
CXX = clang
CXXFLAGS = -MD -Wall -Wextra -ggdb
CXXFLAGS += -std=c++11 -O0
-LDLIBS = -lminisat -lstdc++
+LDLIBS = ../minisat/Options.cc ../minisat/SimpSolver.cc ../minisat/Solver.cc ../minisat/System.cc -lm -lstdc++
+
all: demo_vec demo_bit demo_cmp testbench puzzle3d
@@ -17,10 +18,11 @@ test: all
./testbench
./demo_bit
./demo_vec
- ./demo_cmp
+ # ./demo_cmp
+ # ./puzzle3d
clean:
- rm -f demo_bit demo_vec testbench puzzle3d *.o *.d
+ rm -f demo_bit demo_vec demo_cmp testbench puzzle3d *.o *.d
.PHONY: all test clean
diff --git a/libs/ezsat/ezminisat.cc b/libs/ezsat/ezminisat.cc
index d545834c..dc4e5d28 100644
--- a/libs/ezsat/ezminisat.cc
+++ b/libs/ezsat/ezminisat.cc
@@ -25,15 +25,20 @@
#include <limits.h>
#include <stdint.h>
-#include <signal.h>
+#include <csignal>
#include <cinttypes>
+#include <unistd.h>
-#include <minisat/core/Solver.h>
+#include "../minisat/Solver.h"
+#include "../minisat/SimpSolver.h"
ezMiniSAT::ezMiniSAT() : minisatSolver(NULL)
{
minisatSolver = NULL;
foundContradiction = false;
+
+ freeze(TRUE);
+ freeze(FALSE);
}
ezMiniSAT::~ezMiniSAT()
@@ -50,9 +55,28 @@ void ezMiniSAT::clear()
}
foundContradiction = false;
minisatVars.clear();
+#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL
+ cnfFrozenVars.clear();
+#endif
ezSAT::clear();
}
+#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL
+void ezMiniSAT::freeze(int id)
+{
+ if (!mode_non_incremental())
+ cnfFrozenVars.insert(bind(id));
+}
+
+bool ezMiniSAT::eliminated(int idx)
+{
+ idx = idx < 0 ? -idx : idx;
+ if (minisatSolver != NULL && idx > 0 && idx <= int(minisatVars.size()))
+ return minisatSolver->isEliminated(minisatVars.at(idx-1));
+ return false;
+}
+#endif
+
ezMiniSAT *ezMiniSAT::alarmHandlerThis = NULL;
clock_t ezMiniSAT::alarmHandlerTimeout = 0;
@@ -67,6 +91,8 @@ void ezMiniSAT::alarmHandler(int)
bool ezMiniSAT::solver(const std::vector<int> &modelExpressions, std::vector<bool> &modelValues, const std::vector<int> &assumptions)
{
+ preSolverCallback();
+
solverTimoutStatus = false;
if (0) {
@@ -90,22 +116,42 @@ contradiction:
for (auto id : modelExpressions)
modelIdx.push_back(bind(id));
- if (minisatSolver == NULL)
- minisatSolver = new Minisat::Solver;
+ if (minisatSolver == NULL) {
+ minisatSolver = new Solver;
+ minisatSolver->verbosity = EZMINISAT_VERBOSITY;
+ }
+#if EZMINISAT_INCREMENTAL
std::vector<std::vector<int>> cnf;
consumeCnf(cnf);
+#else
+ const std::vector<std::vector<int>> &cnf = this->cnf();
+#endif
while (int(minisatVars.size()) < numCnfVariables())
minisatVars.push_back(minisatSolver->newVar());
+#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL
+ for (auto idx : cnfFrozenVars)
+ minisatSolver->setFrozen(minisatVars.at(idx > 0 ? idx-1 : -idx-1), true);
+ cnfFrozenVars.clear();
+#endif
+
for (auto &clause : cnf) {
Minisat::vec<Minisat::Lit> ps;
- for (auto idx : clause)
+ for (auto idx : clause) {
if (idx > 0)
ps.push(Minisat::mkLit(minisatVars.at(idx-1)));
else
ps.push(Minisat::mkLit(minisatVars.at(-idx-1), true));
+#if EZMINISAT_SIMPSOLVER
+ if (minisatSolver->isEliminated(minisatVars.at(idx > 0 ? idx-1 : -idx-1))) {
+ fprintf(stderr, "Assert in %s:%d failed! Missing call to ezsat->freeze(): %s (lit=%d)\n",
+ __FILE__, __LINE__, cnfLiteralInfo(idx).c_str(), idx);
+ abort();
+ }
+#endif
+ }
if (!minisatSolver->addClause(ps))
goto contradiction;
}
@@ -115,20 +161,31 @@ contradiction:
Minisat::vec<Minisat::Lit> assumps;
- for (auto idx : extraClauses)
+ for (auto idx : extraClauses) {
if (idx > 0)
assumps.push(Minisat::mkLit(minisatVars.at(idx-1)));
else
assumps.push(Minisat::mkLit(minisatVars.at(-idx-1), true));
+#if EZMINISAT_SIMPSOLVER
+ if (minisatSolver->isEliminated(minisatVars.at(idx > 0 ? idx-1 : -idx-1))) {
+ fprintf(stderr, "Assert in %s:%d failed! Missing call to ezsat->freeze(): %s\n", __FILE__, __LINE__, cnfLiteralInfo(idx).c_str());
+ abort();
+ }
+#endif
+ }
- sighandler_t old_alarm_sighandler = NULL;
+ struct sigaction sig_action;
+ struct sigaction old_sig_action;
int old_alarm_timeout = 0;
if (solverTimeout > 0) {
+ sig_action.sa_handler = alarmHandler;
+ sigemptyset(&sig_action.sa_mask);
+ sig_action.sa_flags = SA_RESTART;
alarmHandlerThis = this;
alarmHandlerTimeout = clock() + solverTimeout*CLOCKS_PER_SEC;
old_alarm_timeout = alarm(0);
- old_alarm_sighandler = signal(SIGALRM, alarmHandler);
+ sigaction(SIGALRM, &sig_action, &old_sig_action);
alarm(1);
}
@@ -138,12 +195,18 @@ contradiction:
if (alarmHandlerTimeout == 0)
solverTimoutStatus = true;
alarm(0);
- signal(SIGALRM, old_alarm_sighandler);
+ sigaction(SIGALRM, &old_sig_action, NULL);
alarm(old_alarm_timeout);
}
- if (!foundSolution)
+ if (!foundSolution) {
+#if !EZMINISAT_INCREMENTAL
+ delete minisatSolver;
+ minisatSolver = NULL;
+ minisatVars.clear();
+#endif
return false;
+ }
modelValues.clear();
modelValues.resize(modelIdx.size());
@@ -161,6 +224,11 @@ contradiction:
modelValues[i] = (value == Minisat::lbool(refvalue));
}
+#if !EZMINISAT_INCREMENTAL
+ delete minisatSolver;
+ minisatSolver = NULL;
+ minisatVars.clear();
+#endif
return true;
}
diff --git a/libs/ezsat/ezminisat.h b/libs/ezsat/ezminisat.h
index 2919aa2e..ac9c071c 100644
--- a/libs/ezsat/ezminisat.h
+++ b/libs/ezsat/ezminisat.h
@@ -20,6 +20,10 @@
#ifndef EZMINISAT_H
#define EZMINISAT_H
+#define EZMINISAT_SIMPSOLVER 1
+#define EZMINISAT_VERBOSITY 0
+#define EZMINISAT_INCREMENTAL 1
+
#include "ezsat.h"
#include <time.h>
@@ -28,15 +32,25 @@
// don't force ezSAT users to use minisat headers..
namespace Minisat {
class Solver;
+ class SimpSolver;
}
class ezMiniSAT : public ezSAT
{
private:
- Minisat::Solver *minisatSolver;
+#if EZMINISAT_SIMPSOLVER
+ typedef Minisat::SimpSolver Solver;
+#else
+ typedef Minisat::Solver Solver;
+#endif
+ Solver *minisatSolver;
std::vector<int> minisatVars;
bool foundContradiction;
+#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL
+ std::set<int> cnfFrozenVars;
+#endif
+
static ezMiniSAT *alarmHandlerThis;
static clock_t alarmHandlerTimeout;
static void alarmHandler(int);
@@ -45,6 +59,10 @@ public:
ezMiniSAT();
virtual ~ezMiniSAT();
virtual void clear();
+#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL
+ virtual void freeze(int id);
+ virtual bool eliminated(int idx);
+#endif
virtual bool solver(const std::vector<int> &modelExpressions, std::vector<bool> &modelValues, const std::vector<int> &assumptions);
};
diff --git a/libs/ezsat/ezsat.cc b/libs/ezsat/ezsat.cc
index dccc0055..13ed112e 100644
--- a/libs/ezsat/ezsat.cc
+++ b/libs/ezsat/ezsat.cc
@@ -19,21 +19,21 @@
#include "ezsat.h"
+#include <cmath>
#include <algorithm>
+#include <cassert>
#include <stdlib.h>
-#include <assert.h>
const int ezSAT::TRUE = 1;
const int ezSAT::FALSE = 2;
ezSAT::ezSAT()
{
- literal("TRUE");
- literal("FALSE");
+ flag_keep_cnf = false;
+ flag_non_incremental = false;
- assert(literal("TRUE") == TRUE);
- assert(literal("FALSE") == FALSE);
+ non_incremental_solve_used_up = false;
cnfConsumed = false;
cnfVariableCount = 0;
@@ -41,6 +41,12 @@ ezSAT::ezSAT()
solverTimeout = 0;
solverTimoutStatus = false;
+
+ literal("TRUE");
+ literal("FALSE");
+
+ assert(literal("TRUE") == TRUE);
+ assert(literal("FALSE") == FALSE);
}
ezSAT::~ezSAT()
@@ -67,6 +73,20 @@ int ezSAT::literal(const std::string &name)
return literalsCache.at(name);
}
+int ezSAT::frozen_literal()
+{
+ int id = literal();
+ freeze(id);
+ return id;
+}
+
+int ezSAT::frozen_literal(const std::string &name)
+{
+ int id = literal(name);
+ freeze(id);
+ return id;
+}
+
int ezSAT::expression(OpId op, int a, int b, int c, int d, int e, int f)
{
std::vector<int> args(6);
@@ -342,13 +362,19 @@ void ezSAT::clear()
cnfLiteralVariables.clear();
cnfExpressionVariables.clear();
cnfClauses.clear();
- cnfAssumptions.clear();
}
-void ezSAT::assume(int id)
+void ezSAT::freeze(int)
+{
+}
+
+bool ezSAT::eliminated(int)
{
- cnfAssumptions.insert(id);
+ return false;
+}
+void ezSAT::assume(int id)
+{
if (id < 0)
{
assert(0 < -id && -id <= int(expressions.size()));
@@ -462,11 +488,32 @@ int ezSAT::bound(int id) const
return 0;
}
-int ezSAT::bind(int id)
+std::string ezSAT::cnfLiteralInfo(int idx) const
+{
+ for (size_t i = 0; i < cnfLiteralVariables.size(); i++) {
+ if (cnfLiteralVariables[i] == idx)
+ return to_string(i+1);
+ if (cnfLiteralVariables[i] == -idx)
+ return "NOT " + to_string(i+1);
+ }
+ for (size_t i = 0; i < cnfExpressionVariables.size(); i++) {
+ if (cnfExpressionVariables[i] == idx)
+ return to_string(-i-1);
+ if (cnfExpressionVariables[i] == -idx)
+ return "NOT " + to_string(-i-1);
+ }
+ return "<unnamed>";
+}
+
+int ezSAT::bind(int id, bool auto_freeze)
{
if (id >= 0) {
assert(0 < id && id <= int(literals.size()));
cnfLiteralVariables.resize(literals.size());
+ if (eliminated(cnfLiteralVariables[id-1])) {
+ fprintf(stderr, "ezSAT: Missing freeze on literal `%s'.\n", to_string(id).c_str());
+ abort();
+ }
if (cnfLiteralVariables[id-1] == 0) {
cnfLiteralVariables[id-1] = ++cnfVariableCount;
if (id == TRUE)
@@ -480,6 +527,17 @@ int ezSAT::bind(int id)
assert(0 < -id && -id <= int(expressions.size()));
cnfExpressionVariables.resize(expressions.size());
+ if (eliminated(cnfExpressionVariables[-id-1]))
+ {
+ cnfExpressionVariables[-id-1] = 0;
+
+ // this will recursively call bind(id). within the recursion
+ // the cnf is pre-set to 0. an idx is allocated there, then it
+ // is frozen, then it returns here with the new idx already set.
+ if (auto_freeze)
+ freeze(id);
+ }
+
if (cnfExpressionVariables[-id-1] == 0)
{
OpId op;
@@ -497,7 +555,7 @@ int ezSAT::bind(int id)
newArgs.push_back(OR(AND(args[i], NOT(args[i+1])), AND(NOT(args[i]), args[i+1])));
args.swap(newArgs);
}
- idx = bind(args.at(0));
+ idx = bind(args.at(0), false);
goto assign_idx;
}
@@ -505,17 +563,17 @@ int ezSAT::bind(int id)
std::vector<int> invArgs;
for (auto arg : args)
invArgs.push_back(NOT(arg));
- idx = bind(OR(expression(OpAnd, args), expression(OpAnd, invArgs)));
+ idx = bind(OR(expression(OpAnd, args), expression(OpAnd, invArgs)), false);
goto assign_idx;
}
if (op == OpITE) {
- idx = bind(OR(AND(args[0], args[1]), AND(NOT(args[0]), args[2])));
+ idx = bind(OR(AND(args[0], args[1]), AND(NOT(args[0]), args[2])), false);
goto assign_idx;
}
for (int i = 0; i < int(args.size()); i++)
- args[i] = bind(args[i]);
+ args[i] = bind(args[i], false);
switch (op)
{
@@ -535,120 +593,45 @@ int ezSAT::bind(int id)
void ezSAT::consumeCnf()
{
- cnfConsumed = true;
+ if (mode_keep_cnf())
+ cnfClausesBackup.insert(cnfClausesBackup.end(), cnfClauses.begin(), cnfClauses.end());
+ else
+ cnfConsumed = true;
cnfClauses.clear();
}
void ezSAT::consumeCnf(std::vector<std::vector<int>> &cnf)
{
- cnfConsumed = true;
+ if (mode_keep_cnf())
+ cnfClausesBackup.insert(cnfClausesBackup.end(), cnfClauses.begin(), cnfClauses.end());
+ else
+ cnfConsumed = true;
cnf.swap(cnfClauses);
cnfClauses.clear();
}
-static bool test_bit(uint32_t bitmask, int idx)
+void ezSAT::getFullCnf(std::vector<std::vector<int>> &full_cnf) const
{
- if (idx > 0)
- return (bitmask & (1 << (+idx-1))) != 0;
- else
- return (bitmask & (1 << (-idx-1))) == 0;
+ assert(full_cnf.empty());
+ full_cnf.insert(full_cnf.end(), cnfClausesBackup.begin(), cnfClausesBackup.end());
+ full_cnf.insert(full_cnf.end(), cnfClauses.begin(), cnfClauses.end());
}
-bool ezSAT::solver(const std::vector<int> &modelExpressions, std::vector<bool> &modelValues, const std::vector<int> &assumptions)
+void ezSAT::preSolverCallback()
{
- std::vector<int> extraClauses, modelIdx;
- std::vector<int> values(numLiterals());
-
- for (auto id : assumptions)
- extraClauses.push_back(bind(id));
- for (auto id : modelExpressions)
- modelIdx.push_back(bind(id));
-
- if (cnfVariableCount > 20) {
- fprintf(stderr, "*************************************************************************************\n");
- fprintf(stderr, "ERROR: You are trying to use the builtin solver of ezSAT with more than 20 variables!\n");
- fprintf(stderr, "The builtin solver is a dumb brute force solver and only ment for testing and demo\n");
- fprintf(stderr, "purposes. Use a real SAT solve like MiniSAT (e.g. using the ezMiniSAT class) instead.\n");
- fprintf(stderr, "*************************************************************************************\n");
- abort();
- }
-
- for (uint32_t bitmask = 0; bitmask < (1 << numCnfVariables()); bitmask++)
- {
- // printf("%07o:", int(bitmask));
- // for (int i = 2; i < numLiterals(); i++)
- // if (bound(i+1))
- // printf(" %s=%d", to_string(i+1).c_str(), test_bit(bitmask, bound(i+1)));
- // printf(" |");
- // for (int idx = 1; idx <= numCnfVariables(); idx++)
- // printf(" %3d", test_bit(bitmask, idx) ? idx : -idx);
- // printf("\n");
-
- for (auto idx : extraClauses)
- if (!test_bit(bitmask, idx))
- goto next;
-
- for (auto &clause : cnfClauses) {
- for (auto idx : clause)
- if (test_bit(bitmask, idx))
- goto next_clause;
- // printf("failed clause:");
- // for (auto idx2 : clause)
- // printf(" %3d", idx2);
- // printf("\n");
- goto next;
- next_clause:;
- // printf("passed clause:");
- // for (auto idx2 : clause)
- // printf(" %3d", idx2);
- // printf("\n");
- }
-
- modelValues.resize(modelIdx.size());
- for (int i = 0; i < int(modelIdx.size()); i++)
- modelValues[i] = test_bit(bitmask, modelIdx[i]);
-
- // validate result using eval()
-
- values[0] = TRUE, values[1] = FALSE;
- for (int i = 2; i < numLiterals(); i++) {
- int idx = bound(i+1);
- values[i] = idx != 0 ? (test_bit(bitmask, idx) ? TRUE : FALSE) : 0;
- }
-
- for (auto id : cnfAssumptions) {
- int result = eval(id, values);
- if (result != TRUE) {
- printInternalState(stderr);
- fprintf(stderr, "Variables:");
- for (int i = 0; i < numLiterals(); i++)
- fprintf(stderr, " %s=%s", lookup_literal(i+1).c_str(), values[i] == TRUE ? "TRUE" : values[i] == FALSE ? "FALSE" : "UNDEF");
- fprintf(stderr, "\nValidation of solver results failed: got `%d' (%s) for assumption '%d': %s\n",
- result, result == FALSE ? "FALSE" : "UNDEF", id, to_string(id).c_str());
- abort();
- }
- // printf("OK: %d -> %d\n", id, result);
- }
-
- for (auto id : assumptions) {
- int result = eval(id, values);
- if (result != TRUE) {
- printInternalState(stderr);
- fprintf(stderr, "Variables:");
- for (int i = 0; i < numLiterals(); i++)
- fprintf(stderr, " %s=%s", lookup_literal(i+1).c_str(), values[i] == TRUE ? "TRUE" : values[i] == FALSE ? "FALSE" : "UNDEF");
- fprintf(stderr, "\nValidation of solver results failed: got `%d' (%s) for assumption '%d': %s\n",
- result, result == FALSE ? "FALSE" : "UNDEF", id, to_string(id).c_str());
- abort();
- }
- // printf("OK: %d -> %d\n", id, result);
- }
-
- return true;
- next:;
- }
+ assert(!non_incremental_solve_used_up);
+ if (mode_non_incremental())
+ non_incremental_solve_used_up = true;
+}
- return false;
+bool ezSAT::solver(const std::vector<int>&, std::vector<bool>&, const std::vector<int>&)
+{
+ preSolverCallback();
+ fprintf(stderr, "************************************************************************\n");
+ fprintf(stderr, "ERROR: You are trying to use the solve() method of the ezSAT base class!\n");
+ fprintf(stderr, "Use a dervied class like ezMiniSAT instead.\n");
+ fprintf(stderr, "************************************************************************\n");
+ abort();
}
std::vector<int> ezSAT::vec_const(const std::vector<bool> &bits)
@@ -994,6 +977,96 @@ std::vector<int> ezSAT::vec_srl(const std::vector<int> &vec1, int shift)
return vec;
}
+std::vector<int> ezSAT::vec_shift(const std::vector<int> &vec1, int shift, int extend_left, int extend_right)
+{
+ std::vector<int> vec;
+ for (int i = 0; i < int(vec1.size()); i++) {
+ int j = i+shift;
+ if (j < 0)
+ vec.push_back(extend_right);
+ else if (j >= int(vec1.size()))
+ vec.push_back(extend_left);
+ else
+ vec.push_back(vec1[j]);
+ }
+ return vec;
+}
+
+static int my_clog2(int x)
+{
+ int result = 0;
+ for (x--; x > 0; result++)
+ x >>= 1;
+ return result;
+}
+
+std::vector<int> ezSAT::vec_shift_right(const std::vector<int> &vec1, const std::vector<int> &vec2, bool vec2_signed, int extend_left, int extend_right)
+{
+ int vec2_bits = std::min(my_clog2(vec1.size()) + (vec2_signed ? 1 : 0), int(vec2.size()));
+
+ std::vector<int> overflow_bits(vec2.begin() + vec2_bits, vec2.end());
+ int overflow_left = FALSE, overflow_right = FALSE;
+
+ if (vec2_signed) {
+ int overflow = FALSE;
+ for (auto bit : overflow_bits)
+ overflow = OR(overflow, XOR(bit, vec2[vec2_bits-1]));
+ overflow_left = AND(overflow, NOT(vec2.back()));
+ overflow_right = AND(overflow, vec2.back());
+ } else
+ overflow_left = vec_reduce_or(overflow_bits);
+
+ std::vector<int> buffer = vec1;
+
+ if (vec2_signed)
+ while (buffer.size() < vec1.size() + (1 << vec2_bits))
+ buffer.push_back(extend_left);
+
+ std::vector<int> overflow_pattern_left(buffer.size(), extend_left);
+ std::vector<int> overflow_pattern_right(buffer.size(), extend_right);
+
+ buffer = vec_ite(overflow_left, overflow_pattern_left, buffer);
+
+ if (vec2_signed)
+ buffer = vec_ite(overflow_right, overflow_pattern_left, buffer);
+
+ for (int i = vec2_bits-1; i >= 0; i--) {
+ std::vector<int> shifted_buffer;
+ if (vec2_signed && i == vec2_bits-1)
+ shifted_buffer = vec_shift(buffer, -(1 << i), extend_left, extend_right);
+ else
+ shifted_buffer = vec_shift(buffer, 1 << i, extend_left, extend_right);
+ buffer = vec_ite(vec2[i], shifted_buffer, buffer);
+ }
+
+ buffer.resize(vec1.size());
+ return buffer;
+}
+
+std::vector<int> ezSAT::vec_shift_left(const std::vector<int> &vec1, const std::vector<int> &vec2, bool vec2_signed, int extend_left, int extend_right)
+{
+ // vec2_signed is not implemented in vec_shift_left() yet
+ assert(vec2_signed == false);
+
+ int vec2_bits = std::min(my_clog2(vec1.size()), int(vec2.size()));
+
+ std::vector<int> overflow_bits(vec2.begin() + vec2_bits, vec2.end());
+ int overflow = vec_reduce_or(overflow_bits);
+
+ std::vector<int> buffer = vec1;
+ std::vector<int> overflow_pattern_right(buffer.size(), extend_right);
+ buffer = vec_ite(overflow, overflow_pattern_right, buffer);
+
+ for (int i = 0; i < vec2_bits; i++) {
+ std::vector<int> shifted_buffer;
+ shifted_buffer = vec_shift(buffer, -(1 << i), extend_left, extend_right);
+ buffer = vec_ite(vec2[i], shifted_buffer, buffer);
+ }
+
+ buffer.resize(vec1.size());
+ return buffer;
+}
+
void ezSAT::vec_append(std::vector<int> &vec, const std::vector<int> &vec1) const
{
for (auto bit : vec1)
@@ -1124,17 +1197,32 @@ void ezSAT::printDIMACS(FILE *f, bool verbose) const
if (cnfExpressionVariables[i] != 0)
fprintf(f, "c %*d: %s\n", digits, cnfExpressionVariables[i], to_string(-i-1).c_str());
+ if (mode_keep_cnf()) {
+ fprintf(f, "c\n");
+ fprintf(f, "c %d clauses from backup, %d from current buffer\n",
+ int(cnfClausesBackup.size()), int(cnfClauses.size()));
+ }
+
fprintf(f, "c\n");
}
- fprintf(f, "p cnf %d %d\n", cnfVariableCount, int(cnfClauses.size()));
+ std::vector<std::vector<int>> all_clauses;
+ getFullCnf(all_clauses);
+ assert(cnfClausesCount == int(all_clauses.size()));
+
+ fprintf(f, "p cnf %d %d\n", cnfVariableCount, cnfClausesCount);
int maxClauseLen = 0;
- for (auto &clause : cnfClauses)
+ for (auto &clause : all_clauses)
maxClauseLen = std::max(int(clause.size()), maxClauseLen);
- for (auto &clause : cnfClauses) {
+ if (!verbose)
+ maxClauseLen = std::min(maxClauseLen, 3);
+ for (auto &clause : all_clauses) {
for (auto idx : clause)
fprintf(f, " %*d", digits, idx);
- fprintf(f, " %*d\n", (digits + 1)*int(maxClauseLen - clause.size()) + digits, 0);
+ if (maxClauseLen >= int(clause.size()))
+ fprintf(f, " %*d\n", (digits + 1)*int(maxClauseLen - clause.size()) + digits, 0);
+ else
+ fprintf(f, " %*d\n", digits, 0);
}
}
diff --git a/libs/ezsat/ezsat.h b/libs/ezsat/ezsat.h
index 547edb93..c5ef6b0a 100644
--- a/libs/ezsat/ezsat.h
+++ b/libs/ezsat/ezsat.h
@@ -48,6 +48,11 @@ public:
static const int FALSE;
private:
+ bool flag_keep_cnf;
+ bool flag_non_incremental;
+
+ bool non_incremental_solve_used_up;
+
std::map<std::string, int> literalsCache;
std::vector<std::string> literals;
@@ -57,8 +62,7 @@ private:
bool cnfConsumed;
int cnfVariableCount, cnfClausesCount;
std::vector<int> cnfLiteralVariables, cnfExpressionVariables;
- std::vector<std::vector<int>> cnfClauses;
- std::set<int> cnfAssumptions;
+ std::vector<std::vector<int>> cnfClauses, cnfClausesBackup;
void add_clause(const std::vector<int> &args);
void add_clause(const std::vector<int> &args, bool argsPolarity, int a = 0, int b = 0, int c = 0);
@@ -68,6 +72,9 @@ private:
int bind_cnf_and(const std::vector<int> &args);
int bind_cnf_or(const std::vector<int> &args);
+protected:
+ void preSolverCallback();
+
public:
int solverTimeout;
bool solverTimoutStatus;
@@ -75,11 +82,19 @@ public:
ezSAT();
virtual ~ezSAT();
+ void keep_cnf() { flag_keep_cnf = true; }
+ void non_incremental() { flag_non_incremental = true; }
+
+ bool mode_keep_cnf() const { return flag_keep_cnf; }
+ bool mode_non_incremental() const { return flag_non_incremental; }
+
// manage expressions
int value(bool val);
int literal();
int literal(const std::string &name);
+ int frozen_literal();
+ int frozen_literal(const std::string &name);
int expression(OpId op, int a = 0, int b = 0, int c = 0, int d = 0, int e = 0, int f = 0);
int expression(OpId op, const std::vector<int> &args);
@@ -141,10 +156,10 @@ public:
// manage CNF (usually only accessed by SAT solvers)
virtual void clear();
+ virtual void freeze(int id);
+ virtual bool eliminated(int idx);
void assume(int id);
- int bind(int id);
-
- const std::set<int> &assumed() const { return cnfAssumptions; }
+ int bind(int id, bool auto_freeze = true);
int bound(int id) const;
int numCnfVariables() const { return cnfVariableCount; }
@@ -154,6 +169,11 @@ public:
void consumeCnf();
void consumeCnf(std::vector<std::vector<int>> &cnf);
+ // use this function to get the full CNF in keep_cnf mode
+ void getFullCnf(std::vector<std::vector<int>> &full_cnf) const;
+
+ std::string cnfLiteralInfo(int idx) const;
+
// simple helpers for build expressions easily
struct _V {
@@ -165,7 +185,7 @@ public:
int get(ezSAT *that) {
if (name.empty())
return id;
- return that->literal(name);
+ return that->frozen_literal(name);
}
};
@@ -217,7 +237,7 @@ public:
std::vector<int> vec_iff(const std::vector<int> &vec1, const std::vector<int> &vec2);
std::vector<int> vec_ite(const std::vector<int> &vec1, const std::vector<int> &vec2, const std::vector<int> &vec3);
- std::vector<int> vec_ite(int sel, const std::vector<int> &vec2, const std::vector<int> &vec3);
+ std::vector<int> vec_ite(int sel, const std::vector<int> &vec1, const std::vector<int> &vec2);
std::vector<int> vec_count(const std::vector<int> &vec, int numBits, bool clip = true);
std::vector<int> vec_add(const std::vector<int> &vec1, const std::vector<int> &vec2);
@@ -245,6 +265,10 @@ public:
std::vector<int> vec_shr(const std::vector<int> &vec1, int shift, bool signExtend = false) { return vec_shl(vec1, -shift, signExtend); }
std::vector<int> vec_srr(const std::vector<int> &vec1, int shift) { return vec_srl(vec1, -shift); }
+ std::vector<int> vec_shift(const std::vector<int> &vec1, int shift, int extend_left, int extend_right);
+ std::vector<int> vec_shift_right(const std::vector<int> &vec1, const std::vector<int> &vec2, bool vec2_signed, int extend_left, int extend_right);
+ std::vector<int> vec_shift_left(const std::vector<int> &vec1, const std::vector<int> &vec2, bool vec2_signed, int extend_left, int extend_right);
+
void vec_append(std::vector<int> &vec, const std::vector<int> &vec1) const;
void vec_append_signed(std::vector<int> &vec, const std::vector<int> &vec1, int64_t value);
void vec_append_unsigned(std::vector<int> &vec, const std::vector<int> &vec1, uint64_t value);
diff --git a/libs/ezsat/puzzle3d.cc b/libs/ezsat/puzzle3d.cc
index 56d29326..aee0044b 100644
--- a/libs/ezsat/puzzle3d.cc
+++ b/libs/ezsat/puzzle3d.cc
@@ -260,8 +260,10 @@ int main()
std::vector<int> modelExpressions;
std::vector<bool> modelValues;
- for (auto &it : blockinfo)
+ for (auto &it : blockinfo) {
+ ez.freeze(it.first);
modelExpressions.push_back(it.first);
+ }
int solution_counter = 0;
while (1)
diff --git a/libs/ezsat/testbench.cc b/libs/ezsat/testbench.cc
index cc0fe573..d20258c3 100644
--- a/libs/ezsat/testbench.cc
+++ b/libs/ezsat/testbench.cc
@@ -38,11 +38,6 @@ struct xorshift128 {
bool test(ezSAT &sat, int assumption = 0)
{
- for (auto id : sat.assumed())
- printf("%s\n", sat.to_string(id).c_str());
- if (assumption)
- printf("%s\n", sat.to_string(assumption).c_str());
-
std::vector<int> modelExpressions;
std::vector<bool> modelValues;
@@ -68,7 +63,8 @@ void test_simple()
{
printf("==== %s ====\n\n", __PRETTY_FUNCTION__);
- ezSAT sat;
+ ezMiniSAT sat;
+ sat.non_incremental();
sat.assume(sat.OR("A", "B"));
sat.assume(sat.NOT(sat.AND("A", "B")));
test(sat);
@@ -76,89 +72,6 @@ void test_simple()
// ------------------------------------------------------------------------------------------------------------
-void test_basic_operators(ezSAT &sat, xorshift128 &rng, int iter, bool buildTrees, bool buildClusters, std::vector<bool> &log)
-{
- int vars[6] = {
- sat.VAR("A"), sat.VAR("B"), sat.VAR("C"),
- sat.NOT("A"), sat.NOT("B"), sat.NOT("C")
- };
- for (int i = 0; i < iter; i++) {
- int assumption = 0, op = rng() % 6, to = rng() % 6;
- int a = vars[rng() % 6], b = vars[rng() % 6], c = vars[rng() % 6];
- // printf("--> %d %d:%s %d:%s %d:%s\n", op, a, sat.to_string(a).c_str(), b, sat.to_string(b).c_str(), c, sat.to_string(c).c_str());
- switch (op)
- {
- case 0:
- assumption = sat.NOT(a);
- break;
- case 1:
- assumption = sat.AND(a, b);
- break;
- case 2:
- assumption = sat.OR(a, b);
- break;
- case 3:
- assumption = sat.XOR(a, b);
- break;
- case 4:
- assumption = sat.IFF(a, b);
- break;
- case 5:
- assumption = sat.ITE(a, b, c);
- break;
- }
- // printf(" --> %d:%s\n", to, sat.to_string(assumption).c_str());
- if (buildTrees)
- vars[to] = assumption;
- if (!buildClusters)
- sat.clear();
- sat.assume(assumption);
- if (sat.numCnfVariables() < 15) {
- printf("%d:\n", int(log.size()));
- log.push_back(test(sat));
- } else {
- // printf("** skipping large problem **\n");
- }
- }
-}
-
-void test_basic_operators(ezSAT &sat, std::vector<bool> &log)
-{
- printf("-- %s --\n\n", __PRETTY_FUNCTION__);
-
- xorshift128 rng;
- test_basic_operators(sat, rng, 1000, false, false, log);
- for (int i = 0; i < 100; i++)
- test_basic_operators(sat, rng, 10, true, false, log);
- for (int i = 0; i < 100; i++)
- test_basic_operators(sat, rng, 10, false, true, log);
-}
-
-void test_basic_operators()
-{
- printf("==== %s ====\n\n", __PRETTY_FUNCTION__);
-
- ezSAT sat;
- ezMiniSAT miniSat;
- std::vector<bool> logSat, logMiniSat;
-
- test_basic_operators(sat, logSat);
- test_basic_operators(miniSat, logMiniSat);
-
- if (logSat != logMiniSat) {
- printf("Differences between logSat and logMiniSat:");
- for (int i = 0; i < int(std::max(logSat.size(), logMiniSat.size())); i++)
- if (i >= int(logSat.size()) || i >= int(logMiniSat.size()) || logSat[i] != logMiniSat[i])
- printf(" %d", i);
- printf("\n");
- abort();
- } else {
- printf("Completed %d tests with identical results with ezSAT and ezMiniSAT.\n\n", int(logSat.size()));
- }
-}
-
-// ------------------------------------------------------------------------------------------------------------
-
void test_xorshift32_try(ezSAT &sat, uint32_t input_pattern)
{
uint32_t output_pattern = input_pattern;
@@ -209,6 +122,8 @@ void test_xorshift32()
printf("==== %s ====\n\n", __PRETTY_FUNCTION__);
ezMiniSAT sat;
+ sat.keep_cnf();
+
xorshift128 rng;
std::vector<int> bits = sat.vec_var("i", 32);
@@ -225,6 +140,9 @@ void test_xorshift32()
test_xorshift32_try(sat, rng());
test_xorshift32_try(sat, rng());
test_xorshift32_try(sat, rng());
+
+ sat.printDIMACS(stdout, true);
+ printf("\n");
}
// ------------------------------------------------------------------------------------------------------------
@@ -243,7 +161,7 @@ void check(const char *expr1_str, bool expr1, const char *expr2_str, bool expr2)
void test_signed(int8_t a, int8_t b, int8_t c)
{
- ezSAT sat;
+ ezMiniSAT sat;
std::vector<int> av = sat.vec_const_signed(a, 8);
std::vector<int> bv = sat.vec_const_signed(b, 8);
@@ -262,7 +180,7 @@ void test_signed(int8_t a, int8_t b, int8_t c)
void test_unsigned(uint8_t a, uint8_t b, uint8_t c)
{
- ezSAT sat;
+ ezMiniSAT sat;
if (b < c)
b ^= c, c ^= b, b ^= c;
@@ -284,7 +202,7 @@ void test_unsigned(uint8_t a, uint8_t b, uint8_t c)
void test_count(uint32_t x)
{
- ezSAT sat;
+ ezMiniSAT sat;
int count = 0;
for (int i = 0; i < 32; i++)
@@ -338,10 +256,10 @@ void test_onehot()
printf("==== %s ====\n\n", __PRETTY_FUNCTION__);
ezMiniSAT ez;
- int a = ez.literal("a");
- int b = ez.literal("b");
- int c = ez.literal("c");
- int d = ez.literal("d");
+ int a = ez.frozen_literal("a");
+ int b = ez.frozen_literal("b");
+ int c = ez.frozen_literal("c");
+ int d = ez.frozen_literal("d");
std::vector<int> abcd;
abcd.push_back(a);
@@ -392,10 +310,10 @@ void test_manyhot()
printf("==== %s ====\n\n", __PRETTY_FUNCTION__);
ezMiniSAT ez;
- int a = ez.literal("a");
- int b = ez.literal("b");
- int c = ez.literal("c");
- int d = ez.literal("d");
+ int a = ez.frozen_literal("a");
+ int b = ez.frozen_literal("b");
+ int c = ez.frozen_literal("c");
+ int d = ez.frozen_literal("d");
std::vector<int> abcd;
abcd.push_back(a);
@@ -446,13 +364,13 @@ void test_ordered()
printf("==== %s ====\n\n", __PRETTY_FUNCTION__);
ezMiniSAT ez;
- int a = ez.literal("a");
- int b = ez.literal("b");
- int c = ez.literal("c");
+ int a = ez.frozen_literal("a");
+ int b = ez.frozen_literal("b");
+ int c = ez.frozen_literal("c");
- int x = ez.literal("x");
- int y = ez.literal("y");
- int z = ez.literal("z");
+ int x = ez.frozen_literal("x");
+ int y = ez.frozen_literal("y");
+ int z = ez.frozen_literal("z");
std::vector<int> abc;
abc.push_back(a);
@@ -512,7 +430,6 @@ void test_ordered()
int main()
{
test_simple();
- test_basic_operators();
test_xorshift32();
test_arith();
test_onehot();
diff --git a/libs/minisat/00_PATCH_mkLit_default_arg.patch b/libs/minisat/00_PATCH_mkLit_default_arg.patch
new file mode 100644
index 00000000..e21683f9
--- /dev/null
+++ b/libs/minisat/00_PATCH_mkLit_default_arg.patch
@@ -0,0 +1,20 @@
+--- SolverTypes.h
++++ SolverTypes.h
+@@ -52,7 +52,7 @@ struct Lit {
+ int x;
+
+ // Use this as a constructor:
+- friend Lit mkLit(Var var, bool sign = false);
++ friend Lit mkLit(Var var, bool sign);
+
+ bool operator == (Lit p) const { return x == p.x; }
+ bool operator != (Lit p) const { return x != p.x; }
+@@ -60,7 +60,7 @@ struct Lit {
+ };
+
+
+-inline Lit mkLit (Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; }
++inline Lit mkLit (Var var, bool sign = false) { Lit p; p.x = var + var + (int)sign; return p; }
+ inline Lit operator ~(Lit p) { Lit q; q.x = p.x ^ 1; return q; }
+ inline Lit operator ^(Lit p, bool b) { Lit q; q.x = p.x ^ (unsigned int)b; return q; }
+ inline bool sign (Lit p) { return p.x & 1; }
diff --git a/libs/minisat/00_PATCH_remove_zlib.patch b/libs/minisat/00_PATCH_remove_zlib.patch
new file mode 100644
index 00000000..61a36f7e
--- /dev/null
+++ b/libs/minisat/00_PATCH_remove_zlib.patch
@@ -0,0 +1,38 @@
+--- ParseUtils.h
++++ ParseUtils.h
+@@ -24,8 +24,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
+ #include <stdlib.h>
+ #include <stdio.h>
+
+-#include <zlib.h>
+-
+ #include "XAlloc.h"
+
+ namespace Minisat {
+@@ -36,24 +34,16 @@ namespace Minisat {
+
+
+ class StreamBuffer {
+- gzFile in;
+ unsigned char* buf;
+ int pos;
+ int size;
+
+ enum { buffer_size = 64*1024 };
+
+- void assureLookahead() {
+- if (pos >= size) {
+- pos = 0;
+- size = gzread(in, buf, buffer_size); } }
++ virtual void assureLookahead() = 0;
+
+ public:
+- explicit StreamBuffer(gzFile i) : in(i), pos(0), size(0){
+- buf = (unsigned char*)xrealloc(NULL, buffer_size);
+- assureLookahead();
+- }
+- ~StreamBuffer() { free(buf); }
++ virtual ~StreamBuffer() { }
+
+ int operator * () const { return (pos >= size) ? EOF : buf[pos]; }
+ void operator ++ () { pos++; assureLookahead(); }
diff --git a/libs/minisat/00_UPDATE.sh b/libs/minisat/00_UPDATE.sh
new file mode 100644
index 00000000..96a34ec9
--- /dev/null
+++ b/libs/minisat/00_UPDATE.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+rm -f LICENSE *.cc *.h
+git clone --depth 1 https://github.com/niklasso/minisat minisat_upstream
+rm minisat_upstream/minisat/*/Main.cc
+mv minisat_upstream/LICENSE minisat_upstream/minisat/*/*.{h,cc} .
+rm -rf minisat_upstream
+
+sed -i -e 's,^#include *"minisat/[^/]\+/\?,#include ",' *.cc *.h
+sed -i -e 's/Minisat::memUsedPeak()/Minisat::memUsedPeak(bool)/' System.cc
+sed -i -e 's/PRI[iu]64/ & /' Options.h Solver.cc
+sed -i -e '1 i #define __STDC_LIMIT_MACROS' *.cc
+sed -i -e '1 i #define __STDC_FORMAT_MACROS' *.cc
+
+patch -p0 < 00_PATCH_mkLit_default_arg.patch
+patch -p0 < 00_PATCH_remove_zlib.patch
+
diff --git a/libs/minisat/Alg.h b/libs/minisat/Alg.h
new file mode 100644
index 00000000..ddb972e7
--- /dev/null
+++ b/libs/minisat/Alg.h
@@ -0,0 +1,84 @@
+/*******************************************************************************************[Alg.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_Alg_h
+#define Minisat_Alg_h
+
+#include "Vec.h"
+
+namespace Minisat {
+
+//=================================================================================================
+// Useful functions on vector-like types:
+
+//=================================================================================================
+// Removing and searching for elements:
+//
+
+template<class V, class T>
+static inline void remove(V& ts, const T& t)
+{
+ int j = 0;
+ for (; j < (int)ts.size() && ts[j] != t; j++);
+ assert(j < (int)ts.size());
+ for (; j < (int)ts.size()-1; j++) ts[j] = ts[j+1];
+ ts.pop();
+}
+
+
+template<class V, class T>
+static inline bool find(V& ts, const T& t)
+{
+ int j = 0;
+ for (; j < (int)ts.size() && ts[j] != t; j++);
+ return j < (int)ts.size();
+}
+
+
+//=================================================================================================
+// Copying vectors with support for nested vector types:
+//
+
+// Base case:
+template<class T>
+static inline void copy(const T& from, T& to)
+{
+ to = from;
+}
+
+// Recursive case:
+template<class T>
+static inline void copy(const vec<T>& from, vec<T>& to, bool append = false)
+{
+ if (!append)
+ to.clear();
+ for (int i = 0; i < from.size(); i++){
+ to.push();
+ copy(from[i], to.last());
+ }
+}
+
+template<class T>
+static inline void append(const vec<T>& from, vec<T>& to){ copy(from, to, true); }
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/minisat/Alloc.h b/libs/minisat/Alloc.h
new file mode 100644
index 00000000..6591dcd5
--- /dev/null
+++ b/libs/minisat/Alloc.h
@@ -0,0 +1,131 @@
+/*****************************************************************************************[Alloc.h]
+Copyright (c) 2008-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+
+#ifndef Minisat_Alloc_h
+#define Minisat_Alloc_h
+
+#include "XAlloc.h"
+#include "Vec.h"
+
+namespace Minisat {
+
+//=================================================================================================
+// Simple Region-based memory allocator:
+
+template<class T>
+class RegionAllocator
+{
+ T* memory;
+ uint32_t sz;
+ uint32_t cap;
+ uint32_t wasted_;
+
+ void capacity(uint32_t min_cap);
+
+ public:
+ // TODO: make this a class for better type-checking?
+ typedef uint32_t Ref;
+ enum { Ref_Undef = UINT32_MAX };
+ enum { Unit_Size = sizeof(T) };
+
+ explicit RegionAllocator(uint32_t start_cap = 1024*1024) : memory(NULL), sz(0), cap(0), wasted_(0){ capacity(start_cap); }
+ ~RegionAllocator()
+ {
+ if (memory != NULL)
+ ::free(memory);
+ }
+
+
+ uint32_t size () const { return sz; }
+ uint32_t wasted () const { return wasted_; }
+
+ Ref alloc (int size);
+ void free (int size) { wasted_ += size; }
+
+ // Deref, Load Effective Address (LEA), Inverse of LEA (AEL):
+ T& operator[](Ref r) { assert(r < sz); return memory[r]; }
+ const T& operator[](Ref r) const { assert(r < sz); return memory[r]; }
+
+ T* lea (Ref r) { assert(r < sz); return &memory[r]; }
+ const T* lea (Ref r) const { assert(r < sz); return &memory[r]; }
+ Ref ael (const T* t) { assert((void*)t >= (void*)&memory[0] && (void*)t < (void*)&memory[sz-1]);
+ return (Ref)(t - &memory[0]); }
+
+ void moveTo(RegionAllocator& to) {
+ if (to.memory != NULL) ::free(to.memory);
+ to.memory = memory;
+ to.sz = sz;
+ to.cap = cap;
+ to.wasted_ = wasted_;
+
+ memory = NULL;
+ sz = cap = wasted_ = 0;
+ }
+
+
+};
+
+template<class T>
+void RegionAllocator<T>::capacity(uint32_t min_cap)
+{
+ if (cap >= min_cap) return;
+
+ uint32_t prev_cap = cap;
+ while (cap < min_cap){
+ // NOTE: Multiply by a factor (13/8) without causing overflow, then add 2 and make the
+ // result even by clearing the least significant bit. The resulting sequence of capacities
+ // is carefully chosen to hit a maximum capacity that is close to the '2^32-1' limit when
+ // using 'uint32_t' as indices so that as much as possible of this space can be used.
+ uint32_t delta = ((cap >> 1) + (cap >> 3) + 2) & ~1;
+ cap += delta;
+
+ if (cap <= prev_cap)
+ throw OutOfMemoryException();
+ }
+ // printf(" .. (%p) cap = %u\n", this, cap);
+
+ assert(cap > 0);
+ memory = (T*)xrealloc(memory, sizeof(T)*cap);
+}
+
+
+template<class T>
+typename RegionAllocator<T>::Ref
+RegionAllocator<T>::alloc(int size)
+{
+ // printf("ALLOC called (this = %p, size = %d)\n", this, size); fflush(stdout);
+ assert(size > 0);
+ capacity(sz + size);
+
+ uint32_t prev_sz = sz;
+ sz += size;
+
+ // Handle overflow:
+ if (sz < prev_sz)
+ throw OutOfMemoryException();
+
+ return prev_sz;
+}
+
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/minisat/Dimacs.h b/libs/minisat/Dimacs.h
new file mode 100644
index 00000000..ccfa1c01
--- /dev/null
+++ b/libs/minisat/Dimacs.h
@@ -0,0 +1,87 @@
+/****************************************************************************************[Dimacs.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_Dimacs_h
+#define Minisat_Dimacs_h
+
+#include <stdio.h>
+
+#include "ParseUtils.h"
+#include "SolverTypes.h"
+
+namespace Minisat {
+
+//=================================================================================================
+// DIMACS Parser:
+
+template<class B, class Solver>
+static void readClause(B& in, Solver& S, vec<Lit>& lits) {
+ int parsed_lit, var;
+ lits.clear();
+ for (;;){
+ parsed_lit = parseInt(in);
+ if (parsed_lit == 0) break;
+ var = abs(parsed_lit)-1;
+ while (var >= S.nVars()) S.newVar();
+ lits.push( (parsed_lit > 0) ? mkLit(var) : ~mkLit(var) );
+ }
+}
+
+template<class B, class Solver>
+static void parse_DIMACS_main(B& in, Solver& S, bool strictp = false) {
+ vec<Lit> lits;
+ int vars = 0;
+ int clauses = 0;
+ int cnt = 0;
+ for (;;){
+ skipWhitespace(in);
+ if (*in == EOF) break;
+ else if (*in == 'p'){
+ if (eagerMatch(in, "p cnf")){
+ vars = parseInt(in);
+ clauses = parseInt(in);
+ // SATRACE'06 hack
+ // if (clauses > 4000000)
+ // S.eliminate(true);
+ }else{
+ printf("PARSE ERROR! Unexpected char: %c\n", *in), exit(3);
+ }
+ } else if (*in == 'c' || *in == 'p')
+ skipLine(in);
+ else{
+ cnt++;
+ readClause(in, S, lits);
+ S.addClause_(lits); }
+ }
+ if (strictp && cnt != clauses)
+ printf("PARSE ERROR! DIMACS header mismatch: wrong number of clauses\n");
+}
+
+// Inserts problem into solver.
+//
+template<class Solver>
+static void parse_DIMACS(gzFile input_stream, Solver& S, bool strictp = false) {
+ StreamBuffer in(input_stream);
+ parse_DIMACS_main(in, S, strictp); }
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/minisat/Heap.h b/libs/minisat/Heap.h
new file mode 100644
index 00000000..057a3cdf
--- /dev/null
+++ b/libs/minisat/Heap.h
@@ -0,0 +1,168 @@
+/******************************************************************************************[Heap.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_Heap_h
+#define Minisat_Heap_h
+
+#include "Vec.h"
+#include "IntMap.h"
+
+namespace Minisat {
+
+//=================================================================================================
+// A heap implementation with support for decrease/increase key.
+
+
+template<class K, class Comp, class MkIndex = MkIndexDefault<K> >
+class Heap {
+ vec<K> heap; // Heap of Keys
+ IntMap<K,int,MkIndex> indices; // Each Key's position (index) in the Heap
+ Comp lt; // The heap is a minimum-heap with respect to this comparator
+
+ // Index "traversal" functions
+ static inline int left (int i) { return i*2+1; }
+ static inline int right (int i) { return (i+1)*2; }
+ static inline int parent(int i) { return (i-1) >> 1; }
+
+
+ void percolateUp(int i)
+ {
+ K x = heap[i];
+ int p = parent(i);
+
+ while (i != 0 && lt(x, heap[p])){
+ heap[i] = heap[p];
+ indices[heap[p]] = i;
+ i = p;
+ p = parent(p);
+ }
+ heap [i] = x;
+ indices[x] = i;
+ }
+
+
+ void percolateDown(int i)
+ {
+ K x = heap[i];
+ while (left(i) < heap.size()){
+ int child = right(i) < heap.size() && lt(heap[right(i)], heap[left(i)]) ? right(i) : left(i);
+ if (!lt(heap[child], x)) break;
+ heap[i] = heap[child];
+ indices[heap[i]] = i;
+ i = child;
+ }
+ heap [i] = x;
+ indices[x] = i;
+ }
+
+
+ public:
+ Heap(const Comp& c, MkIndex _index = MkIndex()) : indices(_index), lt(c) {}
+
+ int size () const { return heap.size(); }
+ bool empty () const { return heap.size() == 0; }
+ bool inHeap (K k) const { return indices.has(k) && indices[k] >= 0; }
+ int operator[](int index) const { assert(index < heap.size()); return heap[index]; }
+
+ void decrease (K k) { assert(inHeap(k)); percolateUp (indices[k]); }
+ void increase (K k) { assert(inHeap(k)); percolateDown(indices[k]); }
+
+
+ // Safe variant of insert/decrease/increase:
+ void update(K k)
+ {
+ if (!inHeap(k))
+ insert(k);
+ else {
+ percolateUp(indices[k]);
+ percolateDown(indices[k]); }
+ }
+
+
+ void insert(K k)
+ {
+ indices.reserve(k, -1);
+ assert(!inHeap(k));
+
+ indices[k] = heap.size();
+ heap.push(k);
+ percolateUp(indices[k]);
+ }
+
+
+ void remove(K k)
+ {
+ assert(inHeap(k));
+
+ int k_pos = indices[k];
+ indices[k] = -1;
+
+ if (k_pos < heap.size()-1){
+ heap[k_pos] = heap.last();
+ indices[heap[k_pos]] = k_pos;
+ heap.pop();
+ percolateDown(k_pos);
+ }else
+ heap.pop();
+ }
+
+
+ K removeMin()
+ {
+ K x = heap[0];
+ heap[0] = heap.last();
+ indices[heap[0]] = 0;
+ indices[x] = -1;
+ heap.pop();
+ if (heap.size() > 1) percolateDown(0);
+ return x;
+ }
+
+
+ // Rebuild the heap from scratch, using the elements in 'ns':
+ void build(const vec<K>& ns) {
+ for (int i = 0; i < heap.size(); i++)
+ indices[heap[i]] = -1;
+ heap.clear();
+
+ for (int i = 0; i < ns.size(); i++){
+ // TODO: this should probably call reserve instead of relying on it being reserved already.
+ assert(indices.has(ns[i]));
+ indices[ns[i]] = i;
+ heap.push(ns[i]); }
+
+ for (int i = heap.size() / 2 - 1; i >= 0; i--)
+ percolateDown(i);
+ }
+
+ void clear(bool dispose = false)
+ {
+ // TODO: shouldn't the 'indices' map also be dispose-cleared?
+ for (int i = 0; i < heap.size(); i++)
+ indices[heap[i]] = -1;
+ heap.clear(dispose);
+ }
+};
+
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/minisat/IntMap.h b/libs/minisat/IntMap.h
new file mode 100644
index 00000000..9a66315d
--- /dev/null
+++ b/libs/minisat/IntMap.h
@@ -0,0 +1,106 @@
+/****************************************************************************************[IntMap.h]
+Copyright (c) 2011, Niklas Sorensson
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_IntMap_h
+#define Minisat_IntMap_h
+
+#include "Vec.h"
+
+namespace Minisat {
+
+ template<class T> struct MkIndexDefault {
+ typename vec<T>::Size operator()(T t) const { return (typename vec<T>::Size)t; }
+ };
+
+ template<class K, class V, class MkIndex = MkIndexDefault<K> >
+ class IntMap {
+ vec<V> map;
+ MkIndex index;
+ public:
+ explicit IntMap(MkIndex _index = MkIndex()) : index(_index){}
+
+ bool has (K k) const { return index(k) < map.size(); }
+
+ const V& operator[](K k) const { assert(has(k)); return map[index(k)]; }
+ V& operator[](K k) { assert(has(k)); return map[index(k)]; }
+
+ const V* begin () const { return &map[0]; }
+ const V* end () const { return &map[map.size()]; }
+ V* begin () { return &map[0]; }
+ V* end () { return &map[map.size()]; }
+
+ void reserve(K key, V pad) { map.growTo(index(key)+1, pad); }
+ void reserve(K key) { map.growTo(index(key)+1); }
+ void insert (K key, V val, V pad){ reserve(key, pad); operator[](key) = val; }
+ void insert (K key, V val) { reserve(key); operator[](key) = val; }
+
+ void clear (bool dispose = false) { map.clear(dispose); }
+ void moveTo (IntMap& to) { map.moveTo(to.map); to.index = index; }
+ void copyTo (IntMap& to) const { map.copyTo(to.map); to.index = index; }
+ };
+
+
+ template<class K, class MkIndex = MkIndexDefault<K> >
+ class IntSet
+ {
+ IntMap<K, char, MkIndex> in_set;
+ vec<K> xs;
+
+ public:
+ // Size operations:
+ int size (void) const { return xs.size(); }
+ void clear (bool free = false){
+ if (free)
+ in_set.clear(true);
+ else
+ for (int i = 0; i < xs.size(); i++)
+ in_set[xs[i]] = 0;
+ xs.clear(free);
+ }
+
+ // Allow inspecting the internal vector:
+ const vec<K>&
+ toVec () const { return xs; }
+
+ // Vector interface:
+ K operator [] (int index) const { return xs[index]; }
+
+
+ void insert (K k) { in_set.reserve(k, 0); if (!in_set[k]) { in_set[k] = 1; xs.push(k); } }
+ bool has (K k) { in_set.reserve(k, 0); return in_set[k]; }
+ };
+
+ #if 0
+ template<class K, class V, V nil, class MkIndex = MkIndexDefault<K> >
+ class IntMapNil {
+ vec<V> map;
+ V nil;
+
+ public:
+ IntMap(){}
+
+ void reserve(K);
+ V& find (K);
+ const V& operator[](K k) const;
+
+ };
+ #endif
+
+//=================================================================================================
+} // namespace Minisat
+#endif
diff --git a/libs/minisat/IntTypes.h b/libs/minisat/IntTypes.h
new file mode 100644
index 00000000..c4881628
--- /dev/null
+++ b/libs/minisat/IntTypes.h
@@ -0,0 +1,42 @@
+/**************************************************************************************[IntTypes.h]
+Copyright (c) 2009-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_IntTypes_h
+#define Minisat_IntTypes_h
+
+#ifdef __sun
+ // Not sure if there are newer versions that support C99 headers. The
+ // needed features are implemented in the headers below though:
+
+# include <sys/int_types.h>
+# include <sys/int_fmtio.h>
+# include <sys/int_limits.h>
+
+#else
+
+# include <stdint.h>
+# include <inttypes.h>
+
+#endif
+
+#include <limits.h>
+
+//=================================================================================================
+
+#endif
diff --git a/libs/minisat/LICENSE b/libs/minisat/LICENSE
new file mode 100644
index 00000000..22816ff3
--- /dev/null
+++ b/libs/minisat/LICENSE
@@ -0,0 +1,21 @@
+MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+ Copyright (c) 2007-2010 Niklas Sorensson
+
+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.
diff --git a/libs/minisat/Map.h b/libs/minisat/Map.h
new file mode 100644
index 00000000..a6f83200
--- /dev/null
+++ b/libs/minisat/Map.h
@@ -0,0 +1,193 @@
+/*******************************************************************************************[Map.h]
+Copyright (c) 2006-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_Map_h
+#define Minisat_Map_h
+
+#include "IntTypes.h"
+#include "Vec.h"
+
+namespace Minisat {
+
+//=================================================================================================
+// Default hash/equals functions
+//
+
+template<class K> struct Hash { uint32_t operator()(const K& k) const { return hash(k); } };
+template<class K> struct Equal { bool operator()(const K& k1, const K& k2) const { return k1 == k2; } };
+
+template<class K> struct DeepHash { uint32_t operator()(const K* k) const { return hash(*k); } };
+template<class K> struct DeepEqual { bool operator()(const K* k1, const K* k2) const { return *k1 == *k2; } };
+
+static inline uint32_t hash(uint32_t x){ return x; }
+static inline uint32_t hash(uint64_t x){ return (uint32_t)x; }
+static inline uint32_t hash(int32_t x) { return (uint32_t)x; }
+static inline uint32_t hash(int64_t x) { return (uint32_t)x; }
+
+
+//=================================================================================================
+// Some primes
+//
+
+static const int nprimes = 25;
+static const int primes [nprimes] = { 31, 73, 151, 313, 643, 1291, 2593, 5233, 10501, 21013, 42073, 84181, 168451, 337219, 674701, 1349473, 2699299, 5398891, 10798093, 21596719, 43193641, 86387383, 172775299, 345550609, 691101253 };
+
+//=================================================================================================
+// Hash table implementation of Maps
+//
+
+template<class K, class D, class H = Hash<K>, class E = Equal<K> >
+class Map {
+ public:
+ struct Pair { K key; D data; };
+
+ private:
+ H hash;
+ E equals;
+
+ vec<Pair>* table;
+ int cap;
+ int size;
+
+ // Don't allow copying (error prone):
+ Map<K,D,H,E>& operator = (Map<K,D,H,E>& other);
+ Map (Map<K,D,H,E>& other);
+
+ bool checkCap(int new_size) const { return new_size > cap; }
+
+ int32_t index (const K& k) const { return hash(k) % cap; }
+ void _insert (const K& k, const D& d) {
+ vec<Pair>& ps = table[index(k)];
+ ps.push(); ps.last().key = k; ps.last().data = d; }
+
+ void rehash () {
+ const vec<Pair>* old = table;
+
+ int old_cap = cap;
+ int newsize = primes[0];
+ for (int i = 1; newsize <= cap && i < nprimes; i++)
+ newsize = primes[i];
+
+ table = new vec<Pair>[newsize];
+ cap = newsize;
+
+ for (int i = 0; i < old_cap; i++){
+ for (int j = 0; j < old[i].size(); j++){
+ _insert(old[i][j].key, old[i][j].data); }}
+
+ delete [] old;
+
+ // printf(" --- rehashing, old-cap=%d, new-cap=%d\n", cap, newsize);
+ }
+
+
+ public:
+
+ Map () : table(NULL), cap(0), size(0) {}
+ Map (const H& h, const E& e) : hash(h), equals(e), table(NULL), cap(0), size(0){}
+ ~Map () { delete [] table; }
+
+ // PRECONDITION: the key must already exist in the map.
+ const D& operator [] (const K& k) const
+ {
+ assert(size != 0);
+ const D* res = NULL;
+ const vec<Pair>& ps = table[index(k)];
+ for (int i = 0; i < ps.size(); i++)
+ if (equals(ps[i].key, k))
+ res = &ps[i].data;
+ assert(res != NULL);
+ return *res;
+ }
+
+ // PRECONDITION: the key must already exist in the map.
+ D& operator [] (const K& k)
+ {
+ assert(size != 0);
+ D* res = NULL;
+ vec<Pair>& ps = table[index(k)];
+ for (int i = 0; i < ps.size(); i++)
+ if (equals(ps[i].key, k))
+ res = &ps[i].data;
+ assert(res != NULL);
+ return *res;
+ }
+
+ // PRECONDITION: the key must *NOT* exist in the map.
+ void insert (const K& k, const D& d) { if (checkCap(size+1)) rehash(); _insert(k, d); size++; }
+ bool peek (const K& k, D& d) const {
+ if (size == 0) return false;
+ const vec<Pair>& ps = table[index(k)];
+ for (int i = 0; i < ps.size(); i++)
+ if (equals(ps[i].key, k)){
+ d = ps[i].data;
+ return true; }
+ return false;
+ }
+
+ bool has (const K& k) const {
+ if (size == 0) return false;
+ const vec<Pair>& ps = table[index(k)];
+ for (int i = 0; i < ps.size(); i++)
+ if (equals(ps[i].key, k))
+ return true;
+ return false;
+ }
+
+ // PRECONDITION: the key must exist in the map.
+ void remove(const K& k) {
+ assert(table != NULL);
+ vec<Pair>& ps = table[index(k)];
+ int j = 0;
+ for (; j < ps.size() && !equals(ps[j].key, k); j++);
+ assert(j < ps.size());
+ ps[j] = ps.last();
+ ps.pop();
+ size--;
+ }
+
+ void clear () {
+ cap = size = 0;
+ delete [] table;
+ table = NULL;
+ }
+
+ int elems() const { return size; }
+ int bucket_count() const { return cap; }
+
+ // NOTE: the hash and equality objects are not moved by this method:
+ void moveTo(Map& other){
+ delete [] other.table;
+
+ other.table = table;
+ other.cap = cap;
+ other.size = size;
+
+ table = NULL;
+ size = cap = 0;
+ }
+
+ // NOTE: given a bit more time, I could make a more C++-style iterator out of this:
+ const vec<Pair>& bucket(int i) const { return table[i]; }
+};
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/minisat/Options.cc b/libs/minisat/Options.cc
new file mode 100644
index 00000000..1aff3fab
--- /dev/null
+++ b/libs/minisat/Options.cc
@@ -0,0 +1,94 @@
+#define __STDC_FORMAT_MACROS
+#define __STDC_LIMIT_MACROS
+/**************************************************************************************[Options.cc]
+Copyright (c) 2008-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#include "Sort.h"
+#include "Options.h"
+#include "ParseUtils.h"
+
+using namespace Minisat;
+
+void Minisat::parseOptions(int& argc, char** argv, bool strict)
+{
+ int i, j;
+ for (i = j = 1; i < argc; i++){
+ const char* str = argv[i];
+ if (match(str, "--") && match(str, Option::getHelpPrefixString()) && match(str, "help")){
+ if (*str == '\0')
+ printUsageAndExit(argc, argv);
+ else if (match(str, "-verb"))
+ printUsageAndExit(argc, argv, true);
+ } else {
+ bool parsed_ok = false;
+
+ for (int k = 0; !parsed_ok && k < Option::getOptionList().size(); k++){
+ parsed_ok = Option::getOptionList()[k]->parse(argv[i]);
+
+ // fprintf(stderr, "checking %d: %s against flag <%s> (%s)\n", i, argv[i], Option::getOptionList()[k]->name, parsed_ok ? "ok" : "skip");
+ }
+
+ if (!parsed_ok){
+ if (strict && match(argv[i], "-"))
+ fprintf(stderr, "ERROR! Unknown flag \"%s\". Use '--%shelp' for help.\n", argv[i], Option::getHelpPrefixString()), exit(1);
+ else
+ argv[j++] = argv[i];
+ }
+ }
+ }
+
+ argc -= (i - j);
+}
+
+
+void Minisat::setUsageHelp (const char* str){ Option::getUsageString() = str; }
+void Minisat::setHelpPrefixStr (const char* str){ Option::getHelpPrefixString() = str; }
+void Minisat::printUsageAndExit (int /*argc*/, char** argv, bool verbose)
+{
+ const char* usage = Option::getUsageString();
+ if (usage != NULL)
+ fprintf(stderr, usage, argv[0]);
+
+ sort(Option::getOptionList(), Option::OptionLt());
+
+ const char* prev_cat = NULL;
+ const char* prev_type = NULL;
+
+ for (int i = 0; i < Option::getOptionList().size(); i++){
+ const char* cat = Option::getOptionList()[i]->category;
+ const char* type = Option::getOptionList()[i]->type_name;
+
+ if (cat != prev_cat)
+ fprintf(stderr, "\n%s OPTIONS:\n\n", cat);
+ else if (type != prev_type)
+ fprintf(stderr, "\n");
+
+ Option::getOptionList()[i]->help(verbose);
+
+ prev_cat = Option::getOptionList()[i]->category;
+ prev_type = Option::getOptionList()[i]->type_name;
+ }
+
+ fprintf(stderr, "\nHELP OPTIONS:\n\n");
+ fprintf(stderr, " --%shelp Print help message.\n", Option::getHelpPrefixString());
+ fprintf(stderr, " --%shelp-verb Print verbose help message.\n", Option::getHelpPrefixString());
+ fprintf(stderr, "\n");
+ exit(0);
+}
+
diff --git a/libs/minisat/Options.h b/libs/minisat/Options.h
new file mode 100644
index 00000000..d602769c
--- /dev/null
+++ b/libs/minisat/Options.h
@@ -0,0 +1,386 @@
+/***************************************************************************************[Options.h]
+Copyright (c) 2008-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_Options_h
+#define Minisat_Options_h
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#include "IntTypes.h"
+#include "Vec.h"
+#include "ParseUtils.h"
+
+namespace Minisat {
+
+//==================================================================================================
+// Top-level option parse/help functions:
+
+
+extern void parseOptions (int& argc, char** argv, bool strict = false);
+extern void printUsageAndExit(int argc, char** argv, bool verbose = false);
+extern void setUsageHelp (const char* str);
+extern void setHelpPrefixStr (const char* str);
+
+
+//==================================================================================================
+// Options is an abstract class that gives the interface for all types options:
+
+
+class Option
+{
+ protected:
+ const char* name;
+ const char* description;
+ const char* category;
+ const char* type_name;
+
+ static vec<Option*>& getOptionList () { static vec<Option*> options; return options; }
+ static const char*& getUsageString() { static const char* usage_str; return usage_str; }
+ static const char*& getHelpPrefixString() { static const char* help_prefix_str = ""; return help_prefix_str; }
+
+ struct OptionLt {
+ bool operator()(const Option* x, const Option* y) {
+ int test1 = strcmp(x->category, y->category);
+ return test1 < 0 || (test1 == 0 && strcmp(x->type_name, y->type_name) < 0);
+ }
+ };
+
+ Option(const char* name_,
+ const char* desc_,
+ const char* cate_,
+ const char* type_) :
+ name (name_)
+ , description(desc_)
+ , category (cate_)
+ , type_name (type_)
+ {
+ getOptionList().push(this);
+ }
+
+ public:
+ virtual ~Option() {}
+
+ virtual bool parse (const char* str) = 0;
+ virtual void help (bool verbose = false) = 0;
+
+ friend void parseOptions (int& argc, char** argv, bool strict);
+ friend void printUsageAndExit (int argc, char** argv, bool verbose);
+ friend void setUsageHelp (const char* str);
+ friend void setHelpPrefixStr (const char* str);
+};
+
+
+//==================================================================================================
+// Range classes with specialization for floating types:
+
+
+struct IntRange {
+ int begin;
+ int end;
+ IntRange(int b, int e) : begin(b), end(e) {}
+};
+
+struct Int64Range {
+ int64_t begin;
+ int64_t end;
+ Int64Range(int64_t b, int64_t e) : begin(b), end(e) {}
+};
+
+struct DoubleRange {
+ double begin;
+ double end;
+ bool begin_inclusive;
+ bool end_inclusive;
+ DoubleRange(double b, bool binc, double e, bool einc) : begin(b), end(e), begin_inclusive(binc), end_inclusive(einc) {}
+};
+
+
+//==================================================================================================
+// Double options:
+
+
+class DoubleOption : public Option
+{
+ protected:
+ DoubleRange range;
+ double value;
+
+ public:
+ DoubleOption(const char* c, const char* n, const char* d, double def = double(), DoubleRange r = DoubleRange(-HUGE_VAL, false, HUGE_VAL, false))
+ : Option(n, d, c, "<double>"), range(r), value(def) {
+ // FIXME: set LC_NUMERIC to "C" to make sure that strtof/strtod parses decimal point correctly.
+ }
+
+ operator double (void) const { return value; }
+ operator double& (void) { return value; }
+ DoubleOption& operator=(double x) { value = x; return *this; }
+
+ virtual bool parse(const char* str){
+ const char* span = str;
+
+ if (!match(span, "-") || !match(span, name) || !match(span, "="))
+ return false;
+
+ char* end;
+ double tmp = strtod(span, &end);
+
+ if (end == NULL)
+ return false;
+ else if (tmp >= range.end && (!range.end_inclusive || tmp != range.end)){
+ fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name);
+ exit(1);
+ }else if (tmp <= range.begin && (!range.begin_inclusive || tmp != range.begin)){
+ fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name);
+ exit(1); }
+
+ value = tmp;
+ // fprintf(stderr, "READ VALUE: %g\n", value);
+
+ return true;
+ }
+
+ virtual void help (bool verbose = false){
+ fprintf(stderr, " -%-12s = %-8s %c%4.2g .. %4.2g%c (default: %g)\n",
+ name, type_name,
+ range.begin_inclusive ? '[' : '(',
+ range.begin,
+ range.end,
+ range.end_inclusive ? ']' : ')',
+ value);
+ if (verbose){
+ fprintf(stderr, "\n %s\n", description);
+ fprintf(stderr, "\n");
+ }
+ }
+};
+
+
+//==================================================================================================
+// Int options:
+
+
+class IntOption : public Option
+{
+ protected:
+ IntRange range;
+ int32_t value;
+
+ public:
+ IntOption(const char* c, const char* n, const char* d, int32_t def = int32_t(), IntRange r = IntRange(INT32_MIN, INT32_MAX))
+ : Option(n, d, c, "<int32>"), range(r), value(def) {}
+
+ operator int32_t (void) const { return value; }
+ operator int32_t& (void) { return value; }
+ IntOption& operator= (int32_t x) { value = x; return *this; }
+
+ virtual bool parse(const char* str){
+ const char* span = str;
+
+ if (!match(span, "-") || !match(span, name) || !match(span, "="))
+ return false;
+
+ char* end;
+ int32_t tmp = strtol(span, &end, 10);
+
+ if (end == NULL)
+ return false;
+ else if (tmp > range.end){
+ fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name);
+ exit(1);
+ }else if (tmp < range.begin){
+ fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name);
+ exit(1); }
+
+ value = tmp;
+
+ return true;
+ }
+
+ virtual void help (bool verbose = false){
+ fprintf(stderr, " -%-12s = %-8s [", name, type_name);
+ if (range.begin == INT32_MIN)
+ fprintf(stderr, "imin");
+ else
+ fprintf(stderr, "%4d", range.begin);
+
+ fprintf(stderr, " .. ");
+ if (range.end == INT32_MAX)
+ fprintf(stderr, "imax");
+ else
+ fprintf(stderr, "%4d", range.end);
+
+ fprintf(stderr, "] (default: %d)\n", value);
+ if (verbose){
+ fprintf(stderr, "\n %s\n", description);
+ fprintf(stderr, "\n");
+ }
+ }
+};
+
+
+// Leave this out for visual C++ until Microsoft implements C99 and gets support for strtoll.
+#ifndef _MSC_VER
+
+class Int64Option : public Option
+{
+ protected:
+ Int64Range range;
+ int64_t value;
+
+ public:
+ Int64Option(const char* c, const char* n, const char* d, int64_t def = int64_t(), Int64Range r = Int64Range(INT64_MIN, INT64_MAX))
+ : Option(n, d, c, "<int64>"), range(r), value(def) {}
+
+ operator int64_t (void) const { return value; }
+ operator int64_t& (void) { return value; }
+ Int64Option& operator= (int64_t x) { value = x; return *this; }
+
+ virtual bool parse(const char* str){
+ const char* span = str;
+
+ if (!match(span, "-") || !match(span, name) || !match(span, "="))
+ return false;
+
+ char* end;
+ int64_t tmp = strtoll(span, &end, 10);
+
+ if (end == NULL)
+ return false;
+ else if (tmp > range.end){
+ fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name);
+ exit(1);
+ }else if (tmp < range.begin){
+ fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name);
+ exit(1); }
+
+ value = tmp;
+
+ return true;
+ }
+
+ virtual void help (bool verbose = false){
+ fprintf(stderr, " -%-12s = %-8s [", name, type_name);
+ if (range.begin == INT64_MIN)
+ fprintf(stderr, "imin");
+ else
+ fprintf(stderr, "%4" PRIi64 , range.begin);
+
+ fprintf(stderr, " .. ");
+ if (range.end == INT64_MAX)
+ fprintf(stderr, "imax");
+ else
+ fprintf(stderr, "%4" PRIi64 , range.end);
+
+ fprintf(stderr, "] (default: %" PRIi64 ")\n", value);
+ if (verbose){
+ fprintf(stderr, "\n %s\n", description);
+ fprintf(stderr, "\n");
+ }
+ }
+};
+#endif
+
+//==================================================================================================
+// String option:
+
+
+class StringOption : public Option
+{
+ const char* value;
+ public:
+ StringOption(const char* c, const char* n, const char* d, const char* def = NULL)
+ : Option(n, d, c, "<string>"), value(def) {}
+
+ operator const char* (void) const { return value; }
+ operator const char*& (void) { return value; }
+ StringOption& operator= (const char* x) { value = x; return *this; }
+
+ virtual bool parse(const char* str){
+ const char* span = str;
+
+ if (!match(span, "-") || !match(span, name) || !match(span, "="))
+ return false;
+
+ value = span;
+ return true;
+ }
+
+ virtual void help (bool verbose = false){
+ fprintf(stderr, " -%-10s = %8s\n", name, type_name);
+ if (verbose){
+ fprintf(stderr, "\n %s\n", description);
+ fprintf(stderr, "\n");
+ }
+ }
+};
+
+
+//==================================================================================================
+// Bool option:
+
+
+class BoolOption : public Option
+{
+ bool value;
+
+ public:
+ BoolOption(const char* c, const char* n, const char* d, bool v)
+ : Option(n, d, c, "<bool>"), value(v) {}
+
+ operator bool (void) const { return value; }
+ operator bool& (void) { return value; }
+ BoolOption& operator=(bool b) { value = b; return *this; }
+
+ virtual bool parse(const char* str){
+ const char* span = str;
+
+ if (match(span, "-")){
+ bool b = !match(span, "no-");
+
+ if (strcmp(span, name) == 0){
+ value = b;
+ return true; }
+ }
+
+ return false;
+ }
+
+ virtual void help (bool verbose = false){
+
+ fprintf(stderr, " -%s, -no-%s", name, name);
+
+ for (uint32_t i = 0; i < 32 - strlen(name)*2; i++)
+ fprintf(stderr, " ");
+
+ fprintf(stderr, " ");
+ fprintf(stderr, "(default: %s)\n", value ? "on" : "off");
+ if (verbose){
+ fprintf(stderr, "\n %s\n", description);
+ fprintf(stderr, "\n");
+ }
+ }
+};
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/minisat/ParseUtils.h b/libs/minisat/ParseUtils.h
new file mode 100644
index 00000000..04911c70
--- /dev/null
+++ b/libs/minisat/ParseUtils.h
@@ -0,0 +1,119 @@
+/************************************************************************************[ParseUtils.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_ParseUtils_h
+#define Minisat_ParseUtils_h
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "XAlloc.h"
+
+namespace Minisat {
+
+//-------------------------------------------------------------------------------------------------
+// A simple buffered character stream class:
+
+
+
+class StreamBuffer {
+ unsigned char* buf;
+ int pos;
+ int size;
+
+ enum { buffer_size = 64*1024 };
+
+ virtual void assureLookahead() = 0;
+
+public:
+ virtual ~StreamBuffer() { }
+
+ int operator * () const { return (pos >= size) ? EOF : buf[pos]; }
+ void operator ++ () { pos++; assureLookahead(); }
+ int position () const { return pos; }
+};
+
+
+//-------------------------------------------------------------------------------------------------
+// End-of-file detection functions for StreamBuffer and char*:
+
+
+static inline bool isEof(StreamBuffer& in) { return *in == EOF; }
+static inline bool isEof(const char* in) { return *in == '\0'; }
+
+//-------------------------------------------------------------------------------------------------
+// Generic parse functions parametrized over the input-stream type.
+
+
+template<class B>
+static void skipWhitespace(B& in) {
+ while ((*in >= 9 && *in <= 13) || *in == 32)
+ ++in; }
+
+
+template<class B>
+static void skipLine(B& in) {
+ for (;;){
+ if (isEof(in)) return;
+ if (*in == '\n') { ++in; return; }
+ ++in; } }
+
+
+template<class B>
+static int parseInt(B& in) {
+ int val = 0;
+ bool neg = false;
+ skipWhitespace(in);
+ if (*in == '-') neg = true, ++in;
+ else if (*in == '+') ++in;
+ if (*in < '0' || *in > '9') fprintf(stderr, "PARSE ERROR! Unexpected char: %c\n", *in), exit(3);
+ while (*in >= '0' && *in <= '9')
+ val = val*10 + (*in - '0'),
+ ++in;
+ return neg ? -val : val; }
+
+
+// String matching: in case of a match the input iterator will be advanced the corresponding
+// number of characters.
+template<class B>
+static bool match(B& in, const char* str) {
+ int i;
+ for (i = 0; str[i] != '\0'; i++)
+ if (in[i] != str[i])
+ return false;
+
+ in += i;
+
+ return true;
+}
+
+// String matching: consumes characters eagerly, but does not require random access iterator.
+template<class B>
+static bool eagerMatch(B& in, const char* str) {
+ for (; *str != '\0'; ++str, ++in)
+ if (*str != *in)
+ return false;
+ return true; }
+
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/minisat/Queue.h b/libs/minisat/Queue.h
new file mode 100644
index 00000000..5ba50cd2
--- /dev/null
+++ b/libs/minisat/Queue.h
@@ -0,0 +1,69 @@
+/*****************************************************************************************[Queue.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_Queue_h
+#define Minisat_Queue_h
+
+#include "Vec.h"
+
+namespace Minisat {
+
+//=================================================================================================
+
+template<class T>
+class Queue {
+ vec<T> buf;
+ int first;
+ int end;
+
+public:
+ typedef T Key;
+
+ Queue() : buf(1), first(0), end(0) {}
+
+ void clear (bool dealloc = false) { buf.clear(dealloc); buf.growTo(1); first = end = 0; }
+ int size () const { return (end >= first) ? end - first : end - first + buf.size(); }
+
+ const T& operator [] (int index) const { assert(index >= 0); assert(index < size()); return buf[(first + index) % buf.size()]; }
+ T& operator [] (int index) { assert(index >= 0); assert(index < size()); return buf[(first + index) % buf.size()]; }
+
+ T peek () const { assert(first != end); return buf[first]; }
+ void pop () { assert(first != end); first++; if (first == buf.size()) first = 0; }
+ void insert(T elem) { // INVARIANT: buf[end] is always unused
+ buf[end++] = elem;
+ if (end == buf.size()) end = 0;
+ if (first == end){ // Resize:
+ vec<T> tmp((buf.size()*3 + 1) >> 1);
+ //**/printf("queue alloc: %d elems (%.1f MB)\n", tmp.size(), tmp.size() * sizeof(T) / 1000000.0);
+ int i = 0;
+ for (int j = first; j < buf.size(); j++) tmp[i++] = buf[j];
+ for (int j = 0 ; j < end ; j++) tmp[i++] = buf[j];
+ first = 0;
+ end = buf.size();
+ tmp.moveTo(buf);
+ }
+ }
+};
+
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/minisat/Rnd.h b/libs/minisat/Rnd.h
new file mode 100644
index 00000000..ccb94c6c
--- /dev/null
+++ b/libs/minisat/Rnd.h
@@ -0,0 +1,67 @@
+/*******************************************************************************************[Rnd.h]
+Copyright (c) 2012, Niklas Sorensson
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_Rnd_h
+#define Minisat_Rnd_h
+
+#include "Vec.h"
+
+namespace Minisat {
+
+// Generate a random double:
+static inline double drand(double& seed)
+{
+ seed *= 1389796;
+ int q = (int)(seed / 2147483647);
+ seed -= (double)q * 2147483647;
+ return seed / 2147483647;
+}
+
+
+// Generate a random integer:
+static inline int irand(double& seed, int size) { return (int)(drand(seed) * size); }
+
+
+// Randomly shuffle the contents of a vector:
+template<class T>
+static void randomShuffle(double& seed, vec<T>& xs)
+{
+ for (int i = 0; i < xs.size(); i++){
+ int pick = i + irand(seed, xs.size() - i);
+ T tmp = xs[i];
+ xs[i] = xs[pick];
+ xs[pick] = tmp;
+ }
+}
+
+// Randomly shuffle a vector of a vector (ugly)
+template<class T>
+static void randomShuffle(double& seed, vec<vec<T> >& xs)
+{
+ for (int i = 0; i < xs.size(); i++){
+ int pick = i + irand(seed, xs.size() - i);
+ vec<T> tmp; xs[i].moveTo(tmp);
+ xs[pick].moveTo(xs[i]);
+ tmp.moveTo(xs[pick]);
+ }
+}
+
+
+//=================================================================================================
+} // namespace Minisat
+#endif
diff --git a/libs/minisat/SimpSolver.cc b/libs/minisat/SimpSolver.cc
new file mode 100644
index 00000000..fd5774e0
--- /dev/null
+++ b/libs/minisat/SimpSolver.cc
@@ -0,0 +1,727 @@
+#define __STDC_FORMAT_MACROS
+#define __STDC_LIMIT_MACROS
+/***********************************************************************************[SimpSolver.cc]
+Copyright (c) 2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#include "Sort.h"
+#include "SimpSolver.h"
+#include "System.h"
+
+using namespace Minisat;
+
+//=================================================================================================
+// Options:
+
+
+static const char* _cat = "SIMP";
+
+static BoolOption opt_use_asymm (_cat, "asymm", "Shrink clauses by asymmetric branching.", false);
+static BoolOption opt_use_rcheck (_cat, "rcheck", "Check if a clause is already implied. (costly)", false);
+static BoolOption opt_use_elim (_cat, "elim", "Perform variable elimination.", true);
+static IntOption opt_grow (_cat, "grow", "Allow a variable elimination step to grow by a number of clauses.", 0);
+static IntOption opt_clause_lim (_cat, "cl-lim", "Variables are not eliminated if it produces a resolvent with a length above this limit. -1 means no limit", 20, IntRange(-1, INT32_MAX));
+static IntOption opt_subsumption_lim (_cat, "sub-lim", "Do not check if subsumption against a clause larger than this. -1 means no limit.", 1000, IntRange(-1, INT32_MAX));
+static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered during simplification.", 0.5, DoubleRange(0, false, HUGE_VAL, false));
+
+
+//=================================================================================================
+// Constructor/Destructor:
+
+
+SimpSolver::SimpSolver() :
+ grow (opt_grow)
+ , clause_lim (opt_clause_lim)
+ , subsumption_lim (opt_subsumption_lim)
+ , simp_garbage_frac (opt_simp_garbage_frac)
+ , use_asymm (opt_use_asymm)
+ , use_rcheck (opt_use_rcheck)
+ , use_elim (opt_use_elim)
+ , extend_model (true)
+ , merges (0)
+ , asymm_lits (0)
+ , eliminated_vars (0)
+ , elimorder (1)
+ , use_simplification (true)
+ , occurs (ClauseDeleted(ca))
+ , elim_heap (ElimLt(n_occ))
+ , bwdsub_assigns (0)
+ , n_touched (0)
+{
+ vec<Lit> dummy(1,lit_Undef);
+ ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below.
+ bwdsub_tmpunit = ca.alloc(dummy);
+ remove_satisfied = false;
+}
+
+
+SimpSolver::~SimpSolver()
+{
+}
+
+
+Var SimpSolver::newVar(lbool upol, bool dvar) {
+ Var v = Solver::newVar(upol, dvar);
+
+ frozen .insert(v, (char)false);
+ eliminated.insert(v, (char)false);
+
+ if (use_simplification){
+ n_occ .insert( mkLit(v), 0);
+ n_occ .insert(~mkLit(v), 0);
+ occurs .init (v);
+ touched .insert(v, 0);
+ elim_heap .insert(v);
+ }
+ return v; }
+
+
+void SimpSolver::releaseVar(Lit l)
+{
+ assert(!isEliminated(var(l)));
+ if (!use_simplification && var(l) >= max_simp_var)
+ // Note: Guarantees that no references to this variable is
+ // left in model extension datastructure. Could be improved!
+ Solver::releaseVar(l);
+ else
+ // Otherwise, don't allow variable to be reused.
+ Solver::addClause(l);
+}
+
+
+lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
+{
+ vec<Var> extra_frozen;
+ lbool result = l_True;
+
+ do_simp &= use_simplification;
+
+ if (do_simp){
+ // Assumptions must be temporarily frozen to run variable elimination:
+ for (int i = 0; i < assumptions.size(); i++){
+ Var v = var(assumptions[i]);
+
+ // If an assumption has been eliminated, remember it.
+ assert(!isEliminated(v));
+
+ if (!frozen[v]){
+ // Freeze and store.
+ setFrozen(v, true);
+ extra_frozen.push(v);
+ } }
+
+ result = lbool(eliminate(turn_off_simp));
+ }
+
+ if (result == l_True)
+ result = Solver::solve_();
+ else if (verbosity >= 1)
+ printf("===============================================================================\n");
+
+ if (result == l_True && extend_model)
+ extendModel();
+
+ if (do_simp)
+ // Unfreeze the assumptions that were frozen:
+ for (int i = 0; i < extra_frozen.size(); i++)
+ setFrozen(extra_frozen[i], false);
+
+ return result;
+}
+
+
+
+bool SimpSolver::addClause_(vec<Lit>& ps)
+{
+#ifndef NDEBUG
+ for (int i = 0; i < ps.size(); i++)
+ assert(!isEliminated(var(ps[i])));
+#endif
+
+ int nclauses = clauses.size();
+
+ if (use_rcheck && implied(ps))
+ return true;
+
+ if (!Solver::addClause_(ps))
+ return false;
+
+ if (use_simplification && clauses.size() == nclauses + 1){
+ CRef cr = clauses.last();
+ const Clause& c = ca[cr];
+
+ // NOTE: the clause is added to the queue immediately and then
+ // again during 'gatherTouchedClauses()'. If nothing happens
+ // in between, it will only be checked once. Otherwise, it may
+ // be checked twice unnecessarily. This is an unfortunate
+ // consequence of how backward subsumption is used to mimic
+ // forward subsumption.
+ subsumption_queue.insert(cr);
+ for (int i = 0; i < c.size(); i++){
+ occurs[var(c[i])].push(cr);
+ n_occ[c[i]]++;
+ touched[var(c[i])] = 1;
+ n_touched++;
+ if (elim_heap.inHeap(var(c[i])))
+ elim_heap.increase(var(c[i]));
+ }
+ }
+
+ return true;
+}
+
+
+void SimpSolver::removeClause(CRef cr)
+{
+ const Clause& c = ca[cr];
+
+ if (use_simplification)
+ for (int i = 0; i < c.size(); i++){
+ n_occ[c[i]]--;
+ updateElimHeap(var(c[i]));
+ occurs.smudge(var(c[i]));
+ }
+
+ Solver::removeClause(cr);
+}
+
+
+bool SimpSolver::strengthenClause(CRef cr, Lit l)
+{
+ Clause& c = ca[cr];
+ assert(decisionLevel() == 0);
+ assert(use_simplification);
+
+ // FIX: this is too inefficient but would be nice to have (properly implemented)
+ // if (!find(subsumption_queue, &c))
+ subsumption_queue.insert(cr);
+
+ if (c.size() == 2){
+ removeClause(cr);
+ c.strengthen(l);
+ }else{
+ detachClause(cr, true);
+ c.strengthen(l);
+ attachClause(cr);
+ remove(occurs[var(l)], cr);
+ n_occ[l]--;
+ updateElimHeap(var(l));
+ }
+
+ return c.size() == 1 ? enqueue(c[0]) && propagate() == CRef_Undef : true;
+}
+
+
+// Returns FALSE if clause is always satisfied ('out_clause' should not be used).
+bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause)
+{
+ merges++;
+ out_clause.clear();
+
+ bool ps_smallest = _ps.size() < _qs.size();
+ const Clause& ps = ps_smallest ? _qs : _ps;
+ const Clause& qs = ps_smallest ? _ps : _qs;
+
+ for (int i = 0; i < qs.size(); i++){
+ if (var(qs[i]) != v){
+ for (int j = 0; j < ps.size(); j++)
+ if (var(ps[j]) == var(qs[i])){
+ if (ps[j] == ~qs[i])
+ return false;
+ else
+ goto next;
+ }
+ out_clause.push(qs[i]);
+ }
+ next:;
+ }
+
+ for (int i = 0; i < ps.size(); i++)
+ if (var(ps[i]) != v)
+ out_clause.push(ps[i]);
+
+ return true;
+}
+
+
+// Returns FALSE if clause is always satisfied.
+bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, int& size)
+{
+ merges++;
+
+ bool ps_smallest = _ps.size() < _qs.size();
+ const Clause& ps = ps_smallest ? _qs : _ps;
+ const Clause& qs = ps_smallest ? _ps : _qs;
+ const Lit* __ps = (const Lit*)ps;
+ const Lit* __qs = (const Lit*)qs;
+
+ size = ps.size()-1;
+
+ for (int i = 0; i < qs.size(); i++){
+ if (var(__qs[i]) != v){
+ for (int j = 0; j < ps.size(); j++)
+ if (var(__ps[j]) == var(__qs[i])){
+ if (__ps[j] == ~__qs[i])
+ return false;
+ else
+ goto next;
+ }
+ size++;
+ }
+ next:;
+ }
+
+ return true;
+}
+
+
+void SimpSolver::gatherTouchedClauses()
+{
+ if (n_touched == 0) return;
+
+ int i,j;
+ for (i = j = 0; i < subsumption_queue.size(); i++)
+ if (ca[subsumption_queue[i]].mark() == 0)
+ ca[subsumption_queue[i]].mark(2);
+
+ for (i = 0; i < nVars(); i++)
+ if (touched[i]){
+ const vec<CRef>& cs = occurs.lookup(i);
+ for (j = 0; j < cs.size(); j++)
+ if (ca[cs[j]].mark() == 0){
+ subsumption_queue.insert(cs[j]);
+ ca[cs[j]].mark(2);
+ }
+ touched[i] = 0;
+ }
+
+ for (i = 0; i < subsumption_queue.size(); i++)
+ if (ca[subsumption_queue[i]].mark() == 2)
+ ca[subsumption_queue[i]].mark(0);
+
+ n_touched = 0;
+}
+
+
+bool SimpSolver::implied(const vec<Lit>& c)
+{
+ assert(decisionLevel() == 0);
+
+ trail_lim.push(trail.size());
+ for (int i = 0; i < c.size(); i++)
+ if (value(c[i]) == l_True){
+ cancelUntil(0);
+ return true;
+ }else if (value(c[i]) != l_False){
+ assert(value(c[i]) == l_Undef);
+ uncheckedEnqueue(~c[i]);
+ }
+
+ bool result = propagate() != CRef_Undef;
+ cancelUntil(0);
+ return result;
+}
+
+
+// Backward subsumption + backward subsumption resolution
+bool SimpSolver::backwardSubsumptionCheck(bool verbose)
+{
+ int cnt = 0;
+ int subsumed = 0;
+ int deleted_literals = 0;
+ assert(decisionLevel() == 0);
+
+ while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){
+
+ // Empty subsumption queue and return immediately on user-interrupt:
+ if (asynch_interrupt){
+ subsumption_queue.clear();
+ bwdsub_assigns = trail.size();
+ break; }
+
+ // Check top-level assignments by creating a dummy clause and placing it in the queue:
+ if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){
+ Lit l = trail[bwdsub_assigns++];
+ ca[bwdsub_tmpunit][0] = l;
+ ca[bwdsub_tmpunit].calcAbstraction();
+ subsumption_queue.insert(bwdsub_tmpunit); }
+
+ CRef cr = subsumption_queue.peek(); subsumption_queue.pop();
+ Clause& c = ca[cr];
+
+ if (c.mark()) continue;
+
+ if (verbose && verbosity >= 2 && cnt++ % 1000 == 0)
+ printf("subsumption left: %10d (%10d subsumed, %10d deleted literals)\r", subsumption_queue.size(), subsumed, deleted_literals);
+
+ assert(c.size() > 1 || value(c[0]) == l_True); // Unit-clauses should have been propagated before this point.
+
+ // Find best variable to scan:
+ Var best = var(c[0]);
+ for (int i = 1; i < c.size(); i++)
+ if (occurs[var(c[i])].size() < occurs[best].size())
+ best = var(c[i]);
+
+ // Search all candidates:
+ vec<CRef>& _cs = occurs.lookup(best);
+ CRef* cs = (CRef*)_cs;
+
+ for (int j = 0; j < _cs.size(); j++)
+ if (c.mark())
+ break;
+ else if (!ca[cs[j]].mark() && cs[j] != cr && (subsumption_lim == -1 || ca[cs[j]].size() < subsumption_lim)){
+ Lit l = c.subsumes(ca[cs[j]]);
+
+ if (l == lit_Undef)
+ subsumed++, removeClause(cs[j]);
+ else if (l != lit_Error){
+ deleted_literals++;
+
+ if (!strengthenClause(cs[j], ~l))
+ return false;
+
+ // Did current candidate get deleted from cs? Then check candidate at index j again:
+ if (var(l) == best)
+ j--;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+bool SimpSolver::asymm(Var v, CRef cr)
+{
+ Clause& c = ca[cr];
+ assert(decisionLevel() == 0);
+
+ if (c.mark() || satisfied(c)) return true;
+
+ trail_lim.push(trail.size());
+ Lit l = lit_Undef;
+ for (int i = 0; i < c.size(); i++)
+ if (var(c[i]) != v && value(c[i]) != l_False)
+ uncheckedEnqueue(~c[i]);
+ else
+ l = c[i];
+
+ if (propagate() != CRef_Undef){
+ cancelUntil(0);
+ asymm_lits++;
+ if (!strengthenClause(cr, l))
+ return false;
+ }else
+ cancelUntil(0);
+
+ return true;
+}
+
+
+bool SimpSolver::asymmVar(Var v)
+{
+ assert(use_simplification);
+
+ const vec<CRef>& cls = occurs.lookup(v);
+
+ if (value(v) != l_Undef || cls.size() == 0)
+ return true;
+
+ for (int i = 0; i < cls.size(); i++)
+ if (!asymm(v, cls[i]))
+ return false;
+
+ return backwardSubsumptionCheck();
+}
+
+
+static void mkElimClause(vec<uint32_t>& elimclauses, Lit x)
+{
+ elimclauses.push(toInt(x));
+ elimclauses.push(1);
+}
+
+
+static void mkElimClause(vec<uint32_t>& elimclauses, Var v, Clause& c)
+{
+ int first = elimclauses.size();
+ int v_pos = -1;
+
+ // Copy clause to elimclauses-vector. Remember position where the
+ // variable 'v' occurs:
+ for (int i = 0; i < c.size(); i++){
+ elimclauses.push(toInt(c[i]));
+ if (var(c[i]) == v)
+ v_pos = i + first;
+ }
+ assert(v_pos != -1);
+
+ // Swap the first literal with the 'v' literal, so that the literal
+ // containing 'v' will occur first in the clause:
+ uint32_t tmp = elimclauses[v_pos];
+ elimclauses[v_pos] = elimclauses[first];
+ elimclauses[first] = tmp;
+
+ // Store the length of the clause last:
+ elimclauses.push(c.size());
+}
+
+
+
+bool SimpSolver::eliminateVar(Var v)
+{
+ assert(!frozen[v]);
+ assert(!isEliminated(v));
+ assert(value(v) == l_Undef);
+
+ // Split the occurrences into positive and negative:
+ //
+ const vec<CRef>& cls = occurs.lookup(v);
+ vec<CRef> pos, neg;
+ for (int i = 0; i < cls.size(); i++)
+ (find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]);
+
+ // Check wether the increase in number of clauses stays within the allowed ('grow'). Moreover, no
+ // clause must exceed the limit on the maximal clause size (if it is set):
+ //
+ int cnt = 0;
+ int clause_size = 0;
+
+ for (int i = 0; i < pos.size(); i++)
+ for (int j = 0; j < neg.size(); j++)
+ if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) &&
+ (++cnt > cls.size() + grow || (clause_lim != -1 && clause_size > clause_lim)))
+ return true;
+
+ // Delete and store old clauses:
+ eliminated[v] = true;
+ setDecisionVar(v, false);
+ eliminated_vars++;
+
+ if (pos.size() > neg.size()){
+ for (int i = 0; i < neg.size(); i++)
+ mkElimClause(elimclauses, v, ca[neg[i]]);
+ mkElimClause(elimclauses, mkLit(v));
+ }else{
+ for (int i = 0; i < pos.size(); i++)
+ mkElimClause(elimclauses, v, ca[pos[i]]);
+ mkElimClause(elimclauses, ~mkLit(v));
+ }
+
+ for (int i = 0; i < cls.size(); i++)
+ removeClause(cls[i]);
+
+ // Produce clauses in cross product:
+ vec<Lit>& resolvent = add_tmp;
+ for (int i = 0; i < pos.size(); i++)
+ for (int j = 0; j < neg.size(); j++)
+ if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent))
+ return false;
+
+ // Free occurs list for this variable:
+ occurs[v].clear(true);
+
+ // Free watchers lists for this variable, if possible:
+ if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true);
+ if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true);
+
+ return backwardSubsumptionCheck();
+}
+
+
+bool SimpSolver::substitute(Var v, Lit x)
+{
+ assert(!frozen[v]);
+ assert(!isEliminated(v));
+ assert(value(v) == l_Undef);
+
+ if (!ok) return false;
+
+ eliminated[v] = true;
+ setDecisionVar(v, false);
+ const vec<CRef>& cls = occurs.lookup(v);
+
+ vec<Lit>& subst_clause = add_tmp;
+ for (int i = 0; i < cls.size(); i++){
+ Clause& c = ca[cls[i]];
+
+ subst_clause.clear();
+ for (int j = 0; j < c.size(); j++){
+ Lit p = c[j];
+ subst_clause.push(var(p) == v ? x ^ sign(p) : p);
+ }
+
+ removeClause(cls[i]);
+
+ if (!addClause_(subst_clause))
+ return ok = false;
+ }
+
+ return true;
+}
+
+
+void SimpSolver::extendModel()
+{
+ int i, j;
+ Lit x;
+
+ for (i = elimclauses.size()-1; i > 0; i -= j){
+ for (j = elimclauses[i--]; j > 1; j--, i--)
+ if (modelValue(toLit(elimclauses[i])) != l_False)
+ goto next;
+
+ x = toLit(elimclauses[i]);
+ model[var(x)] = lbool(!sign(x));
+ next:;
+ }
+}
+
+
+bool SimpSolver::eliminate(bool turn_off_elim)
+{
+ if (!simplify())
+ return false;
+ else if (!use_simplification)
+ return true;
+
+ // Main simplification loop:
+ //
+ while (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0){
+
+ gatherTouchedClauses();
+ // printf(" ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns);
+ if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) &&
+ !backwardSubsumptionCheck(true)){
+ ok = false; goto cleanup; }
+
+ // Empty elim_heap and return immediately on user-interrupt:
+ if (asynch_interrupt){
+ assert(bwdsub_assigns == trail.size());
+ assert(subsumption_queue.size() == 0);
+ assert(n_touched == 0);
+ elim_heap.clear();
+ goto cleanup; }
+
+ // printf(" ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), elim_heap.size());
+ for (int cnt = 0; !elim_heap.empty(); cnt++){
+ Var elim = elim_heap.removeMin();
+
+ if (asynch_interrupt) break;
+
+ if (isEliminated(elim) || value(elim) != l_Undef) continue;
+
+ if (verbosity >= 2 && cnt % 100 == 0)
+ printf("elimination left: %10d\r", elim_heap.size());
+
+ if (use_asymm){
+ // Temporarily freeze variable. Otherwise, it would immediately end up on the queue again:
+ bool was_frozen = frozen[elim];
+ frozen[elim] = true;
+ if (!asymmVar(elim)){
+ ok = false; goto cleanup; }
+ frozen[elim] = was_frozen; }
+
+ // At this point, the variable may have been set by assymetric branching, so check it
+ // again. Also, don't eliminate frozen variables:
+ if (use_elim && value(elim) == l_Undef && !frozen[elim] && !eliminateVar(elim)){
+ ok = false; goto cleanup; }
+
+ checkGarbage(simp_garbage_frac);
+ }
+
+ assert(subsumption_queue.size() == 0);
+ }
+ cleanup:
+
+ // If no more simplification is needed, free all simplification-related data structures:
+ if (turn_off_elim){
+ touched .clear(true);
+ occurs .clear(true);
+ n_occ .clear(true);
+ elim_heap.clear(true);
+ subsumption_queue.clear(true);
+
+ use_simplification = false;
+ remove_satisfied = true;
+ ca.extra_clause_field = false;
+ max_simp_var = nVars();
+
+ // Force full cleanup (this is safe and desirable since it only happens once):
+ rebuildOrderHeap();
+ garbageCollect();
+ }else{
+ // Cheaper cleanup:
+ checkGarbage();
+ }
+
+ if (verbosity >= 1 && elimclauses.size() > 0)
+ printf("| Eliminated clauses: %10.2f Mb |\n",
+ double(elimclauses.size() * sizeof(uint32_t)) / (1024*1024));
+
+ return ok;
+}
+
+
+//=================================================================================================
+// Garbage Collection methods:
+
+
+void SimpSolver::relocAll(ClauseAllocator& to)
+{
+ if (!use_simplification) return;
+
+ // All occurs lists:
+ //
+ for (int i = 0; i < nVars(); i++){
+ occurs.clean(i);
+ vec<CRef>& cs = occurs[i];
+ for (int j = 0; j < cs.size(); j++)
+ ca.reloc(cs[j], to);
+ }
+
+ // Subsumption queue:
+ //
+ for (int i = subsumption_queue.size(); i > 0; i--){
+ CRef cr = subsumption_queue.peek(); subsumption_queue.pop();
+ if (ca[cr].mark()) continue;
+ ca.reloc(cr, to);
+ subsumption_queue.insert(cr);
+ }
+
+ // Temporary clause:
+ //
+ ca.reloc(bwdsub_tmpunit, to);
+}
+
+
+void SimpSolver::garbageCollect()
+{
+ // Initialize the next region to a size corresponding to the estimated utilization degree. This
+ // is not precise but should avoid some unnecessary reallocations for the new region:
+ ClauseAllocator to(ca.size() - ca.wasted());
+
+ to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields.
+ relocAll(to);
+ Solver::relocAll(to);
+ if (verbosity >= 2)
+ printf("| Garbage collection: %12d bytes => %12d bytes |\n",
+ ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size);
+ to.moveTo(ca);
+}
diff --git a/libs/minisat/SimpSolver.h b/libs/minisat/SimpSolver.h
new file mode 100644
index 00000000..76d5aca1
--- /dev/null
+++ b/libs/minisat/SimpSolver.h
@@ -0,0 +1,222 @@
+/************************************************************************************[SimpSolver.h]
+Copyright (c) 2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_SimpSolver_h
+#define Minisat_SimpSolver_h
+
+#include "Queue.h"
+#include "Solver.h"
+
+
+namespace Minisat {
+
+//=================================================================================================
+
+
+class SimpSolver : public Solver {
+ public:
+ // Constructor/Destructor:
+ //
+ SimpSolver();
+ ~SimpSolver();
+
+ // Problem specification:
+ //
+ Var newVar (lbool upol = l_Undef, bool dvar = true);
+ void releaseVar(Lit l);
+ bool addClause (const vec<Lit>& ps);
+ bool addEmptyClause(); // Add the empty clause to the solver.
+ bool addClause (Lit p); // Add a unit clause to the solver.
+ bool addClause (Lit p, Lit q); // Add a binary clause to the solver.
+ bool addClause (Lit p, Lit q, Lit r); // Add a ternary clause to the solver.
+ bool addClause (Lit p, Lit q, Lit r, Lit s); // Add a quaternary clause to the solver.
+ bool addClause_( vec<Lit>& ps);
+ bool substitute(Var v, Lit x); // Replace all occurences of v with x (may cause a contradiction).
+
+ // Variable mode:
+ //
+ void setFrozen (Var v, bool b); // If a variable is frozen it will not be eliminated.
+ bool isEliminated(Var v) const;
+
+ // Alternative freeze interface (may replace 'setFrozen()'):
+ void freezeVar (Var v); // Freeze one variable so it will not be eliminated.
+ void thaw (); // Thaw all frozen variables.
+
+
+ // Solving:
+ //
+ bool solve (const vec<Lit>& assumps, bool do_simp = true, bool turn_off_simp = false);
+ lbool solveLimited(const vec<Lit>& assumps, bool do_simp = true, bool turn_off_simp = false);
+ bool solve ( bool do_simp = true, bool turn_off_simp = false);
+ bool solve (Lit p , bool do_simp = true, bool turn_off_simp = false);
+ bool solve (Lit p, Lit q, bool do_simp = true, bool turn_off_simp = false);
+ bool solve (Lit p, Lit q, Lit r, bool do_simp = true, bool turn_off_simp = false);
+ bool eliminate (bool turn_off_elim = false); // Perform variable elimination based simplification.
+
+ // Memory managment:
+ //
+ virtual void garbageCollect();
+
+
+ // Generate a (possibly simplified) DIMACS file:
+ //
+#if 0
+ void toDimacs (const char* file, const vec<Lit>& assumps);
+ void toDimacs (const char* file);
+ void toDimacs (const char* file, Lit p);
+ void toDimacs (const char* file, Lit p, Lit q);
+ void toDimacs (const char* file, Lit p, Lit q, Lit r);
+#endif
+
+ // Mode of operation:
+ //
+ int grow; // Allow a variable elimination step to grow by a number of clauses (default to zero).
+ int clause_lim; // Variables are not eliminated if it produces a resolvent with a length above this limit.
+ // -1 means no limit.
+ int subsumption_lim; // Do not check if subsumption against a clause larger than this. -1 means no limit.
+ double simp_garbage_frac; // A different limit for when to issue a GC during simplification (Also see 'garbage_frac').
+
+ bool use_asymm; // Shrink clauses by asymmetric branching.
+ bool use_rcheck; // Check if a clause is already implied. Prett costly, and subsumes subsumptions :)
+ bool use_elim; // Perform variable elimination.
+ bool extend_model; // Flag to indicate whether the user needs to look at the full model.
+
+ // Statistics:
+ //
+ int merges;
+ int asymm_lits;
+ int eliminated_vars;
+
+ protected:
+
+ // Helper structures:
+ //
+ struct ElimLt {
+ const LMap<int>& n_occ;
+ explicit ElimLt(const LMap<int>& no) : n_occ(no) {}
+
+ // TODO: are 64-bit operations here noticably bad on 32-bit platforms? Could use a saturating
+ // 32-bit implementation instead then, but this will have to do for now.
+ uint64_t cost (Var x) const { return (uint64_t)n_occ[mkLit(x)] * (uint64_t)n_occ[~mkLit(x)]; }
+ bool operator()(Var x, Var y) const { return cost(x) < cost(y); }
+
+ // TODO: investigate this order alternative more.
+ // bool operator()(Var x, Var y) const {
+ // int c_x = cost(x);
+ // int c_y = cost(y);
+ // return c_x < c_y || c_x == c_y && x < y; }
+ };
+
+ struct ClauseDeleted {
+ const ClauseAllocator& ca;
+ explicit ClauseDeleted(const ClauseAllocator& _ca) : ca(_ca) {}
+ bool operator()(const CRef& cr) const { return ca[cr].mark() == 1; } };
+
+ // Solver state:
+ //
+ int elimorder;
+ bool use_simplification;
+ Var max_simp_var; // Max variable at the point simplification was turned off.
+ vec<uint32_t> elimclauses;
+ VMap<char> touched;
+ OccLists<Var, vec<CRef>, ClauseDeleted>
+ occurs;
+ LMap<int> n_occ;
+ Heap<Var,ElimLt> elim_heap;
+ Queue<CRef> subsumption_queue;
+ VMap<char> frozen;
+ vec<Var> frozen_vars;
+ VMap<char> eliminated;
+ int bwdsub_assigns;
+ int n_touched;
+
+ // Temporaries:
+ //
+ CRef bwdsub_tmpunit;
+
+ // Main internal methods:
+ //
+ lbool solve_ (bool do_simp = true, bool turn_off_simp = false);
+ bool asymm (Var v, CRef cr);
+ bool asymmVar (Var v);
+ void updateElimHeap (Var v);
+ void gatherTouchedClauses ();
+ bool merge (const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause);
+ bool merge (const Clause& _ps, const Clause& _qs, Var v, int& size);
+ bool backwardSubsumptionCheck (bool verbose = false);
+ bool eliminateVar (Var v);
+ void extendModel ();
+
+ void removeClause (CRef cr);
+ bool strengthenClause (CRef cr, Lit l);
+ bool implied (const vec<Lit>& c);
+ void relocAll (ClauseAllocator& to);
+};
+
+
+//=================================================================================================
+// Implementation of inline methods:
+
+
+inline bool SimpSolver::isEliminated (Var v) const { return eliminated[v]; }
+inline void SimpSolver::updateElimHeap(Var v) {
+ assert(use_simplification);
+ // if (!frozen[v] && !isEliminated(v) && value(v) == l_Undef)
+ if (elim_heap.inHeap(v) || (!frozen[v] && !isEliminated(v) && value(v) == l_Undef))
+ elim_heap.update(v); }
+
+
+inline bool SimpSolver::addClause (const vec<Lit>& ps) { ps.copyTo(add_tmp); return addClause_(add_tmp); }
+inline bool SimpSolver::addEmptyClause() { add_tmp.clear(); return addClause_(add_tmp); }
+inline bool SimpSolver::addClause (Lit p) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); }
+inline bool SimpSolver::addClause (Lit p, Lit q) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); }
+inline bool SimpSolver::addClause (Lit p, Lit q, Lit r) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); }
+inline bool SimpSolver::addClause (Lit p, Lit q, Lit r, Lit s){ add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); add_tmp.push(s); return addClause_(add_tmp); }
+inline void SimpSolver::setFrozen (Var v, bool b) { frozen[v] = (char)b; if (use_simplification && !b) { updateElimHeap(v); } }
+
+inline void SimpSolver::freezeVar(Var v){
+ if (!frozen[v]){
+ frozen[v] = 1;
+ frozen_vars.push(v);
+ } }
+
+inline void SimpSolver::thaw(){
+ for (int i = 0; i < frozen_vars.size(); i++){
+ Var v = frozen_vars[i];
+ frozen[v] = 0;
+ if (use_simplification)
+ updateElimHeap(v);
+ }
+ frozen_vars.clear(); }
+
+inline bool SimpSolver::solve ( bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); return solve_(do_simp, turn_off_simp) == l_True; }
+inline bool SimpSolver::solve (Lit p , bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); return solve_(do_simp, turn_off_simp) == l_True; }
+inline bool SimpSolver::solve (Lit p, Lit q, bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); return solve_(do_simp, turn_off_simp) == l_True; }
+inline bool SimpSolver::solve (Lit p, Lit q, Lit r, bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); assumptions.push(r); return solve_(do_simp, turn_off_simp) == l_True; }
+inline bool SimpSolver::solve (const vec<Lit>& assumps, bool do_simp, bool turn_off_simp){
+ budgetOff(); assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp) == l_True; }
+
+inline lbool SimpSolver::solveLimited (const vec<Lit>& assumps, bool do_simp, bool turn_off_simp){
+ assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp); }
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/minisat/Solver.cc b/libs/minisat/Solver.cc
new file mode 100644
index 00000000..ab476853
--- /dev/null
+++ b/libs/minisat/Solver.cc
@@ -0,0 +1,1068 @@
+#define __STDC_FORMAT_MACROS
+#define __STDC_LIMIT_MACROS
+/***************************************************************************************[Solver.cc]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#include <math.h>
+
+#include "Alg.h"
+#include "Sort.h"
+#include "System.h"
+#include "Solver.h"
+
+using namespace Minisat;
+
+//=================================================================================================
+// Options:
+
+
+static const char* _cat = "CORE";
+
+static DoubleOption opt_var_decay (_cat, "var-decay", "The variable activity decay factor", 0.95, DoubleRange(0, false, 1, false));
+static DoubleOption opt_clause_decay (_cat, "cla-decay", "The clause activity decay factor", 0.999, DoubleRange(0, false, 1, false));
+static DoubleOption opt_random_var_freq (_cat, "rnd-freq", "The frequency with which the decision heuristic tries to choose a random variable", 0, DoubleRange(0, true, 1, true));
+static DoubleOption opt_random_seed (_cat, "rnd-seed", "Used by the random variable selection", 91648253, DoubleRange(0, false, HUGE_VAL, false));
+static IntOption opt_ccmin_mode (_cat, "ccmin-mode", "Controls conflict clause minimization (0=none, 1=basic, 2=deep)", 2, IntRange(0, 2));
+static IntOption opt_phase_saving (_cat, "phase-saving", "Controls the level of phase saving (0=none, 1=limited, 2=full)", 2, IntRange(0, 2));
+static BoolOption opt_rnd_init_act (_cat, "rnd-init", "Randomize the initial activity", false);
+static BoolOption opt_luby_restart (_cat, "luby", "Use the Luby restart sequence", true);
+static IntOption opt_restart_first (_cat, "rfirst", "The base restart interval", 100, IntRange(1, INT32_MAX));
+static DoubleOption opt_restart_inc (_cat, "rinc", "Restart interval increase factor", 2, DoubleRange(1, false, HUGE_VAL, false));
+static DoubleOption opt_garbage_frac (_cat, "gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered", 0.20, DoubleRange(0, false, HUGE_VAL, false));
+static IntOption opt_min_learnts_lim (_cat, "min-learnts", "Minimum learnt clause limit", 0, IntRange(0, INT32_MAX));
+
+
+//=================================================================================================
+// Constructor/Destructor:
+
+
+Solver::Solver() :
+
+ // Parameters (user settable):
+ //
+ verbosity (0)
+ , var_decay (opt_var_decay)
+ , clause_decay (opt_clause_decay)
+ , random_var_freq (opt_random_var_freq)
+ , random_seed (opt_random_seed)
+ , luby_restart (opt_luby_restart)
+ , ccmin_mode (opt_ccmin_mode)
+ , phase_saving (opt_phase_saving)
+ , rnd_pol (false)
+ , rnd_init_act (opt_rnd_init_act)
+ , garbage_frac (opt_garbage_frac)
+ , min_learnts_lim (opt_min_learnts_lim)
+ , restart_first (opt_restart_first)
+ , restart_inc (opt_restart_inc)
+
+ // Parameters (the rest):
+ //
+ , learntsize_factor((double)1/(double)3), learntsize_inc(1.1)
+
+ // Parameters (experimental):
+ //
+ , learntsize_adjust_start_confl (100)
+ , learntsize_adjust_inc (1.5)
+
+ // Statistics: (formerly in 'SolverStats')
+ //
+ , solves(0), starts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0)
+ , dec_vars(0), num_clauses(0), num_learnts(0), clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0)
+
+ , watches (WatcherDeleted(ca))
+ , order_heap (VarOrderLt(activity))
+ , ok (true)
+ , cla_inc (1)
+ , var_inc (1)
+ , qhead (0)
+ , simpDB_assigns (-1)
+ , simpDB_props (0)
+ , progress_estimate (0)
+ , remove_satisfied (true)
+ , next_var (0)
+
+ // Resource constraints:
+ //
+ , conflict_budget (-1)
+ , propagation_budget (-1)
+ , asynch_interrupt (false)
+{}
+
+
+Solver::~Solver()
+{
+}
+
+
+//=================================================================================================
+// Minor methods:
+
+
+// Creates a new SAT variable in the solver. If 'decision' is cleared, variable will not be
+// used as a decision variable (NOTE! This has effects on the meaning of a SATISFIABLE result).
+//
+Var Solver::newVar(lbool upol, bool dvar)
+{
+ Var v;
+ if (free_vars.size() > 0){
+ v = free_vars.last();
+ free_vars.pop();
+ }else
+ v = next_var++;
+
+ watches .init(mkLit(v, false));
+ watches .init(mkLit(v, true ));
+ assigns .insert(v, l_Undef);
+ vardata .insert(v, mkVarData(CRef_Undef, 0));
+ activity .insert(v, rnd_init_act ? drand(random_seed) * 0.00001 : 0);
+ seen .insert(v, 0);
+ polarity .insert(v, true);
+ user_pol .insert(v, upol);
+ decision .reserve(v);
+ trail .capacity(v+1);
+ setDecisionVar(v, dvar);
+ return v;
+}
+
+
+// Note: at the moment, only unassigned variable will be released (this is to avoid duplicate
+// releases of the same variable).
+void Solver::releaseVar(Lit l)
+{
+ if (value(l) == l_Undef){
+ addClause(l);
+ released_vars.push(var(l));
+ }
+}
+
+
+bool Solver::addClause_(vec<Lit>& ps)
+{
+ assert(decisionLevel() == 0);
+ if (!ok) return false;
+
+ // Check if clause is satisfied and remove false/duplicate literals:
+ sort(ps);
+ Lit p; int i, j;
+ for (i = j = 0, p = lit_Undef; i < ps.size(); i++)
+ if (value(ps[i]) == l_True || ps[i] == ~p)
+ return true;
+ else if (value(ps[i]) != l_False && ps[i] != p)
+ ps[j++] = p = ps[i];
+ ps.shrink(i - j);
+
+ if (ps.size() == 0)
+ return ok = false;
+ else if (ps.size() == 1){
+ uncheckedEnqueue(ps[0]);
+ return ok = (propagate() == CRef_Undef);
+ }else{
+ CRef cr = ca.alloc(ps, false);
+ clauses.push(cr);
+ attachClause(cr);
+ }
+
+ return true;
+}
+
+
+void Solver::attachClause(CRef cr){
+ const Clause& c = ca[cr];
+ assert(c.size() > 1);
+ watches[~c[0]].push(Watcher(cr, c[1]));
+ watches[~c[1]].push(Watcher(cr, c[0]));
+ if (c.learnt()) num_learnts++, learnts_literals += c.size();
+ else num_clauses++, clauses_literals += c.size();
+}
+
+
+void Solver::detachClause(CRef cr, bool strict){
+ const Clause& c = ca[cr];
+ assert(c.size() > 1);
+
+ // Strict or lazy detaching:
+ if (strict){
+ remove(watches[~c[0]], Watcher(cr, c[1]));
+ remove(watches[~c[1]], Watcher(cr, c[0]));
+ }else{
+ watches.smudge(~c[0]);
+ watches.smudge(~c[1]);
+ }
+
+ if (c.learnt()) num_learnts--, learnts_literals -= c.size();
+ else num_clauses--, clauses_literals -= c.size();
+}
+
+
+void Solver::removeClause(CRef cr) {
+ Clause& c = ca[cr];
+ detachClause(cr);
+ // Don't leave pointers to free'd memory!
+ if (locked(c)) vardata[var(c[0])].reason = CRef_Undef;
+ c.mark(1);
+ ca.free(cr);
+}
+
+
+bool Solver::satisfied(const Clause& c) const {
+ for (int i = 0; i < c.size(); i++)
+ if (value(c[i]) == l_True)
+ return true;
+ return false; }
+
+
+// Revert to the state at given level (keeping all assignment at 'level' but not beyond).
+//
+void Solver::cancelUntil(int level) {
+ if (decisionLevel() > level){
+ for (int c = trail.size()-1; c >= trail_lim[level]; c--){
+ Var x = var(trail[c]);
+ assigns [x] = l_Undef;
+ if (phase_saving > 1 || (phase_saving == 1 && c > trail_lim.last()))
+ polarity[x] = sign(trail[c]);
+ insertVarOrder(x); }
+ qhead = trail_lim[level];
+ trail.shrink(trail.size() - trail_lim[level]);
+ trail_lim.shrink(trail_lim.size() - level);
+ } }
+
+
+//=================================================================================================
+// Major methods:
+
+
+Lit Solver::pickBranchLit()
+{
+ Var next = var_Undef;
+
+ // Random decision:
+ if (drand(random_seed) < random_var_freq && !order_heap.empty()){
+ next = order_heap[irand(random_seed,order_heap.size())];
+ if (value(next) == l_Undef && decision[next])
+ rnd_decisions++; }
+
+ // Activity based decision:
+ while (next == var_Undef || value(next) != l_Undef || !decision[next])
+ if (order_heap.empty()){
+ next = var_Undef;
+ break;
+ }else
+ next = order_heap.removeMin();
+
+ // Choose polarity based on different polarity modes (global or per-variable):
+ if (next == var_Undef)
+ return lit_Undef;
+ else if (user_pol[next] != l_Undef)
+ return mkLit(next, user_pol[next] == l_True);
+ else if (rnd_pol)
+ return mkLit(next, drand(random_seed) < 0.5);
+ else
+ return mkLit(next, polarity[next]);
+}
+
+
+/*_________________________________________________________________________________________________
+|
+| analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel : int&) -> [void]
+|
+| Description:
+| Analyze conflict and produce a reason clause.
+|
+| Pre-conditions:
+| * 'out_learnt' is assumed to be cleared.
+| * Current decision level must be greater than root level.
+|
+| Post-conditions:
+| * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'.
+| * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision level of the
+| rest of literals. There may be others from the same level though.
+|
+|________________________________________________________________________________________________@*/
+void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel)
+{
+ int pathC = 0;
+ Lit p = lit_Undef;
+
+ // Generate conflict clause:
+ //
+ out_learnt.push(); // (leave room for the asserting literal)
+ int index = trail.size() - 1;
+
+ do{
+ assert(confl != CRef_Undef); // (otherwise should be UIP)
+ Clause& c = ca[confl];
+
+ if (c.learnt())
+ claBumpActivity(c);
+
+ for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++){
+ Lit q = c[j];
+
+ if (!seen[var(q)] && level(var(q)) > 0){
+ varBumpActivity(var(q));
+ seen[var(q)] = 1;
+ if (level(var(q)) >= decisionLevel())
+ pathC++;
+ else
+ out_learnt.push(q);
+ }
+ }
+
+ // Select next clause to look at:
+ while (!seen[var(trail[index--])]);
+ p = trail[index+1];
+ confl = reason(var(p));
+ seen[var(p)] = 0;
+ pathC--;
+
+ }while (pathC > 0);
+ out_learnt[0] = ~p;
+
+ // Simplify conflict clause:
+ //
+ int i, j;
+ out_learnt.copyTo(analyze_toclear);
+ if (ccmin_mode == 2){
+ for (i = j = 1; i < out_learnt.size(); i++)
+ if (reason(var(out_learnt[i])) == CRef_Undef || !litRedundant(out_learnt[i]))
+ out_learnt[j++] = out_learnt[i];
+
+ }else if (ccmin_mode == 1){
+ for (i = j = 1; i < out_learnt.size(); i++){
+ Var x = var(out_learnt[i]);
+
+ if (reason(x) == CRef_Undef)
+ out_learnt[j++] = out_learnt[i];
+ else{
+ Clause& c = ca[reason(var(out_learnt[i]))];
+ for (int k = 1; k < c.size(); k++)
+ if (!seen[var(c[k])] && level(var(c[k])) > 0){
+ out_learnt[j++] = out_learnt[i];
+ break; }
+ }
+ }
+ }else
+ i = j = out_learnt.size();
+
+ max_literals += out_learnt.size();
+ out_learnt.shrink(i - j);
+ tot_literals += out_learnt.size();
+
+ // Find correct backtrack level:
+ //
+ if (out_learnt.size() == 1)
+ out_btlevel = 0;
+ else{
+ int max_i = 1;
+ // Find the first literal assigned at the next-highest level:
+ for (int i = 2; i < out_learnt.size(); i++)
+ if (level(var(out_learnt[i])) > level(var(out_learnt[max_i])))
+ max_i = i;
+ // Swap-in this literal at index 1:
+ Lit p = out_learnt[max_i];
+ out_learnt[max_i] = out_learnt[1];
+ out_learnt[1] = p;
+ out_btlevel = level(var(p));
+ }
+
+ for (int j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0; // ('seen[]' is now cleared)
+}
+
+
+// Check if 'p' can be removed from a conflict clause.
+bool Solver::litRedundant(Lit p)
+{
+ enum { seen_undef = 0, seen_source = 1, seen_removable = 2, seen_failed = 3 };
+ assert(seen[var(p)] == seen_undef || seen[var(p)] == seen_source);
+ assert(reason(var(p)) != CRef_Undef);
+
+ Clause* c = &ca[reason(var(p))];
+ vec<ShrinkStackElem>& stack = analyze_stack;
+ stack.clear();
+
+ for (uint32_t i = 1; ; i++){
+ if (i < (uint32_t)c->size()){
+ // Checking 'p'-parents 'l':
+ Lit l = (*c)[i];
+
+ // Variable at level 0 or previously removable:
+ if (level(var(l)) == 0 || seen[var(l)] == seen_source || seen[var(l)] == seen_removable){
+ continue; }
+
+ // Check variable can not be removed for some local reason:
+ if (reason(var(l)) == CRef_Undef || seen[var(l)] == seen_failed){
+ stack.push(ShrinkStackElem(0, p));
+ for (int i = 0; i < stack.size(); i++)
+ if (seen[var(stack[i].l)] == seen_undef){
+ seen[var(stack[i].l)] = seen_failed;
+ analyze_toclear.push(stack[i].l);
+ }
+
+ return false;
+ }
+
+ // Recursively check 'l':
+ stack.push(ShrinkStackElem(i, p));
+ i = 0;
+ p = l;
+ c = &ca[reason(var(p))];
+ }else{
+ // Finished with current element 'p' and reason 'c':
+ if (seen[var(p)] == seen_undef){
+ seen[var(p)] = seen_removable;
+ analyze_toclear.push(p);
+ }
+
+ // Terminate with success if stack is empty:
+ if (stack.size() == 0) break;
+
+ // Continue with top element on stack:
+ i = stack.last().i;
+ p = stack.last().l;
+ c = &ca[reason(var(p))];
+
+ stack.pop();
+ }
+ }
+
+ return true;
+}
+
+
+/*_________________________________________________________________________________________________
+|
+| analyzeFinal : (p : Lit) -> [void]
+|
+| Description:
+| Specialized analysis procedure to express the final conflict in terms of assumptions.
+| Calculates the (possibly empty) set of assumptions that led to the assignment of 'p', and
+| stores the result in 'out_conflict'.
+|________________________________________________________________________________________________@*/
+void Solver::analyzeFinal(Lit p, LSet& out_conflict)
+{
+ out_conflict.clear();
+ out_conflict.insert(p);
+
+ if (decisionLevel() == 0)
+ return;
+
+ seen[var(p)] = 1;
+
+ for (int i = trail.size()-1; i >= trail_lim[0]; i--){
+ Var x = var(trail[i]);
+ if (seen[x]){
+ if (reason(x) == CRef_Undef){
+ assert(level(x) > 0);
+ out_conflict.insert(~trail[i]);
+ }else{
+ Clause& c = ca[reason(x)];
+ for (int j = 1; j < c.size(); j++)
+ if (level(var(c[j])) > 0)
+ seen[var(c[j])] = 1;
+ }
+ seen[x] = 0;
+ }
+ }
+
+ seen[var(p)] = 0;
+}
+
+
+void Solver::uncheckedEnqueue(Lit p, CRef from)
+{
+ assert(value(p) == l_Undef);
+ assigns[var(p)] = lbool(!sign(p));
+ vardata[var(p)] = mkVarData(from, decisionLevel());
+ trail.push_(p);
+}
+
+
+/*_________________________________________________________________________________________________
+|
+| propagate : [void] -> [Clause*]
+|
+| Description:
+| Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned,
+| otherwise CRef_Undef.
+|
+| Post-conditions:
+| * the propagation queue is empty, even if there was a conflict.
+|________________________________________________________________________________________________@*/
+CRef Solver::propagate()
+{
+ CRef confl = CRef_Undef;
+ int num_props = 0;
+
+ while (qhead < trail.size()){
+ Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate.
+ vec<Watcher>& ws = watches.lookup(p);
+ Watcher *i, *j, *end;
+ num_props++;
+
+ for (i = j = (Watcher*)ws, end = i + ws.size(); i != end;){
+ // Try to avoid inspecting the clause:
+ Lit blocker = i->blocker;
+ if (value(blocker) == l_True){
+ *j++ = *i++; continue; }
+
+ // Make sure the false literal is data[1]:
+ CRef cr = i->cref;
+ Clause& c = ca[cr];
+ Lit false_lit = ~p;
+ if (c[0] == false_lit)
+ c[0] = c[1], c[1] = false_lit;
+ assert(c[1] == false_lit);
+ i++;
+
+ // If 0th watch is true, then clause is already satisfied.
+ Lit first = c[0];
+ Watcher w = Watcher(cr, first);
+ if (first != blocker && value(first) == l_True){
+ *j++ = w; continue; }
+
+ // Look for new watch:
+ for (int k = 2; k < c.size(); k++)
+ if (value(c[k]) != l_False){
+ c[1] = c[k]; c[k] = false_lit;
+ watches[~c[1]].push(w);
+ goto NextClause; }
+
+ // Did not find watch -- clause is unit under assignment:
+ *j++ = w;
+ if (value(first) == l_False){
+ confl = cr;
+ qhead = trail.size();
+ // Copy the remaining watches:
+ while (i < end)
+ *j++ = *i++;
+ }else
+ uncheckedEnqueue(first, cr);
+
+ NextClause:;
+ }
+ ws.shrink(i - j);
+ }
+ propagations += num_props;
+ simpDB_props -= num_props;
+
+ return confl;
+}
+
+
+/*_________________________________________________________________________________________________
+|
+| reduceDB : () -> [void]
+|
+| Description:
+| Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked
+| clauses are clauses that are reason to some assignment. Binary clauses are never removed.
+|________________________________________________________________________________________________@*/
+struct reduceDB_lt {
+ ClauseAllocator& ca;
+ reduceDB_lt(ClauseAllocator& ca_) : ca(ca_) {}
+ bool operator () (CRef x, CRef y) {
+ return ca[x].size() > 2 && (ca[y].size() == 2 || ca[x].activity() < ca[y].activity()); }
+};
+void Solver::reduceDB()
+{
+ int i, j;
+ double extra_lim = cla_inc / learnts.size(); // Remove any clause below this activity
+
+ sort(learnts, reduceDB_lt(ca));
+ // Don't delete binary or locked clauses. From the rest, delete clauses from the first half
+ // and clauses with activity smaller than 'extra_lim':
+ for (i = j = 0; i < learnts.size(); i++){
+ Clause& c = ca[learnts[i]];
+ if (c.size() > 2 && !locked(c) && (i < learnts.size() / 2 || c.activity() < extra_lim))
+ removeClause(learnts[i]);
+ else
+ learnts[j++] = learnts[i];
+ }
+ learnts.shrink(i - j);
+ checkGarbage();
+}
+
+
+void Solver::removeSatisfied(vec<CRef>& cs)
+{
+ int i, j;
+ for (i = j = 0; i < cs.size(); i++){
+ Clause& c = ca[cs[i]];
+ if (satisfied(c))
+ removeClause(cs[i]);
+ else{
+ // Trim clause:
+ assert(value(c[0]) == l_Undef && value(c[1]) == l_Undef);
+ for (int k = 2; k < c.size(); k++)
+ if (value(c[k]) == l_False){
+ c[k--] = c[c.size()-1];
+ c.pop();
+ }
+ cs[j++] = cs[i];
+ }
+ }
+ cs.shrink(i - j);
+}
+
+
+void Solver::rebuildOrderHeap()
+{
+ vec<Var> vs;
+ for (Var v = 0; v < nVars(); v++)
+ if (decision[v] && value(v) == l_Undef)
+ vs.push(v);
+ order_heap.build(vs);
+}
+
+
+/*_________________________________________________________________________________________________
+|
+| simplify : [void] -> [bool]
+|
+| Description:
+| Simplify the clause database according to the current top-level assigment. Currently, the only
+| thing done here is the removal of satisfied clauses, but more things can be put here.
+|________________________________________________________________________________________________@*/
+bool Solver::simplify()
+{
+ assert(decisionLevel() == 0);
+
+ if (!ok || propagate() != CRef_Undef)
+ return ok = false;
+
+ if (nAssigns() == simpDB_assigns || (simpDB_props > 0))
+ return true;
+
+ // Remove satisfied clauses:
+ removeSatisfied(learnts);
+ if (remove_satisfied){ // Can be turned off.
+ removeSatisfied(clauses);
+
+ // TODO: what todo in if 'remove_satisfied' is false?
+
+ // Remove all released variables from the trail:
+ for (int i = 0; i < released_vars.size(); i++){
+ assert(seen[released_vars[i]] == 0);
+ seen[released_vars[i]] = 1;
+ }
+
+ int i, j;
+ for (i = j = 0; i < trail.size(); i++)
+ if (seen[var(trail[i])] == 0)
+ trail[j++] = trail[i];
+ trail.shrink(i - j);
+ //printf("trail.size()= %d, qhead = %d\n", trail.size(), qhead);
+ qhead = trail.size();
+
+ for (int i = 0; i < released_vars.size(); i++)
+ seen[released_vars[i]] = 0;
+
+ // Released variables are now ready to be reused:
+ append(released_vars, free_vars);
+ released_vars.clear();
+ }
+ checkGarbage();
+ rebuildOrderHeap();
+
+ simpDB_assigns = nAssigns();
+ simpDB_props = clauses_literals + learnts_literals; // (shouldn't depend on stats really, but it will do for now)
+
+ return true;
+}
+
+
+/*_________________________________________________________________________________________________
+|
+| search : (nof_conflicts : int) (params : const SearchParams&) -> [lbool]
+|
+| Description:
+| Search for a model the specified number of conflicts.
+| NOTE! Use negative value for 'nof_conflicts' indicate infinity.
+|
+| Output:
+| 'l_True' if a partial assigment that is consistent with respect to the clauseset is found. If
+| all variables are decision variables, this means that the clause set is satisfiable. 'l_False'
+| if the clause set is unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached.
+|________________________________________________________________________________________________@*/
+lbool Solver::search(int nof_conflicts)
+{
+ assert(ok);
+ int backtrack_level;
+ int conflictC = 0;
+ vec<Lit> learnt_clause;
+ starts++;
+
+ for (;;){
+ CRef confl = propagate();
+ if (confl != CRef_Undef){
+ // CONFLICT
+ conflicts++; conflictC++;
+ if (decisionLevel() == 0) return l_False;
+
+ learnt_clause.clear();
+ analyze(confl, learnt_clause, backtrack_level);
+ cancelUntil(backtrack_level);
+
+ if (learnt_clause.size() == 1){
+ uncheckedEnqueue(learnt_clause[0]);
+ }else{
+ CRef cr = ca.alloc(learnt_clause, true);
+ learnts.push(cr);
+ attachClause(cr);
+ claBumpActivity(ca[cr]);
+ uncheckedEnqueue(learnt_clause[0], cr);
+ }
+
+ varDecayActivity();
+ claDecayActivity();
+
+ if (--learntsize_adjust_cnt == 0){
+ learntsize_adjust_confl *= learntsize_adjust_inc;
+ learntsize_adjust_cnt = (int)learntsize_adjust_confl;
+ max_learnts *= learntsize_inc;
+
+ if (verbosity >= 1)
+ printf("| %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n",
+ (int)conflicts,
+ (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]), nClauses(), (int)clauses_literals,
+ (int)max_learnts, nLearnts(), (double)learnts_literals/nLearnts(), progressEstimate()*100);
+ }
+
+ }else{
+ // NO CONFLICT
+ if ((nof_conflicts >= 0 && conflictC >= nof_conflicts) || !withinBudget()){
+ // Reached bound on number of conflicts:
+ progress_estimate = progressEstimate();
+ cancelUntil(0);
+ return l_Undef; }
+
+ // Simplify the set of problem clauses:
+ if (decisionLevel() == 0 && !simplify())
+ return l_False;
+
+ if (learnts.size()-nAssigns() >= max_learnts)
+ // Reduce the set of learnt clauses:
+ reduceDB();
+
+ Lit next = lit_Undef;
+ while (decisionLevel() < assumptions.size()){
+ // Perform user provided assumption:
+ Lit p = assumptions[decisionLevel()];
+ if (value(p) == l_True){
+ // Dummy decision level:
+ newDecisionLevel();
+ }else if (value(p) == l_False){
+ analyzeFinal(~p, conflict);
+ return l_False;
+ }else{
+ next = p;
+ break;
+ }
+ }
+
+ if (next == lit_Undef){
+ // New variable decision:
+ decisions++;
+ next = pickBranchLit();
+
+ if (next == lit_Undef)
+ // Model found:
+ return l_True;
+ }
+
+ // Increase decision level and enqueue 'next'
+ newDecisionLevel();
+ uncheckedEnqueue(next);
+ }
+ }
+}
+
+
+double Solver::progressEstimate() const
+{
+ double progress = 0;
+ double F = 1.0 / nVars();
+
+ for (int i = 0; i <= decisionLevel(); i++){
+ int beg = i == 0 ? 0 : trail_lim[i - 1];
+ int end = i == decisionLevel() ? trail.size() : trail_lim[i];
+ progress += pow(F, i) * (end - beg);
+ }
+
+ return progress / nVars();
+}
+
+/*
+ Finite subsequences of the Luby-sequence:
+
+ 0: 1
+ 1: 1 1 2
+ 2: 1 1 2 1 1 2 4
+ 3: 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8
+ ...
+
+
+ */
+
+static double luby(double y, int x){
+
+ // Find the finite subsequence that contains index 'x', and the
+ // size of that subsequence:
+ int size, seq;
+ for (size = 1, seq = 0; size < x+1; seq++, size = 2*size+1);
+
+ while (size-1 != x){
+ size = (size-1)>>1;
+ seq--;
+ x = x % size;
+ }
+
+ return pow(y, seq);
+}
+
+// NOTE: assumptions passed in member-variable 'assumptions'.
+lbool Solver::solve_()
+{
+ model.clear();
+ conflict.clear();
+ if (!ok) return l_False;
+
+ solves++;
+
+ max_learnts = nClauses() * learntsize_factor;
+ if (max_learnts < min_learnts_lim)
+ max_learnts = min_learnts_lim;
+
+ learntsize_adjust_confl = learntsize_adjust_start_confl;
+ learntsize_adjust_cnt = (int)learntsize_adjust_confl;
+ lbool status = l_Undef;
+
+ if (verbosity >= 1){
+ printf("============================[ Search Statistics ]==============================\n");
+ printf("| Conflicts | ORIGINAL | LEARNT | Progress |\n");
+ printf("| | Vars Clauses Literals | Limit Clauses Lit/Cl | |\n");
+ printf("===============================================================================\n");
+ }
+
+ // Search:
+ int curr_restarts = 0;
+ while (status == l_Undef){
+ double rest_base = luby_restart ? luby(restart_inc, curr_restarts) : pow(restart_inc, curr_restarts);
+ status = search(rest_base * restart_first);
+ if (!withinBudget()) break;
+ curr_restarts++;
+ }
+
+ if (verbosity >= 1)
+ printf("===============================================================================\n");
+
+
+ if (status == l_True){
+ // Extend & copy model:
+ model.growTo(nVars());
+ for (int i = 0; i < nVars(); i++) model[i] = value(i);
+ }else if (status == l_False && conflict.size() == 0)
+ ok = false;
+
+ cancelUntil(0);
+ return status;
+}
+
+
+bool Solver::implies(const vec<Lit>& assumps, vec<Lit>& out)
+{
+ trail_lim.push(trail.size());
+ for (int i = 0; i < assumps.size(); i++){
+ Lit a = assumps[i];
+
+ if (value(a) == l_False){
+ cancelUntil(0);
+ return false;
+ }else if (value(a) == l_Undef)
+ uncheckedEnqueue(a);
+ }
+
+ unsigned trail_before = trail.size();
+ bool ret = true;
+ if (propagate() == CRef_Undef){
+ out.clear();
+ for (int j = trail_before; j < trail.size(); j++)
+ out.push(trail[j]);
+ }else
+ ret = false;
+
+ cancelUntil(0);
+ return ret;
+}
+
+//=================================================================================================
+// Writing CNF to DIMACS:
+//
+// FIXME: this needs to be rewritten completely.
+
+static Var mapVar(Var x, vec<Var>& map, Var& max)
+{
+ if (map.size() <= x || map[x] == -1){
+ map.growTo(x+1, -1);
+ map[x] = max++;
+ }
+ return map[x];
+}
+
+
+void Solver::toDimacs(FILE* f, Clause& c, vec<Var>& map, Var& max)
+{
+ if (satisfied(c)) return;
+
+ for (int i = 0; i < c.size(); i++)
+ if (value(c[i]) != l_False)
+ fprintf(f, "%s%d ", sign(c[i]) ? "-" : "", mapVar(var(c[i]), map, max)+1);
+ fprintf(f, "0\n");
+}
+
+
+void Solver::toDimacs(const char *file, const vec<Lit>& assumps)
+{
+ FILE* f = fopen(file, "wr");
+ if (f == NULL)
+ fprintf(stderr, "could not open file %s\n", file), exit(1);
+ toDimacs(f, assumps);
+ fclose(f);
+}
+
+
+void Solver::toDimacs(FILE* f, const vec<Lit>& assumps)
+{
+ // Handle case when solver is in contradictory state:
+ if (!ok){
+ fprintf(f, "p cnf 1 2\n1 0\n-1 0\n");
+ return; }
+
+ vec<Var> map; Var max = 0;
+
+ // Cannot use removeClauses here because it is not safe
+ // to deallocate them at this point. Could be improved.
+ int cnt = 0;
+ for (int i = 0; i < clauses.size(); i++)
+ if (!satisfied(ca[clauses[i]]))
+ cnt++;
+
+ for (int i = 0; i < clauses.size(); i++)
+ if (!satisfied(ca[clauses[i]])){
+ Clause& c = ca[clauses[i]];
+ for (int j = 0; j < c.size(); j++)
+ if (value(c[j]) != l_False)
+ mapVar(var(c[j]), map, max);
+ }
+
+ // Assumptions are added as unit clauses:
+ cnt += assumps.size();
+
+ fprintf(f, "p cnf %d %d\n", max, cnt);
+
+ for (int i = 0; i < assumps.size(); i++){
+ assert(value(assumps[i]) != l_False);
+ fprintf(f, "%s%d 0\n", sign(assumps[i]) ? "-" : "", mapVar(var(assumps[i]), map, max)+1);
+ }
+
+ for (int i = 0; i < clauses.size(); i++)
+ toDimacs(f, ca[clauses[i]], map, max);
+
+ if (verbosity > 0)
+ printf("Wrote DIMACS with %d variables and %d clauses.\n", max, cnt);
+}
+
+
+void Solver::printStats() const
+{
+ double cpu_time = cpuTime();
+ double mem_used = memUsedPeak();
+ printf("restarts : %" PRIu64 "\n", starts);
+ printf("conflicts : %-12" PRIu64 " (%.0f /sec)\n", conflicts , conflicts /cpu_time);
+ printf("decisions : %-12" PRIu64 " (%4.2f %% random) (%.0f /sec)\n", decisions, (float)rnd_decisions*100 / (float)decisions, decisions /cpu_time);
+ printf("propagations : %-12" PRIu64 " (%.0f /sec)\n", propagations, propagations/cpu_time);
+ printf("conflict literals : %-12" PRIu64 " (%4.2f %% deleted)\n", tot_literals, (max_literals - tot_literals)*100 / (double)max_literals);
+ if (mem_used != 0) printf("Memory used : %.2f MB\n", mem_used);
+ printf("CPU time : %g s\n", cpu_time);
+}
+
+
+//=================================================================================================
+// Garbage Collection methods:
+
+void Solver::relocAll(ClauseAllocator& to)
+{
+ // All watchers:
+ //
+ watches.cleanAll();
+ for (int v = 0; v < nVars(); v++)
+ for (int s = 0; s < 2; s++){
+ Lit p = mkLit(v, s);
+ vec<Watcher>& ws = watches[p];
+ for (int j = 0; j < ws.size(); j++)
+ ca.reloc(ws[j].cref, to);
+ }
+
+ // All reasons:
+ //
+ for (int i = 0; i < trail.size(); i++){
+ Var v = var(trail[i]);
+
+ // Note: it is not safe to call 'locked()' on a relocated clause. This is why we keep
+ // 'dangling' reasons here. It is safe and does not hurt.
+ if (reason(v) != CRef_Undef && (ca[reason(v)].reloced() || locked(ca[reason(v)]))){
+ assert(!isRemoved(reason(v)));
+ ca.reloc(vardata[v].reason, to);
+ }
+ }
+
+ // All learnt:
+ //
+ int i, j;
+ for (i = j = 0; i < learnts.size(); i++)
+ if (!isRemoved(learnts[i])){
+ ca.reloc(learnts[i], to);
+ learnts[j++] = learnts[i];
+ }
+ learnts.shrink(i - j);
+
+ // All original:
+ //
+ for (i = j = 0; i < clauses.size(); i++)
+ if (!isRemoved(clauses[i])){
+ ca.reloc(clauses[i], to);
+ clauses[j++] = clauses[i];
+ }
+ clauses.shrink(i - j);
+}
+
+
+void Solver::garbageCollect()
+{
+ // Initialize the next region to a size corresponding to the estimated utilization degree. This
+ // is not precise but should avoid some unnecessary reallocations for the new region:
+ ClauseAllocator to(ca.size() - ca.wasted());
+
+ relocAll(to);
+ if (verbosity >= 2)
+ printf("| Garbage collection: %12d bytes => %12d bytes |\n",
+ ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size);
+ to.moveTo(ca);
+}
diff --git a/libs/minisat/Solver.h b/libs/minisat/Solver.h
new file mode 100644
index 00000000..44570b0e
--- /dev/null
+++ b/libs/minisat/Solver.h
@@ -0,0 +1,409 @@
+/****************************************************************************************[Solver.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_Solver_h
+#define Minisat_Solver_h
+
+#include "Vec.h"
+#include "Heap.h"
+#include "Alg.h"
+#include "IntMap.h"
+#include "Options.h"
+#include "SolverTypes.h"
+
+
+namespace Minisat {
+
+//=================================================================================================
+// Solver -- the main class:
+
+class Solver {
+public:
+
+ // Constructor/Destructor:
+ //
+ Solver();
+ virtual ~Solver();
+
+ // Problem specification:
+ //
+ Var newVar (lbool upol = l_Undef, bool dvar = true); // Add a new variable with parameters specifying variable mode.
+ void releaseVar(Lit l); // Make literal true and promise to never refer to variable again.
+
+ bool addClause (const vec<Lit>& ps); // Add a clause to the solver.
+ bool addEmptyClause(); // Add the empty clause, making the solver contradictory.
+ bool addClause (Lit p); // Add a unit clause to the solver.
+ bool addClause (Lit p, Lit q); // Add a binary clause to the solver.
+ bool addClause (Lit p, Lit q, Lit r); // Add a ternary clause to the solver.
+ bool addClause (Lit p, Lit q, Lit r, Lit s); // Add a quaternary clause to the solver.
+ bool addClause_( vec<Lit>& ps); // Add a clause to the solver without making superflous internal copy. Will
+ // change the passed vector 'ps'.
+
+ // Solving:
+ //
+ bool simplify (); // Removes already satisfied clauses.
+ bool solve (const vec<Lit>& assumps); // Search for a model that respects a given set of assumptions.
+ lbool solveLimited (const vec<Lit>& assumps); // Search for a model that respects a given set of assumptions (With resource constraints).
+ bool solve (); // Search without assumptions.
+ bool solve (Lit p); // Search for a model that respects a single assumption.
+ bool solve (Lit p, Lit q); // Search for a model that respects two assumptions.
+ bool solve (Lit p, Lit q, Lit r); // Search for a model that respects three assumptions.
+ bool okay () const; // FALSE means solver is in a conflicting state
+
+ bool implies (const vec<Lit>& assumps, vec<Lit>& out);
+
+ // Iterate over clauses and top-level assignments:
+ ClauseIterator clausesBegin() const;
+ ClauseIterator clausesEnd() const;
+ TrailIterator trailBegin() const;
+ TrailIterator trailEnd () const;
+
+ void toDimacs (FILE* f, const vec<Lit>& assumps); // Write CNF to file in DIMACS-format.
+ void toDimacs (const char *file, const vec<Lit>& assumps);
+ void toDimacs (FILE* f, Clause& c, vec<Var>& map, Var& max);
+
+ // Convenience versions of 'toDimacs()':
+ void toDimacs (const char* file);
+ void toDimacs (const char* file, Lit p);
+ void toDimacs (const char* file, Lit p, Lit q);
+ void toDimacs (const char* file, Lit p, Lit q, Lit r);
+
+ // Variable mode:
+ //
+ void setPolarity (Var v, lbool b); // Declare which polarity the decision heuristic should use for a variable. Requires mode 'polarity_user'.
+ void setDecisionVar (Var v, bool b); // Declare if a variable should be eligible for selection in the decision heuristic.
+
+ // Read state:
+ //
+ lbool value (Var x) const; // The current value of a variable.
+ lbool value (Lit p) const; // The current value of a literal.
+ lbool modelValue (Var x) const; // The value of a variable in the last model. The last call to solve must have been satisfiable.
+ lbool modelValue (Lit p) const; // The value of a literal in the last model. The last call to solve must have been satisfiable.
+ int nAssigns () const; // The current number of assigned literals.
+ int nClauses () const; // The current number of original clauses.
+ int nLearnts () const; // The current number of learnt clauses.
+ int nVars () const; // The current number of variables.
+ int nFreeVars () const;
+ void printStats () const; // Print some current statistics to standard output.
+
+ // Resource constraints:
+ //
+ void setConfBudget(int64_t x);
+ void setPropBudget(int64_t x);
+ void budgetOff();
+ void interrupt(); // Trigger a (potentially asynchronous) interruption of the solver.
+ void clearInterrupt(); // Clear interrupt indicator flag.
+
+ // Memory managment:
+ //
+ virtual void garbageCollect();
+ void checkGarbage(double gf);
+ void checkGarbage();
+
+ // Extra results: (read-only member variable)
+ //
+ vec<lbool> model; // If problem is satisfiable, this vector contains the model (if any).
+ LSet conflict; // If problem is unsatisfiable (possibly under assumptions),
+ // this vector represent the final conflict clause expressed in the assumptions.
+
+ // Mode of operation:
+ //
+ int verbosity;
+ double var_decay;
+ double clause_decay;
+ double random_var_freq;
+ double random_seed;
+ bool luby_restart;
+ int ccmin_mode; // Controls conflict clause minimization (0=none, 1=basic, 2=deep).
+ int phase_saving; // Controls the level of phase saving (0=none, 1=limited, 2=full).
+ bool rnd_pol; // Use random polarities for branching heuristics.
+ bool rnd_init_act; // Initialize variable activities with a small random value.
+ double garbage_frac; // The fraction of wasted memory allowed before a garbage collection is triggered.
+ int min_learnts_lim; // Minimum number to set the learnts limit to.
+
+ int restart_first; // The initial restart limit. (default 100)
+ double restart_inc; // The factor with which the restart limit is multiplied in each restart. (default 1.5)
+ double learntsize_factor; // The intitial limit for learnt clauses is a factor of the original clauses. (default 1 / 3)
+ double learntsize_inc; // The limit for learnt clauses is multiplied with this factor each restart. (default 1.1)
+
+ int learntsize_adjust_start_confl;
+ double learntsize_adjust_inc;
+
+ // Statistics: (read-only member variable)
+ //
+ uint64_t solves, starts, decisions, rnd_decisions, propagations, conflicts;
+ uint64_t dec_vars, num_clauses, num_learnts, clauses_literals, learnts_literals, max_literals, tot_literals;
+
+protected:
+
+ // Helper structures:
+ //
+ struct VarData { CRef reason; int level; };
+ static inline VarData mkVarData(CRef cr, int l){ VarData d = {cr, l}; return d; }
+
+ struct Watcher {
+ CRef cref;
+ Lit blocker;
+ Watcher(CRef cr, Lit p) : cref(cr), blocker(p) {}
+ bool operator==(const Watcher& w) const { return cref == w.cref; }
+ bool operator!=(const Watcher& w) const { return cref != w.cref; }
+ };
+
+ struct WatcherDeleted
+ {
+ const ClauseAllocator& ca;
+ WatcherDeleted(const ClauseAllocator& _ca) : ca(_ca) {}
+ bool operator()(const Watcher& w) const { return ca[w.cref].mark() == 1; }
+ };
+
+ struct VarOrderLt {
+ const IntMap<Var, double>& activity;
+ bool operator () (Var x, Var y) const { return activity[x] > activity[y]; }
+ VarOrderLt(const IntMap<Var, double>& act) : activity(act) { }
+ };
+
+ struct ShrinkStackElem {
+ uint32_t i;
+ Lit l;
+ ShrinkStackElem(uint32_t _i, Lit _l) : i(_i), l(_l){}
+ };
+
+ // Solver state:
+ //
+ vec<CRef> clauses; // List of problem clauses.
+ vec<CRef> learnts; // List of learnt clauses.
+ vec<Lit> trail; // Assignment stack; stores all assigments made in the order they were made.
+ vec<int> trail_lim; // Separator indices for different decision levels in 'trail'.
+ vec<Lit> assumptions; // Current set of assumptions provided to solve by the user.
+
+ VMap<double> activity; // A heuristic measurement of the activity of a variable.
+ VMap<lbool> assigns; // The current assignments.
+ VMap<char> polarity; // The preferred polarity of each variable.
+ VMap<lbool> user_pol; // The users preferred polarity of each variable.
+ VMap<char> decision; // Declares if a variable is eligible for selection in the decision heuristic.
+ VMap<VarData> vardata; // Stores reason and level for each variable.
+ OccLists<Lit, vec<Watcher>, WatcherDeleted, MkIndexLit>
+ watches; // 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true).
+
+ Heap<Var,VarOrderLt>order_heap; // A priority queue of variables ordered with respect to the variable activity.
+
+ bool ok; // If FALSE, the constraints are already unsatisfiable. No part of the solver state may be used!
+ double cla_inc; // Amount to bump next clause with.
+ double var_inc; // Amount to bump next variable with.
+ int qhead; // Head of queue (as index into the trail -- no more explicit propagation queue in MiniSat).
+ int simpDB_assigns; // Number of top-level assignments since last execution of 'simplify()'.
+ int64_t simpDB_props; // Remaining number of propagations that must be made before next execution of 'simplify()'.
+ double progress_estimate;// Set by 'search()'.
+ bool remove_satisfied; // Indicates whether possibly inefficient linear scan for satisfied clauses should be performed in 'simplify'.
+ Var next_var; // Next variable to be created.
+ ClauseAllocator ca;
+
+ vec<Var> released_vars;
+ vec<Var> free_vars;
+
+ // Temporaries (to reduce allocation overhead). Each variable is prefixed by the method in which it is
+ // used, exept 'seen' wich is used in several places.
+ //
+ VMap<char> seen;
+ vec<ShrinkStackElem>analyze_stack;
+ vec<Lit> analyze_toclear;
+ vec<Lit> add_tmp;
+
+ double max_learnts;
+ double learntsize_adjust_confl;
+ int learntsize_adjust_cnt;
+
+ // Resource constraints:
+ //
+ int64_t conflict_budget; // -1 means no budget.
+ int64_t propagation_budget; // -1 means no budget.
+ bool asynch_interrupt;
+
+ // Main internal methods:
+ //
+ void insertVarOrder (Var x); // Insert a variable in the decision order priority queue.
+ Lit pickBranchLit (); // Return the next decision variable.
+ void newDecisionLevel (); // Begins a new decision level.
+ void uncheckedEnqueue (Lit p, CRef from = CRef_Undef); // Enqueue a literal. Assumes value of literal is undefined.
+ bool enqueue (Lit p, CRef from = CRef_Undef); // Test if fact 'p' contradicts current state, enqueue otherwise.
+ CRef propagate (); // Perform unit propagation. Returns possibly conflicting clause.
+ void cancelUntil (int level); // Backtrack until a certain level.
+ void analyze (CRef confl, vec<Lit>& out_learnt, int& out_btlevel); // (bt = backtrack)
+ void analyzeFinal (Lit p, LSet& out_conflict); // COULD THIS BE IMPLEMENTED BY THE ORDINARIY "analyze" BY SOME REASONABLE GENERALIZATION?
+ bool litRedundant (Lit p); // (helper method for 'analyze()')
+ lbool search (int nof_conflicts); // Search for a given number of conflicts.
+ lbool solve_ (); // Main solve method (assumptions given in 'assumptions').
+ void reduceDB (); // Reduce the set of learnt clauses.
+ void removeSatisfied (vec<CRef>& cs); // Shrink 'cs' to contain only non-satisfied clauses.
+ void rebuildOrderHeap ();
+
+ // Maintaining Variable/Clause activity:
+ //
+ void varDecayActivity (); // Decay all variables with the specified factor. Implemented by increasing the 'bump' value instead.
+ void varBumpActivity (Var v, double inc); // Increase a variable with the current 'bump' value.
+ void varBumpActivity (Var v); // Increase a variable with the current 'bump' value.
+ void claDecayActivity (); // Decay all clauses with the specified factor. Implemented by increasing the 'bump' value instead.
+ void claBumpActivity (Clause& c); // Increase a clause with the current 'bump' value.
+
+ // Operations on clauses:
+ //
+ void attachClause (CRef cr); // Attach a clause to watcher lists.
+ void detachClause (CRef cr, bool strict = false); // Detach a clause to watcher lists.
+ void removeClause (CRef cr); // Detach and free a clause.
+ bool isRemoved (CRef cr) const; // Test if a clause has been removed.
+ bool locked (const Clause& c) const; // Returns TRUE if a clause is a reason for some implication in the current state.
+ bool satisfied (const Clause& c) const; // Returns TRUE if a clause is satisfied in the current state.
+
+ // Misc:
+ //
+ int decisionLevel () const; // Gives the current decisionlevel.
+ uint32_t abstractLevel (Var x) const; // Used to represent an abstraction of sets of decision levels.
+ CRef reason (Var x) const;
+ int level (Var x) const;
+ double progressEstimate () const; // DELETE THIS ?? IT'S NOT VERY USEFUL ...
+ bool withinBudget () const;
+ void relocAll (ClauseAllocator& to);
+
+ // Static helpers:
+ //
+
+ // Returns a random float 0 <= x < 1. Seed must never be 0.
+ static inline double drand(double& seed) {
+ seed *= 1389796;
+ int q = (int)(seed / 2147483647);
+ seed -= (double)q * 2147483647;
+ return seed / 2147483647; }
+
+ // Returns a random integer 0 <= x < size. Seed must never be 0.
+ static inline int irand(double& seed, int size) {
+ return (int)(drand(seed) * size); }
+};
+
+
+//=================================================================================================
+// Implementation of inline methods:
+
+inline CRef Solver::reason(Var x) const { return vardata[x].reason; }
+inline int Solver::level (Var x) const { return vardata[x].level; }
+
+inline void Solver::insertVarOrder(Var x) {
+ if (!order_heap.inHeap(x) && decision[x]) order_heap.insert(x); }
+
+inline void Solver::varDecayActivity() { var_inc *= (1 / var_decay); }
+inline void Solver::varBumpActivity(Var v) { varBumpActivity(v, var_inc); }
+inline void Solver::varBumpActivity(Var v, double inc) {
+ if ( (activity[v] += inc) > 1e100 ) {
+ // Rescale:
+ for (int i = 0; i < nVars(); i++)
+ activity[i] *= 1e-100;
+ var_inc *= 1e-100; }
+
+ // Update order_heap with respect to new activity:
+ if (order_heap.inHeap(v))
+ order_heap.decrease(v); }
+
+inline void Solver::claDecayActivity() { cla_inc *= (1 / clause_decay); }
+inline void Solver::claBumpActivity (Clause& c) {
+ if ( (c.activity() += cla_inc) > 1e20 ) {
+ // Rescale:
+ for (int i = 0; i < learnts.size(); i++)
+ ca[learnts[i]].activity() *= 1e-20;
+ cla_inc *= 1e-20; } }
+
+inline void Solver::checkGarbage(void){ return checkGarbage(garbage_frac); }
+inline void Solver::checkGarbage(double gf){
+ if (ca.wasted() > ca.size() * gf)
+ garbageCollect(); }
+
+// NOTE: enqueue does not set the ok flag! (only public methods do)
+inline bool Solver::enqueue (Lit p, CRef from) { return value(p) != l_Undef ? value(p) != l_False : (uncheckedEnqueue(p, from), true); }
+inline bool Solver::addClause (const vec<Lit>& ps) { ps.copyTo(add_tmp); return addClause_(add_tmp); }
+inline bool Solver::addEmptyClause () { add_tmp.clear(); return addClause_(add_tmp); }
+inline bool Solver::addClause (Lit p) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); }
+inline bool Solver::addClause (Lit p, Lit q) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); }
+inline bool Solver::addClause (Lit p, Lit q, Lit r) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); }
+inline bool Solver::addClause (Lit p, Lit q, Lit r, Lit s){ add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); add_tmp.push(s); return addClause_(add_tmp); }
+
+inline bool Solver::isRemoved (CRef cr) const { return ca[cr].mark() == 1; }
+inline bool Solver::locked (const Clause& c) const { return value(c[0]) == l_True && reason(var(c[0])) != CRef_Undef && ca.lea(reason(var(c[0]))) == &c; }
+inline void Solver::newDecisionLevel() { trail_lim.push(trail.size()); }
+
+inline int Solver::decisionLevel () const { return trail_lim.size(); }
+inline uint32_t Solver::abstractLevel (Var x) const { return 1 << (level(x) & 31); }
+inline lbool Solver::value (Var x) const { return assigns[x]; }
+inline lbool Solver::value (Lit p) const { return assigns[var(p)] ^ sign(p); }
+inline lbool Solver::modelValue (Var x) const { return model[x]; }
+inline lbool Solver::modelValue (Lit p) const { return model[var(p)] ^ sign(p); }
+inline int Solver::nAssigns () const { return trail.size(); }
+inline int Solver::nClauses () const { return num_clauses; }
+inline int Solver::nLearnts () const { return num_learnts; }
+inline int Solver::nVars () const { return next_var; }
+// TODO: nFreeVars() is not quite correct, try to calculate right instead of adapting it like below:
+inline int Solver::nFreeVars () const { return (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]); }
+inline void Solver::setPolarity (Var v, lbool b){ user_pol[v] = b; }
+inline void Solver::setDecisionVar(Var v, bool b)
+{
+ if ( b && !decision[v]) dec_vars++;
+ else if (!b && decision[v]) dec_vars--;
+
+ decision[v] = b;
+ insertVarOrder(v);
+}
+inline void Solver::setConfBudget(int64_t x){ conflict_budget = conflicts + x; }
+inline void Solver::setPropBudget(int64_t x){ propagation_budget = propagations + x; }
+inline void Solver::interrupt(){ asynch_interrupt = true; }
+inline void Solver::clearInterrupt(){ asynch_interrupt = false; }
+inline void Solver::budgetOff(){ conflict_budget = propagation_budget = -1; }
+inline bool Solver::withinBudget() const {
+ return !asynch_interrupt &&
+ (conflict_budget < 0 || conflicts < (uint64_t)conflict_budget) &&
+ (propagation_budget < 0 || propagations < (uint64_t)propagation_budget); }
+
+// FIXME: after the introduction of asynchronous interrruptions the solve-versions that return a
+// pure bool do not give a safe interface. Either interrupts must be possible to turn off here, or
+// all calls to solve must return an 'lbool'. I'm not yet sure which I prefer.
+inline bool Solver::solve () { budgetOff(); assumptions.clear(); return solve_() == l_True; }
+inline bool Solver::solve (Lit p) { budgetOff(); assumptions.clear(); assumptions.push(p); return solve_() == l_True; }
+inline bool Solver::solve (Lit p, Lit q) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); return solve_() == l_True; }
+inline bool Solver::solve (Lit p, Lit q, Lit r) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); assumptions.push(r); return solve_() == l_True; }
+inline bool Solver::solve (const vec<Lit>& assumps){ budgetOff(); assumps.copyTo(assumptions); return solve_() == l_True; }
+inline lbool Solver::solveLimited (const vec<Lit>& assumps){ assumps.copyTo(assumptions); return solve_(); }
+inline bool Solver::okay () const { return ok; }
+
+inline ClauseIterator Solver::clausesBegin() const { return ClauseIterator(ca, &clauses[0]); }
+inline ClauseIterator Solver::clausesEnd () const { return ClauseIterator(ca, &clauses[clauses.size()]); }
+inline TrailIterator Solver::trailBegin () const { return TrailIterator(&trail[0]); }
+inline TrailIterator Solver::trailEnd () const {
+ return TrailIterator(&trail[decisionLevel() == 0 ? trail.size() : trail_lim[0]]); }
+
+inline void Solver::toDimacs (const char* file){ vec<Lit> as; toDimacs(file, as); }
+inline void Solver::toDimacs (const char* file, Lit p){ vec<Lit> as; as.push(p); toDimacs(file, as); }
+inline void Solver::toDimacs (const char* file, Lit p, Lit q){ vec<Lit> as; as.push(p); as.push(q); toDimacs(file, as); }
+inline void Solver::toDimacs (const char* file, Lit p, Lit q, Lit r){ vec<Lit> as; as.push(p); as.push(q); as.push(r); toDimacs(file, as); }
+
+
+//=================================================================================================
+// Debug etc:
+
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/minisat/SolverTypes.h b/libs/minisat/SolverTypes.h
new file mode 100644
index 00000000..a7df5785
--- /dev/null
+++ b/libs/minisat/SolverTypes.h
@@ -0,0 +1,478 @@
+/***********************************************************************************[SolverTypes.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+
+#ifndef Minisat_SolverTypes_h
+#define Minisat_SolverTypes_h
+
+#include <assert.h>
+
+#include "IntTypes.h"
+#include "Alg.h"
+#include "Vec.h"
+#include "IntMap.h"
+#include "Map.h"
+#include "Alloc.h"
+
+namespace Minisat {
+
+//=================================================================================================
+// Variables, literals, lifted booleans, clauses:
+
+
+// NOTE! Variables are just integers. No abstraction here. They should be chosen from 0..N,
+// so that they can be used as array indices.
+
+typedef int Var;
+#if defined(MINISAT_CONSTANTS_AS_MACROS)
+#define var_Undef (-1)
+#else
+ const Var var_Undef = -1;
+#endif
+
+
+struct Lit {
+ int x;
+
+ // Use this as a constructor:
+ friend Lit mkLit(Var var, bool sign);
+
+ bool operator == (Lit p) const { return x == p.x; }
+ bool operator != (Lit p) const { return x != p.x; }
+ bool operator < (Lit p) const { return x < p.x; } // '<' makes p, ~p adjacent in the ordering.
+};
+
+
+inline Lit mkLit (Var var, bool sign = false) { Lit p; p.x = var + var + (int)sign; return p; }
+inline Lit operator ~(Lit p) { Lit q; q.x = p.x ^ 1; return q; }
+inline Lit operator ^(Lit p, bool b) { Lit q; q.x = p.x ^ (unsigned int)b; return q; }
+inline bool sign (Lit p) { return p.x & 1; }
+inline int var (Lit p) { return p.x >> 1; }
+
+// Mapping Literals to and from compact integers suitable for array indexing:
+inline int toInt (Var v) { return v; }
+inline int toInt (Lit p) { return p.x; }
+inline Lit toLit (int i) { Lit p; p.x = i; return p; }
+
+//const Lit lit_Undef = mkLit(var_Undef, false); // }- Useful special constants.
+//const Lit lit_Error = mkLit(var_Undef, true ); // }
+
+const Lit lit_Undef = { -2 }; // }- Useful special constants.
+const Lit lit_Error = { -1 }; // }
+
+struct MkIndexLit { vec<Lit>::Size operator()(Lit l) const { return vec<Lit>::Size(l.x); } };
+
+template<class T> class VMap : public IntMap<Var, T>{};
+template<class T> class LMap : public IntMap<Lit, T, MkIndexLit>{};
+class LSet : public IntSet<Lit, MkIndexLit>{};
+
+//=================================================================================================
+// Lifted booleans:
+//
+// NOTE: this implementation is optimized for the case when comparisons between values are mostly
+// between one variable and one constant. Some care had to be taken to make sure that gcc
+// does enough constant propagation to produce sensible code, and this appears to be somewhat
+// fragile unfortunately.
+
+class lbool {
+ uint8_t value;
+
+public:
+ explicit lbool(uint8_t v) : value(v) { }
+
+ lbool() : value(0) { }
+ explicit lbool(bool x) : value(!x) { }
+
+ bool operator == (lbool b) const { return ((b.value&2) & (value&2)) | (!(b.value&2)&(value == b.value)); }
+ bool operator != (lbool b) const { return !(*this == b); }
+ lbool operator ^ (bool b) const { return lbool((uint8_t)(value^(uint8_t)b)); }
+
+ lbool operator && (lbool b) const {
+ uint8_t sel = (this->value << 1) | (b.value << 3);
+ uint8_t v = (0xF7F755F4 >> sel) & 3;
+ return lbool(v); }
+
+ lbool operator || (lbool b) const {
+ uint8_t sel = (this->value << 1) | (b.value << 3);
+ uint8_t v = (0xFCFCF400 >> sel) & 3;
+ return lbool(v); }
+
+ friend int toInt (lbool l);
+ friend lbool toLbool(int v);
+};
+inline int toInt (lbool l) { return l.value; }
+inline lbool toLbool(int v) { return lbool((uint8_t)v); }
+
+#if defined(MINISAT_CONSTANTS_AS_MACROS)
+ #define l_True (lbool((uint8_t)0)) // gcc does not do constant propagation if these are real constants.
+ #define l_False (lbool((uint8_t)1))
+ #define l_Undef (lbool((uint8_t)2))
+#else
+ const lbool l_True ((uint8_t)0);
+ const lbool l_False((uint8_t)1);
+ const lbool l_Undef((uint8_t)2);
+#endif
+
+
+//=================================================================================================
+// Clause -- a simple class for representing a clause:
+
+class Clause;
+typedef RegionAllocator<uint32_t>::Ref CRef;
+
+class Clause {
+ struct {
+ unsigned mark : 2;
+ unsigned learnt : 1;
+ unsigned has_extra : 1;
+ unsigned reloced : 1;
+ unsigned size : 27; } header;
+ union { Lit lit; float act; uint32_t abs; CRef rel; } data[0];
+
+ friend class ClauseAllocator;
+
+ // NOTE: This constructor cannot be used directly (doesn't allocate enough memory).
+ Clause(const vec<Lit>& ps, bool use_extra, bool learnt) {
+ header.mark = 0;
+ header.learnt = learnt;
+ header.has_extra = use_extra;
+ header.reloced = 0;
+ header.size = ps.size();
+
+ for (int i = 0; i < ps.size(); i++)
+ data[i].lit = ps[i];
+
+ if (header.has_extra){
+ if (header.learnt)
+ data[header.size].act = 0;
+ else
+ calcAbstraction();
+ }
+ }
+
+ // NOTE: This constructor cannot be used directly (doesn't allocate enough memory).
+ Clause(const Clause& from, bool use_extra){
+ header = from.header;
+ header.has_extra = use_extra; // NOTE: the copied clause may lose the extra field.
+
+ for (int i = 0; i < from.size(); i++)
+ data[i].lit = from[i];
+
+ if (header.has_extra){
+ if (header.learnt)
+ data[header.size].act = from.data[header.size].act;
+ else
+ data[header.size].abs = from.data[header.size].abs;
+ }
+ }
+
+public:
+ void calcAbstraction() {
+ assert(header.has_extra);
+ uint32_t abstraction = 0;
+ for (int i = 0; i < size(); i++)
+ abstraction |= 1 << (var(data[i].lit) & 31);
+ data[header.size].abs = abstraction; }
+
+
+ int size () const { return header.size; }
+ void shrink (int i) { assert(i <= size()); if (header.has_extra) data[header.size-i] = data[header.size]; header.size -= i; }
+ void pop () { shrink(1); }
+ bool learnt () const { return header.learnt; }
+ bool has_extra () const { return header.has_extra; }
+ uint32_t mark () const { return header.mark; }
+ void mark (uint32_t m) { header.mark = m; }
+ const Lit& last () const { return data[header.size-1].lit; }
+
+ bool reloced () const { return header.reloced; }
+ CRef relocation () const { return data[0].rel; }
+ void relocate (CRef c) { header.reloced = 1; data[0].rel = c; }
+
+ // NOTE: somewhat unsafe to change the clause in-place! Must manually call 'calcAbstraction' afterwards for
+ // subsumption operations to behave correctly.
+ Lit& operator [] (int i) { return data[i].lit; }
+ Lit operator [] (int i) const { return data[i].lit; }
+ operator const Lit* (void) const { return (Lit*)data; }
+
+ float& activity () { assert(header.has_extra); return data[header.size].act; }
+ uint32_t abstraction () const { assert(header.has_extra); return data[header.size].abs; }
+
+ Lit subsumes (const Clause& other) const;
+ void strengthen (Lit p);
+};
+
+
+//=================================================================================================
+// ClauseAllocator -- a simple class for allocating memory for clauses:
+
+const CRef CRef_Undef = RegionAllocator<uint32_t>::Ref_Undef;
+class ClauseAllocator
+{
+ RegionAllocator<uint32_t> ra;
+
+ static uint32_t clauseWord32Size(int size, bool has_extra){
+ return (sizeof(Clause) + (sizeof(Lit) * (size + (int)has_extra))) / sizeof(uint32_t); }
+
+ public:
+ enum { Unit_Size = RegionAllocator<uint32_t>::Unit_Size };
+
+ bool extra_clause_field;
+
+ ClauseAllocator(uint32_t start_cap) : ra(start_cap), extra_clause_field(false){}
+ ClauseAllocator() : extra_clause_field(false){}
+
+ void moveTo(ClauseAllocator& to){
+ to.extra_clause_field = extra_clause_field;
+ ra.moveTo(to.ra); }
+
+ CRef alloc(const vec<Lit>& ps, bool learnt = false)
+ {
+ assert(sizeof(Lit) == sizeof(uint32_t));
+ assert(sizeof(float) == sizeof(uint32_t));
+ bool use_extra = learnt | extra_clause_field;
+ CRef cid = ra.alloc(clauseWord32Size(ps.size(), use_extra));
+ new (lea(cid)) Clause(ps, use_extra, learnt);
+
+ return cid;
+ }
+
+ CRef alloc(const Clause& from)
+ {
+ bool use_extra = from.learnt() | extra_clause_field;
+ CRef cid = ra.alloc(clauseWord32Size(from.size(), use_extra));
+ new (lea(cid)) Clause(from, use_extra);
+ return cid; }
+
+ uint32_t size () const { return ra.size(); }
+ uint32_t wasted () const { return ra.wasted(); }
+
+ // Deref, Load Effective Address (LEA), Inverse of LEA (AEL):
+ Clause& operator[](CRef r) { return (Clause&)ra[r]; }
+ const Clause& operator[](CRef r) const { return (Clause&)ra[r]; }
+ Clause* lea (CRef r) { return (Clause*)ra.lea(r); }
+ const Clause* lea (CRef r) const { return (Clause*)ra.lea(r);; }
+ CRef ael (const Clause* t){ return ra.ael((uint32_t*)t); }
+
+ void free(CRef cid)
+ {
+ Clause& c = operator[](cid);
+ ra.free(clauseWord32Size(c.size(), c.has_extra()));
+ }
+
+ void reloc(CRef& cr, ClauseAllocator& to)
+ {
+ Clause& c = operator[](cr);
+
+ if (c.reloced()) { cr = c.relocation(); return; }
+
+ cr = to.alloc(c);
+ c.relocate(cr);
+ }
+};
+
+//=================================================================================================
+// Simple iterator classes (for iterating over clauses and top-level assignments):
+
+class ClauseIterator {
+ const ClauseAllocator& ca;
+ const CRef* crefs;
+public:
+ ClauseIterator(const ClauseAllocator& _ca, const CRef* _crefs) : ca(_ca), crefs(_crefs){}
+
+ void operator++(){ crefs++; }
+ const Clause& operator*() const { return ca[*crefs]; }
+
+ // NOTE: does not compare that references use the same clause-allocator:
+ bool operator==(const ClauseIterator& ci) const { return crefs == ci.crefs; }
+ bool operator!=(const ClauseIterator& ci) const { return crefs != ci.crefs; }
+};
+
+
+class TrailIterator {
+ const Lit* lits;
+public:
+ TrailIterator(const Lit* _lits) : lits(_lits){}
+
+ void operator++() { lits++; }
+ Lit operator*() const { return *lits; }
+
+ bool operator==(const TrailIterator& ti) const { return lits == ti.lits; }
+ bool operator!=(const TrailIterator& ti) const { return lits != ti.lits; }
+};
+
+
+//=================================================================================================
+// OccLists -- a class for maintaining occurence lists with lazy deletion:
+
+template<class K, class Vec, class Deleted, class MkIndex = MkIndexDefault<K> >
+class OccLists
+{
+ IntMap<K, Vec, MkIndex> occs;
+ IntMap<K, char, MkIndex> dirty;
+ vec<K> dirties;
+ Deleted deleted;
+
+ public:
+ OccLists(const Deleted& d, MkIndex _index = MkIndex()) :
+ occs(_index),
+ dirty(_index),
+ deleted(d){}
+
+ void init (const K& idx){ occs.reserve(idx); occs[idx].clear(); dirty.reserve(idx, 0); }
+ Vec& operator[](const K& idx){ return occs[idx]; }
+ Vec& lookup (const K& idx){ if (dirty[idx]) clean(idx); return occs[idx]; }
+
+ void cleanAll ();
+ void clean (const K& idx);
+ void smudge (const K& idx){
+ if (dirty[idx] == 0){
+ dirty[idx] = 1;
+ dirties.push(idx);
+ }
+ }
+
+ void clear(bool free = true){
+ occs .clear(free);
+ dirty .clear(free);
+ dirties.clear(free);
+ }
+};
+
+
+template<class K, class Vec, class Deleted, class MkIndex>
+void OccLists<K,Vec,Deleted,MkIndex>::cleanAll()
+{
+ for (int i = 0; i < dirties.size(); i++)
+ // Dirties may contain duplicates so check here if a variable is already cleaned:
+ if (dirty[dirties[i]])
+ clean(dirties[i]);
+ dirties.clear();
+}
+
+
+template<class K, class Vec, class Deleted, class MkIndex>
+void OccLists<K,Vec,Deleted,MkIndex>::clean(const K& idx)
+{
+ Vec& vec = occs[idx];
+ int i, j;
+ for (i = j = 0; i < vec.size(); i++)
+ if (!deleted(vec[i]))
+ vec[j++] = vec[i];
+ vec.shrink(i - j);
+ dirty[idx] = 0;
+}
+
+
+//=================================================================================================
+// CMap -- a class for mapping clauses to values:
+
+
+template<class T>
+class CMap
+{
+ struct CRefHash {
+ uint32_t operator()(CRef cr) const { return (uint32_t)cr; } };
+
+ typedef Map<CRef, T, CRefHash> HashTable;
+ HashTable map;
+
+ public:
+ // Size-operations:
+ void clear () { map.clear(); }
+ int size () const { return map.elems(); }
+
+
+ // Insert/Remove/Test mapping:
+ void insert (CRef cr, const T& t){ map.insert(cr, t); }
+ void growTo (CRef cr, const T& t){ map.insert(cr, t); } // NOTE: for compatibility
+ void remove (CRef cr) { map.remove(cr); }
+ bool has (CRef cr, T& t) { return map.peek(cr, t); }
+
+ // Vector interface (the clause 'c' must already exist):
+ const T& operator [] (CRef cr) const { return map[cr]; }
+ T& operator [] (CRef cr) { return map[cr]; }
+
+ // Iteration (not transparent at all at the moment):
+ int bucket_count() const { return map.bucket_count(); }
+ const vec<typename HashTable::Pair>& bucket(int i) const { return map.bucket(i); }
+
+ // Move contents to other map:
+ void moveTo(CMap& other){ map.moveTo(other.map); }
+
+ // TMP debug:
+ void debug(){
+ printf(" --- size = %d, bucket_count = %d\n", size(), map.bucket_count()); }
+};
+
+
+/*_________________________________________________________________________________________________
+|
+| subsumes : (other : const Clause&) -> Lit
+|
+| Description:
+| Checks if clause subsumes 'other', and at the same time, if it can be used to simplify 'other'
+| by subsumption resolution.
+|
+| Result:
+| lit_Error - No subsumption or simplification
+| lit_Undef - Clause subsumes 'other'
+| p - The literal p can be deleted from 'other'
+|________________________________________________________________________________________________@*/
+inline Lit Clause::subsumes(const Clause& other) const
+{
+ //if (other.size() < size() || (extra.abst & ~other.extra.abst) != 0)
+ //if (other.size() < size() || (!learnt() && !other.learnt() && (extra.abst & ~other.extra.abst) != 0))
+ assert(!header.learnt); assert(!other.header.learnt);
+ assert(header.has_extra); assert(other.header.has_extra);
+ if (other.header.size < header.size || (data[header.size].abs & ~other.data[other.header.size].abs) != 0)
+ return lit_Error;
+
+ Lit ret = lit_Undef;
+ const Lit* c = (const Lit*)(*this);
+ const Lit* d = (const Lit*)other;
+
+ for (unsigned i = 0; i < header.size; i++) {
+ // search for c[i] or ~c[i]
+ for (unsigned j = 0; j < other.header.size; j++)
+ if (c[i] == d[j])
+ goto ok;
+ else if (ret == lit_Undef && c[i] == ~d[j]){
+ ret = c[i];
+ goto ok;
+ }
+
+ // did not find it
+ return lit_Error;
+ ok:;
+ }
+
+ return ret;
+}
+
+inline void Clause::strengthen(Lit p)
+{
+ remove(*this, p);
+ calcAbstraction();
+}
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/minisat/Sort.h b/libs/minisat/Sort.h
new file mode 100644
index 00000000..cc96486d
--- /dev/null
+++ b/libs/minisat/Sort.h
@@ -0,0 +1,98 @@
+/******************************************************************************************[Sort.h]
+Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_Sort_h
+#define Minisat_Sort_h
+
+#include "Vec.h"
+
+//=================================================================================================
+// Some sorting algorithms for vec's
+
+
+namespace Minisat {
+
+template<class T>
+struct LessThan_default {
+ bool operator () (T x, T y) { return x < y; }
+};
+
+
+template <class T, class LessThan>
+void selectionSort(T* array, int size, LessThan lt)
+{
+ int i, j, best_i;
+ T tmp;
+
+ for (i = 0; i < size-1; i++){
+ best_i = i;
+ for (j = i+1; j < size; j++){
+ if (lt(array[j], array[best_i]))
+ best_i = j;
+ }
+ tmp = array[i]; array[i] = array[best_i]; array[best_i] = tmp;
+ }
+}
+template <class T> static inline void selectionSort(T* array, int size) {
+ selectionSort(array, size, LessThan_default<T>()); }
+
+template <class T, class LessThan>
+void sort(T* array, int size, LessThan lt)
+{
+ if (size <= 15)
+ selectionSort(array, size, lt);
+
+ else{
+ T pivot = array[size / 2];
+ T tmp;
+ int i = -1;
+ int j = size;
+
+ for(;;){
+ do i++; while(lt(array[i], pivot));
+ do j--; while(lt(pivot, array[j]));
+
+ if (i >= j) break;
+
+ tmp = array[i]; array[i] = array[j]; array[j] = tmp;
+ }
+
+ sort(array , i , lt);
+ sort(&array[i], size-i, lt);
+ }
+}
+template <class T> static inline void sort(T* array, int size) {
+ sort(array, size, LessThan_default<T>()); }
+
+
+//=================================================================================================
+// For 'vec's:
+
+
+template <class T, class LessThan> void sort(vec<T>& v, LessThan lt) {
+ sort((T*)v, v.size(), lt); }
+template <class T> void sort(vec<T>& v) {
+ sort(v, LessThan_default<T>()); }
+
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/minisat/System.cc b/libs/minisat/System.cc
new file mode 100644
index 00000000..febe3b40
--- /dev/null
+++ b/libs/minisat/System.cc
@@ -0,0 +1,171 @@
+#define __STDC_FORMAT_MACROS
+#define __STDC_LIMIT_MACROS
+/***************************************************************************************[System.cc]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#include <signal.h>
+#include <stdio.h>
+
+#include "System.h"
+
+#if defined(__linux__)
+
+#include <stdlib.h>
+
+using namespace Minisat;
+
+static inline int memReadStat(int field)
+{
+ char name[256];
+ pid_t pid = getpid();
+ int value;
+
+ sprintf(name, "/proc/%d/statm", pid);
+ FILE* in = fopen(name, "rb");
+ if (in == NULL) return 0;
+
+ for (; field >= 0; field--)
+ if (fscanf(in, "%d", &value) != 1)
+ printf("ERROR! Failed to parse memory statistics from \"/proc\".\n"), exit(1);
+ fclose(in);
+ return value;
+}
+
+
+static inline int memReadPeak(void)
+{
+ char name[256];
+ pid_t pid = getpid();
+
+ sprintf(name, "/proc/%d/status", pid);
+ FILE* in = fopen(name, "rb");
+ if (in == NULL) return 0;
+
+ // Find the correct line, beginning with "VmPeak:":
+ int peak_kb = 0;
+ while (!feof(in) && fscanf(in, "VmPeak: %d kB", &peak_kb) != 1)
+ while (!feof(in) && fgetc(in) != '\n')
+ ;
+ fclose(in);
+
+ return peak_kb;
+}
+
+double Minisat::memUsed() { return (double)memReadStat(0) * (double)getpagesize() / (1024*1024); }
+double Minisat::memUsedPeak(bool strictlyPeak) {
+ double peak = memReadPeak() / (double)1024;
+ return peak == 0 && !strictlyPeak ? memUsed() : peak; }
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__gnu_hurd__)
+
+double Minisat::memUsed() {
+ struct rusage ru;
+ getrusage(RUSAGE_SELF, &ru);
+ return (double)ru.ru_maxrss / 1024; }
+double Minisat::memUsedPeak(bool) { return memUsed(); }
+
+
+#elif defined(__APPLE__)
+#include <malloc/malloc.h>
+
+double Minisat::memUsed() {
+ malloc_statistics_t t;
+ malloc_zone_statistics(NULL, &t);
+ return (double)t.max_size_in_use / (1024*1024); }
+double Minisat::memUsedPeak(bool) { return memUsed(); }
+
+#else
+double Minisat::memUsed() { return 0; }
+double Minisat::memUsedPeak(bool) { return 0; }
+#endif
+
+
+void Minisat::setX86FPUPrecision()
+{
+#if defined(__linux__) && defined(_FPU_EXTENDED) && defined(_FPU_DOUBLE) && defined(_FPU_GETCW)
+ // Only correct FPU precision on Linux architectures that needs and supports it:
+ fpu_control_t oldcw, newcw;
+ _FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw);
+ printf("WARNING: for repeatability, setting FPU to use double precision\n");
+#endif
+}
+
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+void Minisat::limitMemory(uint64_t max_mem_mb)
+{
+// FIXME: OpenBSD does not support RLIMIT_AS. Not sure how well RLIMIT_DATA works instead.
+#if defined(__OpenBSD__)
+#define RLIMIT_AS RLIMIT_DATA
+#endif
+
+ // Set limit on virtual memory:
+ if (max_mem_mb != 0){
+ rlim_t new_mem_lim = (rlim_t)max_mem_mb * 1024*1024;
+ rlimit rl;
+ getrlimit(RLIMIT_AS, &rl);
+ if (rl.rlim_max == RLIM_INFINITY || new_mem_lim < rl.rlim_max){
+ rl.rlim_cur = new_mem_lim;
+ if (setrlimit(RLIMIT_AS, &rl) == -1)
+ printf("WARNING! Could not set resource limit: Virtual memory.\n");
+ }
+ }
+
+#if defined(__OpenBSD__)
+#undef RLIMIT_AS
+#endif
+}
+#else
+void Minisat::limitMemory(uint64_t /*max_mem_mb*/)
+{
+ printf("WARNING! Memory limit not supported on this architecture.\n");
+}
+#endif
+
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+void Minisat::limitTime(uint32_t max_cpu_time)
+{
+ if (max_cpu_time != 0){
+ rlimit rl;
+ getrlimit(RLIMIT_CPU, &rl);
+ if (rl.rlim_max == RLIM_INFINITY || (rlim_t)max_cpu_time < rl.rlim_max){
+ rl.rlim_cur = max_cpu_time;
+ if (setrlimit(RLIMIT_CPU, &rl) == -1)
+ printf("WARNING! Could not set resource limit: CPU-time.\n");
+ }
+ }
+}
+#else
+void Minisat::limitTime(uint32_t /*max_cpu_time*/)
+{
+ printf("WARNING! CPU-time limit not supported on this architecture.\n");
+}
+#endif
+
+
+void Minisat::sigTerm(void handler(int))
+{
+ signal(SIGINT, handler);
+ signal(SIGTERM,handler);
+#ifdef SIGXCPU
+ signal(SIGXCPU,handler);
+#endif
+}
diff --git a/libs/minisat/System.h b/libs/minisat/System.h
new file mode 100644
index 00000000..ee92a6e0
--- /dev/null
+++ b/libs/minisat/System.h
@@ -0,0 +1,72 @@
+/****************************************************************************************[System.h]
+Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_System_h
+#define Minisat_System_h
+
+#if defined(__linux__)
+#include <fpu_control.h>
+#endif
+
+#include "IntTypes.h"
+
+//-------------------------------------------------------------------------------------------------
+
+namespace Minisat {
+
+static inline double cpuTime(void); // CPU-time in seconds.
+
+extern double memUsed(); // Memory in mega bytes (returns 0 for unsupported architectures).
+extern double memUsedPeak(bool strictlyPeak = false); // Peak-memory in mega bytes (returns 0 for unsupported architectures).
+
+extern void setX86FPUPrecision(); // Make sure double's are represented with the same precision
+ // in memory and registers.
+
+extern void limitMemory(uint64_t max_mem_mb); // Set a limit on total memory usage. The exact
+ // semantics varies depending on architecture.
+
+extern void limitTime(uint32_t max_cpu_time); // Set a limit on maximum CPU time. The exact
+ // semantics varies depending on architecture.
+
+extern void sigTerm(void handler(int)); // Set up handling of available termination signals.
+
+}
+
+//-------------------------------------------------------------------------------------------------
+// Implementation of inline functions:
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#include <time.h>
+
+static inline double Minisat::cpuTime(void) { return (double)clock() / CLOCKS_PER_SEC; }
+
+#else
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+static inline double Minisat::cpuTime(void) {
+ struct rusage ru;
+ getrusage(RUSAGE_SELF, &ru);
+ return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000; }
+
+#endif
+
+#endif
diff --git a/libs/minisat/Vec.h b/libs/minisat/Vec.h
new file mode 100644
index 00000000..6e398801
--- /dev/null
+++ b/libs/minisat/Vec.h
@@ -0,0 +1,134 @@
+/*******************************************************************************************[Vec.h]
+Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson
+Copyright (c) 2007-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+#ifndef Minisat_Vec_h
+#define Minisat_Vec_h
+
+#include <assert.h>
+#include <limits>
+#include <new>
+
+#include "IntTypes.h"
+#include "XAlloc.h"
+
+namespace Minisat {
+
+//=================================================================================================
+// Automatically resizable arrays
+//
+// NOTE! Don't use this vector on datatypes that cannot be re-located in memory (with realloc)
+
+template<class T, class _Size = int>
+class vec {
+public:
+ typedef _Size Size;
+private:
+ T* data;
+ Size sz;
+ Size cap;
+
+ // Don't allow copying (error prone):
+ vec<T>& operator=(vec<T>& other);
+ vec (vec<T>& other);
+
+ static inline Size max(Size x, Size y){ return (x > y) ? x : y; }
+
+public:
+ // Constructors:
+ vec() : data(NULL), sz(0), cap(0) { }
+ explicit vec(Size size) : data(NULL), sz(0), cap(0) { growTo(size); }
+ vec(Size size, const T& pad) : data(NULL), sz(0), cap(0) { growTo(size, pad); }
+ ~vec() { clear(true); }
+
+ // Pointer to first element:
+ operator T* (void) { return data; }
+
+ // Size operations:
+ Size size (void) const { return sz; }
+ void shrink (Size nelems) { assert(nelems <= sz); for (Size i = 0; i < nelems; i++) sz--, data[sz].~T(); }
+ void shrink_ (Size nelems) { assert(nelems <= sz); sz -= nelems; }
+ int capacity (void) const { return cap; }
+ void capacity (Size min_cap);
+ void growTo (Size size);
+ void growTo (Size size, const T& pad);
+ void clear (bool dealloc = false);
+
+ // Stack interface:
+ void push (void) { if (sz == cap) capacity(sz+1); new (&data[sz]) T(); sz++; }
+ //void push (const T& elem) { if (sz == cap) capacity(sz+1); data[sz++] = elem; }
+ void push (const T& elem) { if (sz == cap) capacity(sz+1); new (&data[sz++]) T(elem); }
+ void push_ (const T& elem) { assert(sz < cap); data[sz++] = elem; }
+ void pop (void) { assert(sz > 0); sz--, data[sz].~T(); }
+ // NOTE: it seems possible that overflow can happen in the 'sz+1' expression of 'push()', but
+ // in fact it can not since it requires that 'cap' is equal to INT_MAX. This in turn can not
+ // happen given the way capacities are calculated (below). Essentially, all capacities are
+ // even, but INT_MAX is odd.
+
+ const T& last (void) const { return data[sz-1]; }
+ T& last (void) { return data[sz-1]; }
+
+ // Vector interface:
+ const T& operator [] (Size index) const { return data[index]; }
+ T& operator [] (Size index) { return data[index]; }
+
+ // Duplicatation (preferred instead):
+ void copyTo(vec<T>& copy) const { copy.clear(); copy.growTo(sz); for (Size i = 0; i < sz; i++) copy[i] = data[i]; }
+ void moveTo(vec<T>& dest) { dest.clear(true); dest.data = data; dest.sz = sz; dest.cap = cap; data = NULL; sz = 0; cap = 0; }
+};
+
+
+template<class T, class _Size>
+void vec<T,_Size>::capacity(Size min_cap) {
+ if (cap >= min_cap) return;
+ Size add = max((min_cap - cap + 1) & ~1, ((cap >> 1) + 2) & ~1); // NOTE: grow by approximately 3/2
+ const Size size_max = std::numeric_limits<Size>::max();
+ if ( ((size_max <= std::numeric_limits<int>::max()) && (add > size_max - cap))
+ || (((data = (T*)::realloc(data, (cap += add) * sizeof(T))) == NULL) && errno == ENOMEM) )
+ throw OutOfMemoryException();
+ }
+
+
+template<class T, class _Size>
+void vec<T,_Size>::growTo(Size size, const T& pad) {
+ if (sz >= size) return;
+ capacity(size);
+ for (Size i = sz; i < size; i++) data[i] = pad;
+ sz = size; }
+
+
+template<class T, class _Size>
+void vec<T,_Size>::growTo(Size size) {
+ if (sz >= size) return;
+ capacity(size);
+ for (Size i = sz; i < size; i++) new (&data[i]) T();
+ sz = size; }
+
+
+template<class T, class _Size>
+void vec<T,_Size>::clear(bool dealloc) {
+ if (data != NULL){
+ for (Size i = 0; i < sz; i++) data[i].~T();
+ sz = 0;
+ if (dealloc) free(data), data = NULL, cap = 0; } }
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/minisat/XAlloc.h b/libs/minisat/XAlloc.h
new file mode 100644
index 00000000..1da17602
--- /dev/null
+++ b/libs/minisat/XAlloc.h
@@ -0,0 +1,45 @@
+/****************************************************************************************[XAlloc.h]
+Copyright (c) 2009-2010, Niklas Sorensson
+
+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.
+**************************************************************************************************/
+
+
+#ifndef Minisat_XAlloc_h
+#define Minisat_XAlloc_h
+
+#include <errno.h>
+#include <stdlib.h>
+
+namespace Minisat {
+
+//=================================================================================================
+// Simple layer on top of malloc/realloc to catch out-of-memory situtaions and provide some typing:
+
+class OutOfMemoryException{};
+static inline void* xrealloc(void *ptr, size_t size)
+{
+ void* mem = realloc(ptr, size);
+ if (mem == NULL && errno == ENOMEM){
+ throw OutOfMemoryException();
+ }else
+ return mem;
+}
+
+//=================================================================================================
+}
+
+#endif
diff --git a/libs/sha1/sha1.cpp b/libs/sha1/sha1.cpp
index fb7bfed6..dc86b2ce 100644
--- a/libs/sha1/sha1.cpp
+++ b/libs/sha1/sha1.cpp
@@ -1,185 +1,270 @@
-/*
- Copyright (c) 2011, Micael Hildenborg
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of Micael Hildenborg nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- Contributors:
- Gustav
- Several members in the gamedev.se forum.
- Gregory Petrosyan
- */
-
-#include "sha1.h"
-
-namespace sha1
-{
- namespace // local
- {
- // Rotate an integer value to left.
- inline unsigned int rol(const unsigned int value,
- const unsigned int steps)
- {
- return ((value << steps) | (value >> (32 - steps)));
- }
-
- // Sets the first 16 integers in the buffert to zero.
- // Used for clearing the W buffert.
- inline void clearWBuffert(unsigned int* buffert)
- {
- for (int pos = 16; --pos >= 0;)
- {
- buffert[pos] = 0;
- }
- }
-
- void innerHash(unsigned int* result, unsigned int* w)
- {
- unsigned int a = result[0];
- unsigned int b = result[1];
- unsigned int c = result[2];
- unsigned int d = result[3];
- unsigned int e = result[4];
-
- int round = 0;
-
- #define sha1macro(func,val) \
- { \
- const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
- e = d; \
- d = c; \
- c = rol(b, 30); \
- b = a; \
- a = t; \
- }
-
- while (round < 16)
- {
- sha1macro((b & c) | (~b & d), 0x5a827999)
- ++round;
- }
- while (round < 20)
- {
- w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
- sha1macro((b & c) | (~b & d), 0x5a827999)
- ++round;
- }
- while (round < 40)
- {
- w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
- sha1macro(b ^ c ^ d, 0x6ed9eba1)
- ++round;
- }
- while (round < 60)
- {
- w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
- sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
- ++round;
- }
- while (round < 80)
- {
- w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
- sha1macro(b ^ c ^ d, 0xca62c1d6)
- ++round;
- }
-
- #undef sha1macro
-
- result[0] += a;
- result[1] += b;
- result[2] += c;
- result[3] += d;
- result[4] += e;
- }
- } // namespace
-
- void calc(const void* src, const int bytelength, unsigned char* hash)
- {
- // Init the result array.
- unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };
-
- // Cast the void src pointer to be the byte array we can work with.
- const unsigned char* sarray = (const unsigned char*) src;
-
- // The reusable round buffer
- unsigned int w[80];
-
- // Loop through all complete 64byte blocks.
- const int endOfFullBlocks = bytelength - 64;
- int endCurrentBlock;
- int currentBlock = 0;
-
- while (currentBlock <= endOfFullBlocks)
- {
- endCurrentBlock = currentBlock + 64;
-
- // Init the round buffer with the 64 byte block data.
- for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
- {
- // This line will swap endian on big endian and keep endian on little endian.
- w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
- | (((unsigned int) sarray[currentBlock + 2]) << 8)
- | (((unsigned int) sarray[currentBlock + 1]) << 16)
- | (((unsigned int) sarray[currentBlock]) << 24);
- }
- innerHash(result, w);
- }
-
- // Handle the last and not full 64 byte block if existing.
- endCurrentBlock = bytelength - currentBlock;
- clearWBuffert(w);
- int lastBlockBytes = 0;
- for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)
- {
- w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
- }
- w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
- if (endCurrentBlock >= 56)
- {
- innerHash(result, w);
- clearWBuffert(w);
- }
- w[15] = bytelength << 3;
- innerHash(result, w);
-
- // Store hash in result pointer, and make sure we get in in the correct order on both endian models.
- for (int hashByte = 20; --hashByte >= 0;)
- {
- hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
- }
- }
-
- void toHexString(const unsigned char* hash, char* hexstring)
- {
- const char hexDigits[] = { "0123456789abcdef" };
-
- for (int hashByte = 20; --hashByte >= 0;)
- {
- hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf];
- hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf];
- }
- hexstring[40] = 0;
- }
-} // namespace sha1
+/*
+ sha1.cpp - source code of
+
+ ============
+ SHA-1 in C++
+ ============
+
+ 100% Public Domain.
+
+ Original C Code
+ -- Steve Reid <steve@edmweb.com>
+ Small changes to fit into bglibs
+ -- Bruce Guenter <bruce@untroubled.org>
+ Translation to simpler C++ Code
+ -- Volker Grabsch <vog@notjusthosting.com>
+*/
+
+#include "sha1.h"
+#include <sstream>
+#include <iomanip>
+#include <fstream>
+
+/* Help macros */
+#define SHA1_ROL(value, bits) (((value) << (bits)) | (((value) & 0xffffffff) >> (32 - (bits))))
+#define SHA1_BLK(i) (block[i&15] = SHA1_ROL(block[(i+13)&15] ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define SHA1_R0(v,w,x,y,z,i) z += ((w&(x^y))^y) + block[i] + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
+#define SHA1_R1(v,w,x,y,z,i) z += ((w&(x^y))^y) + SHA1_BLK(i) + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
+#define SHA1_R2(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0x6ed9eba1 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
+#define SHA1_R3(v,w,x,y,z,i) z += (((w|x)&y)|(w&x)) + SHA1_BLK(i) + 0x8f1bbcdc + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
+#define SHA1_R4(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0xca62c1d6 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
+
+SHA1::SHA1()
+{
+ reset();
+}
+
+
+void SHA1::update(const std::string &s)
+{
+ std::istringstream is(s);
+ update(is);
+}
+
+
+void SHA1::update(std::istream &is)
+{
+ std::string rest_of_buffer;
+ read(is, rest_of_buffer, BLOCK_BYTES - buffer.size());
+ buffer += rest_of_buffer;
+
+ while (is)
+ {
+ uint32 block[BLOCK_INTS];
+ buffer_to_block(buffer, block);
+ transform(block);
+ read(is, buffer, BLOCK_BYTES);
+ }
+}
+
+
+/*
+ * Add padding and return the message digest.
+ */
+
+std::string SHA1::final()
+{
+ /* Total number of hashed bits */
+ uint64 total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8;
+
+ /* Padding */
+ buffer += 0x80;
+ unsigned int orig_size = buffer.size();
+ while (buffer.size() < BLOCK_BYTES)
+ {
+ buffer += (char)0x00;
+ }
+
+ uint32 block[BLOCK_INTS];
+ buffer_to_block(buffer, block);
+
+ if (orig_size > BLOCK_BYTES - 8)
+ {
+ transform(block);
+ for (unsigned int i = 0; i < BLOCK_INTS - 2; i++)
+ {
+ block[i] = 0;
+ }
+ }
+
+ /* Append total_bits, split this uint64 into two uint32 */
+ block[BLOCK_INTS - 1] = total_bits;
+ block[BLOCK_INTS - 2] = (total_bits >> 32);
+ transform(block);
+
+ /* Hex std::string */
+ std::ostringstream result;
+ for (unsigned int i = 0; i < DIGEST_INTS; i++)
+ {
+ result << std::hex << std::setfill('0') << std::setw(8);
+ result << (digest[i] & 0xffffffff);
+ }
+
+ /* Reset for next run */
+ reset();
+
+ return result.str();
+}
+
+
+std::string SHA1::from_file(const std::string &filename)
+{
+ std::ifstream stream(filename.c_str(), std::ios::binary);
+ SHA1 checksum;
+ checksum.update(stream);
+ return checksum.final();
+}
+
+
+void SHA1::reset()
+{
+ /* SHA1 initialization constants */
+ digest[0] = 0x67452301;
+ digest[1] = 0xefcdab89;
+ digest[2] = 0x98badcfe;
+ digest[3] = 0x10325476;
+ digest[4] = 0xc3d2e1f0;
+
+ /* Reset counters */
+ transforms = 0;
+ buffer = "";
+}
+
+
+/*
+ * Hash a single 512-bit block. This is the core of the algorithm.
+ */
+
+void SHA1::transform(uint32 block[BLOCK_BYTES])
+{
+ /* Copy digest[] to working vars */
+ uint32 a = digest[0];
+ uint32 b = digest[1];
+ uint32 c = digest[2];
+ uint32 d = digest[3];
+ uint32 e = digest[4];
+
+
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ SHA1_R0(a,b,c,d,e, 0);
+ SHA1_R0(e,a,b,c,d, 1);
+ SHA1_R0(d,e,a,b,c, 2);
+ SHA1_R0(c,d,e,a,b, 3);
+ SHA1_R0(b,c,d,e,a, 4);
+ SHA1_R0(a,b,c,d,e, 5);
+ SHA1_R0(e,a,b,c,d, 6);
+ SHA1_R0(d,e,a,b,c, 7);
+ SHA1_R0(c,d,e,a,b, 8);
+ SHA1_R0(b,c,d,e,a, 9);
+ SHA1_R0(a,b,c,d,e,10);
+ SHA1_R0(e,a,b,c,d,11);
+ SHA1_R0(d,e,a,b,c,12);
+ SHA1_R0(c,d,e,a,b,13);
+ SHA1_R0(b,c,d,e,a,14);
+ SHA1_R0(a,b,c,d,e,15);
+ SHA1_R1(e,a,b,c,d,16);
+ SHA1_R1(d,e,a,b,c,17);
+ SHA1_R1(c,d,e,a,b,18);
+ SHA1_R1(b,c,d,e,a,19);
+ SHA1_R2(a,b,c,d,e,20);
+ SHA1_R2(e,a,b,c,d,21);
+ SHA1_R2(d,e,a,b,c,22);
+ SHA1_R2(c,d,e,a,b,23);
+ SHA1_R2(b,c,d,e,a,24);
+ SHA1_R2(a,b,c,d,e,25);
+ SHA1_R2(e,a,b,c,d,26);
+ SHA1_R2(d,e,a,b,c,27);
+ SHA1_R2(c,d,e,a,b,28);
+ SHA1_R2(b,c,d,e,a,29);
+ SHA1_R2(a,b,c,d,e,30);
+ SHA1_R2(e,a,b,c,d,31);
+ SHA1_R2(d,e,a,b,c,32);
+ SHA1_R2(c,d,e,a,b,33);
+ SHA1_R2(b,c,d,e,a,34);
+ SHA1_R2(a,b,c,d,e,35);
+ SHA1_R2(e,a,b,c,d,36);
+ SHA1_R2(d,e,a,b,c,37);
+ SHA1_R2(c,d,e,a,b,38);
+ SHA1_R2(b,c,d,e,a,39);
+ SHA1_R3(a,b,c,d,e,40);
+ SHA1_R3(e,a,b,c,d,41);
+ SHA1_R3(d,e,a,b,c,42);
+ SHA1_R3(c,d,e,a,b,43);
+ SHA1_R3(b,c,d,e,a,44);
+ SHA1_R3(a,b,c,d,e,45);
+ SHA1_R3(e,a,b,c,d,46);
+ SHA1_R3(d,e,a,b,c,47);
+ SHA1_R3(c,d,e,a,b,48);
+ SHA1_R3(b,c,d,e,a,49);
+ SHA1_R3(a,b,c,d,e,50);
+ SHA1_R3(e,a,b,c,d,51);
+ SHA1_R3(d,e,a,b,c,52);
+ SHA1_R3(c,d,e,a,b,53);
+ SHA1_R3(b,c,d,e,a,54);
+ SHA1_R3(a,b,c,d,e,55);
+ SHA1_R3(e,a,b,c,d,56);
+ SHA1_R3(d,e,a,b,c,57);
+ SHA1_R3(c,d,e,a,b,58);
+ SHA1_R3(b,c,d,e,a,59);
+ SHA1_R4(a,b,c,d,e,60);
+ SHA1_R4(e,a,b,c,d,61);
+ SHA1_R4(d,e,a,b,c,62);
+ SHA1_R4(c,d,e,a,b,63);
+ SHA1_R4(b,c,d,e,a,64);
+ SHA1_R4(a,b,c,d,e,65);
+ SHA1_R4(e,a,b,c,d,66);
+ SHA1_R4(d,e,a,b,c,67);
+ SHA1_R4(c,d,e,a,b,68);
+ SHA1_R4(b,c,d,e,a,69);
+ SHA1_R4(a,b,c,d,e,70);
+ SHA1_R4(e,a,b,c,d,71);
+ SHA1_R4(d,e,a,b,c,72);
+ SHA1_R4(c,d,e,a,b,73);
+ SHA1_R4(b,c,d,e,a,74);
+ SHA1_R4(a,b,c,d,e,75);
+ SHA1_R4(e,a,b,c,d,76);
+ SHA1_R4(d,e,a,b,c,77);
+ SHA1_R4(c,d,e,a,b,78);
+ SHA1_R4(b,c,d,e,a,79);
+
+ /* Add the working vars back into digest[] */
+ digest[0] += a;
+ digest[1] += b;
+ digest[2] += c;
+ digest[3] += d;
+ digest[4] += e;
+
+ /* Count the number of transformations */
+ transforms++;
+}
+
+
+void SHA1::buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES])
+{
+ /* Convert the std::string (byte buffer) to a uint32 array (MSB) */
+ for (unsigned int i = 0; i < BLOCK_INTS; i++)
+ {
+ block[i] = (buffer[4*i+3] & 0xff)
+ | (buffer[4*i+2] & 0xff)<<8
+ | (buffer[4*i+1] & 0xff)<<16
+ | (buffer[4*i+0] & 0xff)<<24;
+ }
+}
+
+
+void SHA1::read(std::istream &is, std::string &s, int max)
+{
+ char sbuf[max];
+ is.read(sbuf, max);
+ s.assign(sbuf, is.gcount());
+}
+
+
+std::string sha1(const std::string &string)
+{
+ SHA1 checksum;
+ checksum.update(string);
+ return checksum.final();
+}
diff --git a/libs/sha1/sha1.h b/libs/sha1/sha1.h
index 540c156d..15edee12 100644
--- a/libs/sha1/sha1.h
+++ b/libs/sha1/sha1.h
@@ -1,49 +1,57 @@
-/*
- Copyright (c) 2011, Micael Hildenborg
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of Micael Hildenborg nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SHA1_DEFINED
-#define SHA1_DEFINED
-
-namespace sha1
-{
-
- /**
- @param src points to any kind of data to be hashed.
- @param bytelength the number of bytes to hash from the src pointer.
- @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.
- */
- void calc(const void* src, const int bytelength, unsigned char* hash);
-
- /**
- @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function.
- @param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string.
- */
- void toHexString(const unsigned char* hash, char* hexstring);
-
-} // namespace sha1
-
-#endif // SHA1_DEFINED
+/*
+ sha1.h - header of
+
+ ============
+ SHA-1 in C++
+ ============
+
+ 100% Public Domain.
+
+ Original C Code
+ -- Steve Reid <steve@edmweb.com>
+ Small changes to fit into bglibs
+ -- Bruce Guenter <bruce@untroubled.org>
+ Translation to simpler C++ Code
+ -- Volker Grabsch <vog@notjusthosting.com>
+*/
+
+#ifndef SHA1_HPP
+#define SHA1_HPP
+
+
+#include <iostream>
+#include <string>
+
+class SHA1
+{
+public:
+ SHA1();
+ void update(const std::string &s);
+ void update(std::istream &is);
+ std::string final();
+ static std::string from_file(const std::string &filename);
+
+private:
+ typedef unsigned long int uint32; /* just needs to be at least 32bit */
+ typedef unsigned long long uint64; /* just needs to be at least 64bit */
+
+ static const unsigned int DIGEST_INTS = 5; /* number of 32bit integers per SHA1 digest */
+ static const unsigned int BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */
+ static const unsigned int BLOCK_BYTES = BLOCK_INTS * 4;
+
+ uint32 digest[DIGEST_INTS];
+ std::string buffer;
+ uint64 transforms;
+
+ void reset();
+ void transform(uint32 block[BLOCK_BYTES]);
+
+ static void buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES]);
+ static void read(std::istream &is, std::string &s, int max);
+};
+
+std::string sha1(const std::string &string);
+
+
+
+#endif /* SHA1_HPP */
diff --git a/libs/subcircuit/subcircuit.cc b/libs/subcircuit/subcircuit.cc
index da263879..84f23d63 100644
--- a/libs/subcircuit/subcircuit.cc
+++ b/libs/subcircuit/subcircuit.cc
@@ -26,8 +26,8 @@
#include <stdio.h>
#ifdef _YOSYS_
-# include "kernel/log.h"
-# define my_printf log
+# include "kernel/yosys.h"
+# define my_printf YOSYS_NAMESPACE_PREFIX log
#else
# define my_printf printf
#endif
diff --git a/libs/svgviewer/.gitignore b/libs/svgviewer/.gitignore
deleted file mode 100644
index b92d91f8..00000000
--- a/libs/svgviewer/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-Makefile
-moc_mainwindow.cpp
-moc_svgview.cpp
-qrc_svgviewer.cpp
-svgviewer
diff --git a/libs/svgviewer/files/bubbles.svg b/libs/svgviewer/files/bubbles.svg
deleted file mode 100644
index 51730124..00000000
--- a/libs/svgviewer/files/bubbles.svg
+++ /dev/null
@@ -1,215 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
-<svg width="20cm" height="15cm" viewBox="0 0 800 600"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink/"
- baseProfile="tiny" version="1.2">
- <title>Spheres</title>
- <desc>Semi-transparent bubbles on a colored background.</desc>
- <defs>
- <!-- Create radial gradients for each bubble. -->
- <radialGradient id="blueBubble" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="-50">
- <stop offset="0%" stop-color="white" stop-opacity="1" />
- <stop offset="25%" stop-color="#cdcdff" stop-opacity=".65" />
- <stop offset="100%" stop-color="#cdaacd" stop-opacity=".75" />
- </radialGradient>
- <radialGradient id="redBubble" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="-50">
- <stop offset="0%" stop-color="white" stop-opacity="1" />
- <stop offset="25%" stop-color="#ffcdcd" stop-opacity=".65" />
- <stop offset="100%" stop-color="#bbbb99" stop-opacity=".75" />
- </radialGradient>
- <radialGradient id="greenBubble" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="-50">
- <stop offset="0%" stop-color="white" stop-opacity="1" />
- <stop offset="25%" stop-color="#cdffcd" stop-opacity=".65" />
- <stop offset="100%" stop-color="#99aaaa" stop-opacity=".75" />
- </radialGradient>
- <radialGradient id="yellowBubble" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="-50">
- <stop offset="0%" stop-color="white" stop-opacity="1" />
- <stop offset="25%" stop-color="#ffffcd" stop-opacity=".65" />
- <stop offset="100%" stop-color="#bbbbaa" stop-opacity=".75" />
- </radialGradient>
- <radialGradient id="background" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="400" fx="250" fy="250">
- <stop offset="0%" stop-color="#ffffee" />
- <stop offset="100%" stop-color="#ccccaa" />
- </radialGradient>
- <linearGradient id="surface" gradientUnits="userSpaceOnUse"
- x1="-100" y1="200" x2="400" y2="200">
- <stop offset="0%" stop-color="#ffffcc" />
- <stop offset="100%" stop-color="#bbbb88" />
- </linearGradient>
-
- <!-- Create radial gradients for each circle to make them look like
- spheres. -->
- <radialGradient id="blueSphere" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="-50">
- <stop offset="0%" stop-color="white" />
- <stop offset="75%" stop-color="blue" />
- <stop offset="100%" stop-color="#222244" />
- </radialGradient>
- <radialGradient id="redSphere" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="-50">
- <stop offset="0%" stop-color="white" />
- <stop offset="75%" stop-color="red" />
- <stop offset="100%" stop-color="#442222" />
- </radialGradient>
- <radialGradient id="greenSphere" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="-50">
- <stop offset="0%" stop-color="white" />
- <stop offset="75%" stop-color="green" />
- <stop offset="100%" stop-color="#113311" />
- </radialGradient>
- <radialGradient id="yellowSphere" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="-50">
- <stop offset="0%" stop-color="white" />
- <stop offset="75%" stop-color="yellow" />
- <stop offset="100%" stop-color="#444422" />
- </radialGradient>
- <radialGradient id="shadowGrad" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="50">
- <stop offset="0%" stop-color="black" stop-opacity="1.0" />
- <stop offset="100%" stop-color="black" stop-opacity="0.0" />
- </radialGradient>
-
- <!-- Define a shadow for each sphere. -->
- <circle id="shadow" fill="url(#shadowGrad)" cx="0" cy="0" r="100" />
- <g id="bubble">
- <circle fill="black" cx="0" cy="0" r="50" />
- <circle fill="#a6ce39" cx="0" cy="0" r="33" />
- <path fill="black" d="M 37,50 L 50,37 L 12,-1 L 22,-11 L 10,-24 L -24,10
- L -11,22 L -1,12 Z" />
- <circle cx="0" cy="0" r="100" />
- </g>
- </defs>
- <g>
- <rect fill="url(#background)" x="0" y="0" width="800" height="600" />
- </g>
-
- <g transform="translate(200,700)">
- <use xlink:href="#bubble" fill="url(#blueBubble)" />
- <animateTransform attributeName="transform" type="translate" additive="sum"
- values="0,0; 0,-800" begin="1s" dur="10s" fill="freeze" repeatCount="indefinite" />
- </g>
- <g transform="translate(315,700)">
- <g transform="scale(0.5,0.5)">
- <use xlink:href="#bubble" fill="url(#redBubble)" />
- </g>
- <animateTransform attributeName="transform" type="translate" additive="sum"
- values="0,0; 0,-800" begin="3s" dur="7s" fill="freeze" repeatCount="indefinite" />
- </g>
- <g transform="translate(80,700)">
- <g transform="scale(0.65,0.65)">
- <use xlink:href="#bubble" fill="url(#greenBubble)" />
- </g>
- <animateTransform attributeName="transform" type="translate" additive="sum"
- values="0,0; 0,-800" begin="5s" dur="9s" fill="freeze" repeatCount="indefinite" />
- </g>
- <g transform="translate(255,700)">
- <g transform="scale(0.3,0.3)">
- <use xlink:href="#bubble" fill="url(#yellowBubble)" />
- </g>
- <animateTransform attributeName="transform" type="translate" additive="sum"
- values="0,0; 0,-800" begin="2s" dur="6s" fill="freeze" repeatCount="indefinite" />
- </g>
- <g transform="translate(565,700)">
- <g transform="scale(0.4,0.4)">
- <use xlink:href="#bubble" fill="url(#blueBubble)" />
- </g>
- <animateTransform attributeName="transform" type="translate" additive="sum"
- values="0,0; 0,-800" begin="4s" dur="8s" fill="freeze" repeatCount="indefinite" />
- </g>
- <g transform="translate(715,700)">
- <g transform="scale(0.6,0.6)">
- <use xlink:href="#bubble" fill="url(#redBubble)" />
- </g>
- <animateTransform attributeName="transform" type="translate" additive="sum"
- values="0,0; 0,-800" begin="1s" dur="4s" fill="freeze" repeatCount="indefinite" />
- </g>
- <g transform="translate(645,700)">
- <g transform="scale(0.375,0.375)">
- <use xlink:href="#bubble" fill="url(#greenBubble)" />
- </g>
- <animateTransform attributeName="transform" type="translate" additive="sum"
- values="0,0; 0,-800" begin="0s" dur="11s" fill="freeze" repeatCount="indefinite" />
- </g>
- <g transform="translate(555,700)">
- <g transform="scale(0.9,0.9)">
- <use xlink:href="#bubble" fill="url(#yellowBubble)" />
- </g>
- <animateTransform attributeName="transform" type="translate" additive="sum"
- values="0,0; 0,-800" begin="3s" dur="7.5s" fill="freeze" repeatCount="indefinite" />
- </g>
-
- <g transform="translate(360,700)">
- <g transform="scale(0.5,0.5)">
- <use xlink:href="#bubble" fill="url(#blueBubble)" />
- </g>
- <animateTransform attributeName="transform" type="translate" additive="sum"
- values="0,0; 0,-800" begin="3s" dur="6s" fill="freeze" repeatCount="indefinite" />
- </g>
- <g transform="translate(215,700)">
- <g transform="scale(0.45,0.45)">
- <use xlink:href="#bubble" fill="url(#redBubble)" />
- </g>
- <animateTransform attributeName="transform" type="translate" additive="sum"
- values="0,0; 0,-800" begin="5.5s" dur="7s" fill="freeze" repeatCount="indefinite" />
- </g>
- <g transform="translate(420,700)">
- <g transform="scale(0.75,0.75)">
- <use xlink:href="#bubble" fill="url(#greenBubble)" />
- </g>
- <animateTransform attributeName="transform" type="translate" additive="sum"
- values="0,0; 0,-800" begin="1s" dur="9s" fill="freeze" repeatCount="indefinite" />
- </g>
- <g transform="translate(815,700)">
- <g transform="scale(0.6,0.6)">
- <use xlink:href="#bubble" fill="url(#yellowBubble)" />
- </g>
- <animateTransform attributeName="transform" type="translate" additive="sum"
- values="0,0; 0,-800" begin="2s" dur="9.5s" fill="freeze" repeatCount="indefinite" />
- </g>
-
- <g transform="translate(225,375)" >
- <g transform="scale(1.0,0.5)" >
- <path d="M 0 0 L 350 0 L 450 450 L -100 450 z"
- fill="url(#surface)" stroke="none" />
- </g>
- </g>
- <g transform="translate(200,0)" >
- <g transform="translate(200,490) scale(2.0,1.0) rotate(45)" >
- <rect fill="#a6ce39" x="-69" y="-69" width="138" height="138" />
- <circle fill="black" cx="0" cy="0" r="50" />
- <circle fill="#a6ce39" cx="0" cy="0" r="33" />
- <path fill="black" d="M 37,50 L 50,37 L 12,-1 L 22,-11 L 10,-24 L -24,10
- L -11,22 L -1,12 Z" />
- <animateTransform attributeName="transform" type="rotate" additive="sum" values="0; 360"
- begin="0s" dur="10s" fill="freeze" repeatCount="indefinite" />
- </g>
- <g transform="translate(200,375)">
- <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
- <circle fill="url(#blueSphere)" cx="0" cy="0" r="100" />
- </g>
- <g transform="translate(315,440)">
- <g transform="scale(0.5,0.5)">
- <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
- <circle fill="url(#redSphere)" cx="0" cy="0" r="100" />
- </g>
- </g>
- <g transform="translate(80,475)">
- <g transform="scale(0.65,0.65)">
- <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
- <circle fill="url(#greenSphere)" cx="0" cy="0" r="100" />
- </g>
- </g>
- <g transform="translate(255,525)">
- <g transform="scale(0.3,0.3)">
- <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
- <circle fill="url(#yellowSphere)" cx="0" cy="0" r="100" />
- </g>
- </g>
- </g>
-</svg>
diff --git a/libs/svgviewer/files/cubic.svg b/libs/svgviewer/files/cubic.svg
deleted file mode 100644
index 492bb72b..00000000
--- a/libs/svgviewer/files/cubic.svg
+++ /dev/null
@@ -1,77 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<svg width="10cm" height="10cm" viewBox="0 0 1000 1000"
- xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny">
- <title>Example cubic02 - cubic Bezier commands in path data</title>
- <desc>Picture showing examples of "C" and "S" commands,
- along with annotations showing the control points
- and end points</desc>
-
- <rect fill="none" stroke="blue" stroke-width="1" x="1" y="1" width="998" height="998" />
-
- <!-- Path 1 -->
- <polyline fill="none" stroke="#888888" stroke-width="2" points="100,200 100,100" />
- <polyline fill="none" stroke="#888888" stroke-width="2" points="400,100 400,200" />
- <path fill="none" stroke="red" stroke-width="5" d="M100,200 C100,100 400,100 400,200" />
- <circle fill="none" stroke="#888888" stroke-width="2" cx="100" cy="200" r="10" />
- <circle fill="none" stroke="#888888" stroke-width="2" cx="400" cy="200" r="10" />
- <circle class="CtlPoint" cx="100" cy="100" r="10" />
- <circle class="CtlPoint" cx="400" cy="100" r="10" />
- <text text-anchor="middle" font-size="22" font-family="Verdana" x="250" y="275">M100,200 C100,100 400,100 400,200</text>
-
- <!-- Path 2 -->
- <polyline fill="none" stroke="#888888" stroke-width="2" points="100,500 25,400" />
- <polyline fill="none" stroke="#888888" stroke-width="2" points="475,400 400,500" />
- <path fill="none" stroke="red" stroke-width="5" d="M100,500 C25,400 475,400 400,500" />
- <circle fill="none" stroke="#888888" stroke-width="2" cx="100" cy="500" r="10" />
- <circle fill="none" stroke="#888888" stroke-width="2" cx="400" cy="500" r="10" />
- <circle fill="#888888" stroke="none" cx="25" cy="400" r="10" />
- <circle fill="#888888" stroke="none" cx="475" cy="400" r="10" />
- <text text-anchor="middle" font-size="22" font-family="Verdana" x="250" y="575">M100,500 C25,400 475,400 400,500</text>
-
- <!-- Path 3 -->
- <polyline fill="none" stroke="#888888" stroke-width="2" points="100,800 175,700" />
- <polyline fill="none" stroke="#888888" stroke-width="2" points="325,700 400,800" />
- <path fill="none" stroke="red" stroke-width="5" d="M100,800 C175,700 325,700 400,800" />
- <circle fill="none" stroke="#888888" stroke-width="2" cx="100" cy="800" r="10" />
- <circle fill="none" stroke="#888888" stroke-width="2" cx="400" cy="800" r="10" />
- <circle fill="#888888" stroke="none" cx="175" cy="700" r="10" />
- <circle fill="#888888" stroke="none" cx="325" cy="700" r="10" />
- <text text-anchor="middle" font-size="22" font-family="Verdana" x="250" y="875">M100,800 C175,700 325,700 400,800</text>
-
- <!-- Path 4 -->
- <polyline fill="none" stroke="#888888" stroke-width="2" points="600,200 675,100" />
- <polyline fill="none" stroke="#888888" stroke-width="2" points="975,100 900,200" />
- <path fill="none" stroke="red" stroke-width="5" d="M600,200 C675,100 975,100 900,200" />
- <circle fill="none" stroke="#888888" stroke-width="2" cx="600" cy="200" r="10" />
- <circle fill="none" stroke="#888888" stroke-width="2" cx="900" cy="200" r="10" />
- <circle fill="#888888" stroke="none" cx="675" cy="100" r="10" />
- <circle fill="#888888" stroke="none" cx="975" cy="100" r="10" />
- <text text-anchor="middle" font-size="22" font-family="Verdana" x="750" y="275">M600,200 C675,100 975,100 900,200</text>
-
- <!-- Path 5 -->
- <polyline fill="none" stroke="#888888" stroke-width="2" points="600,500 600,350" />
- <polyline fill="none" stroke="#888888" stroke-width="2" points="900,650 900,500" />
- <path fill="none" stroke="red" stroke-width="5" d="M600,500 C600,350 900,650 900,500" />
- <circle fill="none" stroke="#888888" stroke-width="2" cx="600" cy="500" r="10" />
- <circle fill="none" stroke="#888888" stroke-width="2" cx="900" cy="500" r="10" />
- <circle fill="#888888" stroke="none" cx="600" cy="350" r="10" />
- <circle fill="#888888" stroke="none" cx="900" cy="650" r="10" />
- <text text-anchor="middle" font-size="22" font-family="Verdana" x="750" y="575">M600,500 C600,350 900,650 900,500</text>
-
- <!-- Path 6 (C and S command) -->
- <polyline fill="none" stroke="#888888" stroke-width="2" points="600,800 625,700" />
- <polyline fill="none" stroke="#888888" stroke-width="2" points="725,700 750,800" />
- <polyline fill="none" stroke="#888888" stroke-width="2" points="750,800 775,900" />
- <polyline fill="none" stroke="#888888" stroke-width="2" points="875,900 900,800" />
- <path fill="none" stroke="red" stroke-width="5" d="M600,800 C625,700 725,700 750,800
- S875,900 900,800" />
- <circle fill="none" stroke="#888888" stroke-width="2" cx="600" cy="800" r="10" />
- <circle fill="none" stroke="#888888" stroke-width="2" cx="750" cy="800" r="10" />
- <circle fill="none" stroke="#888888" stroke-width="2" cx="900" cy="800" r="10" />
- <circle fill="#888888" stroke="none" cx="625" cy="700" r="10" />
- <circle fill="#888888" stroke="none" cx="725" cy="700" r="10" />
- <circle fill="#888888" stroke="none" cx="875" cy="900" r="10" />
- <circle fill="none" stroke="blue" stroke-width="4" cx="775" cy="900" r="9" />
- <text text-anchor="middle" font-size="22" font-family="Verdana" x="750" y="945">M600,800 C625,700 725,700 750,800</text>
- <text text-anchor="middle" font-size="22" font-family="Verdana" x="750" y="975">S875,900 900,800</text>
-</svg>
diff --git a/libs/svgviewer/files/spheres.svg b/libs/svgviewer/files/spheres.svg
deleted file mode 100644
index b23164bc..00000000
--- a/libs/svgviewer/files/spheres.svg
+++ /dev/null
@@ -1,72 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<svg width="8cm" height="8cm" viewBox="0 0 400 400"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink/"
- baseProfile="tiny" version="1.2">
- <title>Spheres</title>
- <desc>Gradient filled spheres with different colors.</desc>
- <defs>
- <!-- Create radial gradients for each circle to make them look like
- spheres. -->
- <radialGradient id="blueSphere" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="-50">
- <stop offset="0%" stop-color="white" />
- <stop offset="75%" stop-color="blue" />
- <stop offset="100%" stop-color="#222244" />
- </radialGradient>
- <radialGradient id="redSphere" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="-50">
- <stop offset="0%" stop-color="white" />
- <stop offset="75%" stop-color="red" />
- <stop offset="100%" stop-color="#442222" />
- </radialGradient>
- <radialGradient id="greenSphere" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="-50">
- <stop offset="0%" stop-color="white" />
- <stop offset="75%" stop-color="green" />
- <stop offset="100%" stop-color="#113311" />
- </radialGradient>
- <radialGradient id="yellowSphere" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="-50">
- <stop offset="0%" stop-color="white" />
- <stop offset="75%" stop-color="yellow" />
- <stop offset="100%" stop-color="#444422" />
- </radialGradient>
- <radialGradient id="shadowGrad" gradientUnits="userSpaceOnUse"
- cx="0" cy="0" r="100" fx="-50" fy="50">
- <stop offset="0%" stop-color="black" stop-opacity="1.0" />
- <stop offset="100%" stop-color="white" stop-opacity="0.0" />
- </radialGradient>
-
- <!-- Define a shadow for each sphere. -->
- <circle id="shadow" fill="url(#shadowGrad)" cx="0" cy="0" r="100" />
- </defs>
- <g fill="#ffee99" stroke="none" >
- <rect x="0" y="0" width="400" height="400" />
- </g>
- <g fill="white" stroke="none" >
- <rect x="0" y="175" width="400" height="225" />
- </g>
- <g transform="translate(200,175)">
- <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
- <circle fill="url(#blueSphere)" cx="0" cy="0" r="100" />
- </g>
- <g transform="translate(315,240)">
- <g transform="scale(0.5,0.5)">
- <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
- <circle fill="url(#redSphere)" cx="0" cy="0" r="100" />
- </g>
- </g>
- <g transform="translate(80,275)">
- <g transform="scale(0.65,0.65)">
- <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
- <circle fill="url(#greenSphere)" cx="0" cy="0" r="100" />
- </g>
- </g>
- <g transform="translate(255,325)">
- <g transform="scale(0.3,0.3)">
- <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
- <circle fill="url(#yellowSphere)" cx="0" cy="0" r="100" />
- </g>
- </g>
-</svg>
diff --git a/libs/svgviewer/main.cpp b/libs/svgviewer/main.cpp
deleted file mode 100644
index 34866f85..00000000
--- a/libs/svgviewer/main.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
-** of its contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QApplication>
-#include <QString>
-#ifndef QT_NO_OPENGL
-#include <QGLFormat>
-#endif
-
-#include "mainwindow.h"
-
-int main(int argc, char **argv)
-{
- Q_INIT_RESOURCE(svgviewer);
-
- QApplication app(argc, argv);
-
- MainWindow window;
- if (argc == 2)
- window.openFile(argv[1]);
- else
- window.openFile(":/files/bubbles.svg");
-#if defined(Q_OS_SYMBIAN)
- window.showMaximized();
-#else
- window.show();
-#endif
- return app.exec();
-}
diff --git a/libs/svgviewer/mainwindow.cpp b/libs/svgviewer/mainwindow.cpp
deleted file mode 100644
index 70da140e..00000000
--- a/libs/svgviewer/mainwindow.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
-** of its contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "mainwindow.h"
-
-#include <QtGui>
-#include <unistd.h>
-#include <QFileSystemWatcher>
-
-#include "svgview.h"
-
-MainWindow::MainWindow()
- : QMainWindow()
- , m_view(new SvgView)
- , m_watcher(NULL)
- , m_filehandle(NULL)
-{
- QMenu *fileMenu = new QMenu(tr("&File"), this);
- QAction *openAction = fileMenu->addAction(tr("&Open..."));
- openAction->setShortcut(QKeySequence(tr("Ctrl+O")));
- QAction *quitAction = fileMenu->addAction(tr("E&xit"));
- quitAction->setShortcuts(QKeySequence::Quit);
-
- menuBar()->addMenu(fileMenu);
-
- QMenu *viewMenu = new QMenu(tr("&View"), this);
-
- m_interactiveAction = viewMenu->addAction(tr("&Interactive"));
- m_interactiveAction->setEnabled(false);
- m_interactiveAction->setCheckable(true);
- m_interactiveAction->setChecked(false);
- connect(m_interactiveAction, SIGNAL(toggled(bool)), m_view, SLOT(setViewInteractive(bool)));
-
- m_backgroundAction = viewMenu->addAction(tr("&Background"));
- m_backgroundAction->setEnabled(false);
- m_backgroundAction->setCheckable(true);
- m_backgroundAction->setChecked(false);
- m_backgroundAction->setVisible(false);
- connect(m_backgroundAction, SIGNAL(toggled(bool)), m_view, SLOT(setViewBackground(bool)));
-
- m_outlineAction = viewMenu->addAction(tr("&Outline"));
- m_outlineAction->setEnabled(false);
- m_outlineAction->setCheckable(true);
- m_outlineAction->setChecked(true);
- connect(m_outlineAction, SIGNAL(toggled(bool)), m_view, SLOT(setViewOutline(bool)));
-
- menuBar()->addMenu(viewMenu);
-
- QMenu *rendererMenu = new QMenu(tr("&Renderer"), this);
- m_nativeAction = rendererMenu->addAction(tr("&Native"));
- m_nativeAction->setCheckable(true);
- m_nativeAction->setChecked(true);
-#ifndef QT_NO_OPENGL
- m_glAction = rendererMenu->addAction(tr("&OpenGL"));
- m_glAction->setCheckable(true);
-#endif
- m_imageAction = rendererMenu->addAction(tr("&Image"));
- m_imageAction->setCheckable(true);
-
-#ifndef QT_NO_OPENGL
- rendererMenu->addSeparator();
- m_highQualityAntialiasingAction = rendererMenu->addAction(tr("&High Quality Antialiasing"));
- m_highQualityAntialiasingAction->setEnabled(false);
- m_highQualityAntialiasingAction->setCheckable(true);
- m_highQualityAntialiasingAction->setChecked(false);
- connect(m_highQualityAntialiasingAction, SIGNAL(toggled(bool)), m_view, SLOT(setHighQualityAntialiasing(bool)));
-#endif
-
- QActionGroup *rendererGroup = new QActionGroup(this);
- rendererGroup->addAction(m_nativeAction);
-#ifndef QT_NO_OPENGL
- rendererGroup->addAction(m_glAction);
-#endif
- rendererGroup->addAction(m_imageAction);
-
- menuBar()->addMenu(rendererMenu);
-
- connect(openAction, SIGNAL(triggered()), this, SLOT(openFile()));
- connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
- connect(rendererGroup, SIGNAL(triggered(QAction*)),
- this, SLOT(setRenderer(QAction*)));
-
- setCentralWidget(m_view);
- setWindowTitle(tr("Yosys SVG Viewer"));
-}
-
-void MainWindow::openFile(const QString &path, bool reload)
-{
- QString fileName;
- if (path.isNull())
- fileName = QFileDialog::getOpenFileName(this, tr("Open SVG File"),
- m_currentPath, "SVG files (*.svg *.svgz *.svg.gz)");
- else
- fileName = path;
-
- if (m_watcher) {
- delete m_watcher;
- m_watcher = NULL;
- }
- if (m_filehandle) {
- fclose(m_filehandle);
- m_filehandle = NULL;
- }
-
- if (!fileName.isEmpty()) {
- QFile file(fileName);
- if (!file.exists()) {
- QMessageBox::critical(this, tr("Open SVG File"),
- QString("Could not open file '%1'.").arg(fileName));
-
- m_interactiveAction->setEnabled(false);
- m_outlineAction->setEnabled(false);
- m_backgroundAction->setEnabled(false);
- return;
- }
-
- QTransform oldTransform = m_view->transform();
- m_view->openFile(file);
-
- if (!fileName.startsWith(":/"))
- {
- m_currentPath = fileName;
- setWindowTitle(tr("%1 - Yosys SVG Viewer").arg(m_currentPath));
-
- // just keep the file open so this process is found using 'fuser'
- m_filehandle = fopen(fileName.toAscii(), "r");
-
- m_watcher = new QFileSystemWatcher(this);
- m_watcher->addPath(fileName);
- connect(m_watcher, SIGNAL(fileChanged(const QString&)), this, SLOT(reloadFile()));
- }
-
- m_interactiveAction->setEnabled(true);
- m_outlineAction->setEnabled(true);
- m_backgroundAction->setEnabled(true);
-
- if (reload)
- m_view->setTransform(oldTransform);
- else
- resize(m_view->sizeHint() + QSize(80, 80 + menuBar()->height()));
- }
-}
-
-void MainWindow::reloadFile()
-{
- // give the writer ~100 ms to finish writing
- usleep(100000);
- openFile(m_currentPath, true);
-}
-
-void MainWindow::setRenderer(QAction *action)
-{
-#ifndef QT_NO_OPENGL
- m_highQualityAntialiasingAction->setEnabled(false);
-#endif
-
- if (action == m_nativeAction)
- m_view->setRenderer(SvgView::Native);
-#ifndef QT_NO_OPENGL
- else if (action == m_glAction) {
- m_highQualityAntialiasingAction->setEnabled(true);
- m_view->setRenderer(SvgView::OpenGL);
- }
-#endif
- else if (action == m_imageAction) {
- m_view->setRenderer(SvgView::Image);
- }
-}
diff --git a/libs/svgviewer/mainwindow.h b/libs/svgviewer/mainwindow.h
deleted file mode 100644
index dfb5586d..00000000
--- a/libs/svgviewer/mainwindow.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
-** of its contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef MAINWINDOW_H
-#define MAINWINDOW_H
-
-#include <QMainWindow>
-#include <QString>
-#include <stdio.h>
-
-class SvgView;
-
-QT_BEGIN_NAMESPACE
-class QAction;
-class QGraphicsView;
-class QGraphicsScene;
-class QGraphicsRectItem;
-class QFileSystemWatcher;
-QT_END_NAMESPACE
-
-class MainWindow : public QMainWindow
-{
- Q_OBJECT
-
-public:
- MainWindow();
-
-public slots:
- void openFile(const QString &path = QString(), bool reload = false);
- void setRenderer(QAction *action);
- void reloadFile();
-
-private:
- QAction *m_nativeAction;
- QAction *m_glAction;
- QAction *m_imageAction;
- QAction *m_highQualityAntialiasingAction;
- QAction *m_interactiveAction;
- QAction *m_backgroundAction;
- QAction *m_outlineAction;
-
- SvgView *m_view;
-
- QString m_currentPath;
- QFileSystemWatcher *m_watcher;
- FILE *m_filehandle;
-};
-
-#endif
diff --git a/libs/svgviewer/svgview.cpp b/libs/svgviewer/svgview.cpp
deleted file mode 100644
index 5a1a5ab2..00000000
--- a/libs/svgviewer/svgview.cpp
+++ /dev/null
@@ -1,227 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
-** of its contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "svgview.h"
-
-#include <QFile>
-#include <QWheelEvent>
-#include <QMouseEvent>
-#include <QGraphicsRectItem>
-#include <QGraphicsSvgItem>
-#include <QGraphicsWebView>
-#include <QPaintEvent>
-#include <qmath.h>
-#include <unistd.h>
-
-#ifndef QT_NO_OPENGL
-#include <QGLWidget>
-#endif
-
-SvgView::SvgView(QWidget *parent)
- : QGraphicsView(parent)
- , m_renderer(Native)
- , m_svgItem(0)
- , m_webview(0)
- , m_backgroundItem(0)
- , m_outlineItem(0)
-{
- setScene(new QGraphicsScene(this));
- setTransformationAnchor(AnchorUnderMouse);
- setDragMode(ScrollHandDrag);
- setViewportUpdateMode(FullViewportUpdate);
-
- // Prepare background check-board pattern
- QPixmap tilePixmap(64, 64);
- tilePixmap.fill(Qt::white);
- QPainter tilePainter(&tilePixmap);
- QColor color(220, 220, 220);
- tilePainter.fillRect(0, 0, 32, 32, color);
- tilePainter.fillRect(32, 32, 32, 32, color);
- tilePainter.end();
-
- setBackgroundBrush(tilePixmap);
-}
-
-void SvgView::drawBackground(QPainter *p, const QRectF &)
-{
- p->save();
- p->resetTransform();
- p->drawTiledPixmap(viewport()->rect(), backgroundBrush().texture());
- p->restore();
-}
-
-void SvgView::openFile(const QFile &file)
-{
- if (!file.exists())
- return;
-
- QGraphicsScene *s = scene();
-
- fn = file.fileName();
- if (fn[0] != '/') {
- char cwd_buffer[4096];
- if (getcwd(cwd_buffer, 4096) != NULL)
- fn = cwd_buffer + ("/" + fn);
- }
-
- bool drawBackground = (m_backgroundItem ? m_backgroundItem->isVisible() : false);
- bool drawOutline = (m_outlineItem ? m_outlineItem->isVisible() : true);
- bool useWebview = (m_webview ? m_webview->isVisible() : false);
-
- s->clear();
- resetTransform();
-
- m_svgItem = new QGraphicsSvgItem(file.fileName());
- m_svgItem->setFlags(QGraphicsItem::ItemClipsToShape);
- m_svgItem->setCacheMode(QGraphicsItem::NoCache);
- m_svgItem->setVisible(!useWebview);
- m_svgItem->setZValue(1);
- s->addItem(m_svgItem);
-
- if (useWebview) {
- m_webview = new QGraphicsWebView();
- m_webview->load(QUrl::fromLocalFile(fn));
- m_webview->setResizesToContents(true);
- m_webview->setZoomFactor(0.75);
- m_webview->setVisible(useWebview);
- m_webview->setZValue(1);
- s->addItem(m_webview);
- } else
- m_webview = NULL;
-
- m_backgroundItem = new QGraphicsRectItem(m_svgItem->boundingRect());
- m_backgroundItem->setBrush(Qt::white);
- m_backgroundItem->setPen(Qt::NoPen);
- m_backgroundItem->setVisible(drawBackground);
- m_backgroundItem->setZValue(0);
- s->addItem(m_backgroundItem);
-
- m_outlineItem = new QGraphicsRectItem(m_svgItem->boundingRect());
- QPen outline(Qt::black, 2, Qt::DashLine);
- outline.setCosmetic(true);
- m_outlineItem->setPen(outline);
- m_outlineItem->setBrush(Qt::NoBrush);
- m_outlineItem->setVisible(drawOutline);
- m_outlineItem->setZValue(2);
- s->addItem(m_outlineItem);
-
- s->setSceneRect(m_outlineItem->boundingRect().adjusted(-10, -10, 10, 10));
-}
-
-void SvgView::setRenderer(RendererType type)
-{
- m_renderer = type;
-
- if (m_renderer == OpenGL) {
-#ifndef QT_NO_OPENGL
- setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
-#endif
- } else {
- setViewport(new QWidget);
- }
-}
-
-void SvgView::setHighQualityAntialiasing(bool highQualityAntialiasing)
-{
-#ifndef QT_NO_OPENGL
- setRenderHint(QPainter::HighQualityAntialiasing, highQualityAntialiasing);
-#else
- Q_UNUSED(highQualityAntialiasing);
-#endif
-}
-
-void SvgView::setViewInteractive(bool enable)
-{
- if (!m_svgItem)
- return;
- if (!m_webview) {
- m_webview = new QGraphicsWebView();
- m_webview->load(QUrl::fromLocalFile(fn));
- m_webview->setResizesToContents(true);
- m_webview->setZoomFactor(0.75);
- m_webview->setVisible(false);
- m_webview->setZValue(1);
- m_svgItem->scene()->addItem(m_webview);
- }
- m_svgItem->setVisible(!enable);
- m_webview->setVisible(enable);
-}
-
-void SvgView::setViewBackground(bool enable)
-{
- if (!m_backgroundItem)
- return;
-
- m_backgroundItem->setVisible(enable);
-}
-
-void SvgView::setViewOutline(bool enable)
-{
- if (!m_outlineItem)
- return;
-
- m_outlineItem->setVisible(enable);
-}
-
-void SvgView::paintEvent(QPaintEvent *event)
-{
- if (m_renderer == Image) {
- if (m_image.size() != viewport()->size()) {
- m_image = QImage(viewport()->size(), QImage::Format_ARGB32_Premultiplied);
- }
-
- QPainter imagePainter(&m_image);
- QGraphicsView::render(&imagePainter);
- imagePainter.end();
-
- QPainter p(viewport());
- p.drawImage(0, 0, m_image);
-
- } else {
- QGraphicsView::paintEvent(event);
- }
-}
-
-void SvgView::wheelEvent(QWheelEvent *event)
-{
- qreal factor = qPow(1.2, event->delta() / 240.0);
- scale(factor, factor);
- event->accept();
-}
-
diff --git a/libs/svgviewer/svgview.h b/libs/svgviewer/svgview.h
deleted file mode 100644
index 833bb52e..00000000
--- a/libs/svgviewer/svgview.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
-** of its contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef SVGVIEW_H
-#define SVGVIEW_H
-
-#include <QGraphicsView>
-#include <QGraphicsWebView>
-
-QT_BEGIN_NAMESPACE
-class QWheelEvent;
-class QPaintEvent;
-class QFile;
-QT_END_NAMESPACE
-
-class SvgView : public QGraphicsView
-{
- Q_OBJECT
-
-public:
- enum RendererType { Native, OpenGL, Image };
-
- SvgView(QWidget *parent = 0);
-
- void openFile(const QFile &file);
- void setRenderer(RendererType type = Native);
- void drawBackground(QPainter *p, const QRectF &rect);
-
-public slots:
- void setHighQualityAntialiasing(bool highQualityAntialiasing);
- void setViewInteractive(bool enable);
- void setViewBackground(bool enable);
- void setViewOutline(bool enable);
-
-protected:
- void wheelEvent(QWheelEvent *event);
- void paintEvent(QPaintEvent *event);
-
-private:
- RendererType m_renderer;
-
- QString fn;
- QGraphicsItem *m_svgItem;
- QGraphicsWebView *m_webview;
- QGraphicsRectItem *m_backgroundItem;
- QGraphicsRectItem *m_outlineItem;
-
- QImage m_image;
-};
-#endif // SVGVIEW_H
diff --git a/libs/svgviewer/svgviewer.desktop b/libs/svgviewer/svgviewer.desktop
deleted file mode 100644
index 477ef789..00000000
--- a/libs/svgviewer/svgviewer.desktop
+++ /dev/null
@@ -1,11 +0,0 @@
-[Desktop Entry]
-Encoding=UTF-8
-Version=1.0
-Type=Application
-Terminal=false
-Name=SVG Viewer
-Exec=/opt/usr/bin/svgviewer
-Icon=svgviewer
-X-Window-Icon=
-X-HildonDesk-ShowInToolbar=true
-X-Osso-Type=application/x-executable
diff --git a/libs/svgviewer/svgviewer.pro b/libs/svgviewer/svgviewer.pro
deleted file mode 100644
index 488c62fd..00000000
--- a/libs/svgviewer/svgviewer.pro
+++ /dev/null
@@ -1,33 +0,0 @@
-HEADERS = mainwindow.h \
- svgview.h
-RESOURCES = svgviewer.qrc
-SOURCES = main.cpp \
- mainwindow.cpp \
- svgview.cpp
-QT += webkit svg xml
-
-contains(QT_CONFIG, opengl): QT += opengl
-
-CONFIG += console
-
-# install
-target.path = $$[QT_INSTALL_EXAMPLES]/painting/svgviewer
-sources.files = $$SOURCES $$HEADERS $$RESOURCES svgviewer.pro files
-sources.path = $$[QT_INSTALL_EXAMPLES]/painting/svgviewer
-INSTALLS += target sources
-
-wince*: {
- addFiles.files = files\\*.svg
- addFiles.path = "\\My Documents"
- DEPLOYMENT += addFiles
-}
-
-symbian: {
- TARGET.UID3 = 0xA000A64E
- include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri)
- addFiles.files = files\\*.svg
- addFiles.path = .
- DEPLOYMENT += addFiles
-}
-maemo5: include($$QT_SOURCE_TREE/examples/maemo5pkgrules.pri)
-
diff --git a/libs/svgviewer/svgviewer.qrc b/libs/svgviewer/svgviewer.qrc
deleted file mode 100644
index db611f51..00000000
--- a/libs/svgviewer/svgviewer.qrc
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource prefix="/">
- <file>files/bubbles.svg</file>
-</qresource>
-</RCC>
-
diff --git a/manual/APPNOTE_011_Design_Investigation.tex b/manual/APPNOTE_011_Design_Investigation.tex
index c0481186..504ab7ec 100644
--- a/manual/APPNOTE_011_Design_Investigation.tex
+++ b/manual/APPNOTE_011_Design_Investigation.tex
@@ -54,7 +54,7 @@
\begin{document}
\title{Yosys Application Note 011: \\ Interactive Design Investigation}
-\author{Clifford Wolf \\ December 2013}
+\author{Clifford Wolf \\ Original Verision December 2013}
\maketitle
\begin{abstract}
@@ -74,9 +74,7 @@ commands for evaluating circuits and solving SAT problems.
This Application Note is based on the Yosys \cite{yosys} GIT Rev. {\tt 2b90ba1} from
2013-12-08. The {\tt README} file covers how to install Yosys. The
{\tt show} command requires a working installation of GraphViz \cite{graphviz}
-for generating the actual circuit diagrams. Yosys must be build with Qt
-support for the built-in SVG viewer. Alternatively an external viewer can be
-used, if Qt is not available.
+and \cite{xdot} for generating the actual circuit diagrams.
\section{Overview}
@@ -131,8 +129,8 @@ The {\tt show} command generates a circuit diagram for the design in its
current state. Various options can be used to change the appearance of the
circuit diagram, set the name and format for the output file, and so forth.
When called without any special options, it saves the circuit diagram in
-a temporary file and launches {\tt yosys-svgviewer} to display the diagram.
-Subsequent calls to {\tt show} re-use the {\tt yosys-svgviewer} instance
+a temporary file and launches {\tt xdot} to display the diagram.
+Subsequent calls to {\tt show} re-use the {\tt xdot} instance
(if still running).
\subsection{A simple circuit}
@@ -270,18 +268,12 @@ command only operates on interior signals.
\subsection{Miscellaneous notes}
-Per default the {\tt show} command outputs a temporary SVG file and launches
-{\tt yosys-svgviewer} to display it. The options {\tt -format}, {\tt -viewer}
+Per default the {\tt show} command outputs a temporary {\tt dot} file and launches
+{\tt xdot} to display it. The options {\tt -format}, {\tt -viewer}
and {\tt -prefix} can be used to change format, viewer and filename prefix.
Note that the {\tt pdf} and {\tt ps} format are the only formats that support
plotting multiple modules in one run.
-In {\tt yosys-svgviewer} the left mouse button is per default bound to move the
-diagram (and the mouse wheel can be used for zooming in and out). However, in
-some cases one wants to copy text from the diagram. In this cases the
-View->Interactive checkbox must be activated. This switches the rendering back-end
-in a mode that supports interaction with the SVG file, such as selecting text.
-
In densely connected circuits it is sometimes hard to keep track of the
individual signal wires. For this cases it can be useful to call {\tt show}
with the {\tt -colors <integer>} argument, which randomly assigns colors to the
@@ -1056,6 +1048,10 @@ Clifford Wolf. The Yosys Open SYnthesis Suite.
Graphviz - Graph Visualization Software.
\url{http://www.graphviz.org/}
+\bibitem{xdot}
+xdot.py - an interactive viewer for graphs written in Graphviz's dot language.
+\url{https://github.com/jrfonseca/xdot.py}
+
\bibitem{CircuitSAT}
{\it Circuit satisfiability problem} on Wikipedia
\url{http://en.wikipedia.org/wiki/Circuit_satisfiability}
diff --git a/manual/CHAPTER_Approach.tex b/manual/CHAPTER_Approach.tex
index a2c40bea..69122580 100644
--- a/manual/CHAPTER_Approach.tex
+++ b/manual/CHAPTER_Approach.tex
@@ -8,7 +8,7 @@ approach followed in the effort to implement this tool.
\section{Data- and Control-Flow}
-The data- and control-flow of a typical synthesis-tool is very similar to the data- and control-flow of a typical
+The data- and control-flow of a typical synthesis tool is very similar to the data- and control-flow of a typical
compiler: different subsystems are called in a predetermined order, each consuming the data generated by the
last subsystem and generating the data for the next subsystem (see Fig.~\ref{fig:approach_flow}).
@@ -44,10 +44,10 @@ last subsystem and generating the data for the next subsystem (see Fig.~\ref{fig
\end{figure}
The first subsystem to be called is usually called a {\it frontend}. It does not process the data generated by
-another subsystem but instead reads the user input; in the case of a HDL synthesis tool the behavioural
+another subsystem but instead reads the user input---in the case of a HDL synthesis tool, the behavioural
HDL code.
-The subsystems that consume data from previous subsystems and produces data for the next subsystems (usually in the
+The subsystems that consume data from previous subsystems and produce data for the next subsystems (usually in the
same or a similar format) are called {\it passes}.
The last subsystem that is executed transforms the data generated by the last pass into a suitable output
@@ -61,7 +61,7 @@ script.
Yosys uses two different internal formats. The first is used to store an abstract syntax tree (AST) of a verilog
input file. This format is simply called {\it AST} and is generated by the Verilog Frontend. This data structure
-is then consumed by a subsystem called {\it AST Frontend}\footnote{In Yosys the term {\it pass} is only used to
+is consumed by a subsystem called {\it AST Frontend}\footnote{In Yosys the term {\it pass} is only used to
refer to commands that operate on the RTLIL data structure.}. This AST Frontend then generates a design in Yosys'
main internal format, the Register-Transfer-Level-Intermediate-Language (RTLIL) representation. It does that
by first performing a number of simplifications within the AST representation and then generating RTLIL from
@@ -71,10 +71,10 @@ The RTLIL representation is used by all passes as input and outputs. This has th
using different representational formats between different passes:
\begin{itemize}
-\item The passes can be re-arranged in a different order and passes can be removed or inserted.
+\item The passes can be rearranged in a different order and passes can be removed or inserted.
\item Passes can simply pass-thru the parts of the design they don't change without the need
to convert between formats. In fact Yosys passes output the same data structure they received
- as input and perform all changes in place.
+ as input and performs all changes in place.
\item All passes use the same interface, thus reducing the effort required to understand a pass
when reading the Yosys source code, e.g.~when adding additional features.
\end{itemize}
@@ -95,7 +95,7 @@ The use of RTLIL also has the disadvantage of having a very powerful format
between all passes, even when doing gate-level synthesis where the more
advanced features are not needed. In order to reduce complexity for passes that
operate on a low-level representation, these passes check the features used in
-the input RTLIL and fail to run when non-supported high-level constructs are
+the input RTLIL and fail to run when unsupported high-level constructs are
used. In such cases a pass that transforms the higher-level constructs to
lower-level constructs must be called from the synthesis script first.
diff --git a/manual/CHAPTER_Auxlibs.tex b/manual/CHAPTER_Auxlibs.tex
index 0726e031..8d3ed743 100644
--- a/manual/CHAPTER_Auxlibs.tex
+++ b/manual/CHAPTER_Auxlibs.tex
@@ -6,9 +6,9 @@ with Yosys.
\section{SHA1}
-The files in {\tt libs/sha1/} provide a SHA1 implementation written by Micael
-Hildenborg \citeweblink{smallsha1}. It is used for generating unique names when
-specializing parameterized modules.
+The files in {\tt libs/sha1/} provide a public domain SHA1 implementation written
+by Steve Reid, Bruce Guenter, and Volker Grabsch. It is used for generating
+unique names when specializing parameterized modules.
\section{BigInt}
diff --git a/manual/CHAPTER_Auxprogs.tex b/manual/CHAPTER_Auxprogs.tex
index eefd3697..cce3741c 100644
--- a/manual/CHAPTER_Auxprogs.tex
+++ b/manual/CHAPTER_Auxprogs.tex
@@ -17,10 +17,3 @@ The {\tt yosys-filterlib} tool is a small utility that can be used to strip
or extract information from a Liberty file. See Sec.~\ref{sec:techmap_extern}
for details.
-\section{yosys-svgviewer}
-
-The {\tt yosys-svgviewer} tool is a small Qt program that can be used to view
-SVG files. This tool is automatically launched by the {\tt show} command when
-no {\tt -format} and no {\tt -viewer} option is passed to the command. See
-{\tt help show} or Sec.~\ref{cmd:show} for details.
-
diff --git a/manual/CHAPTER_Basics.tex b/manual/CHAPTER_Basics.tex
index 9cc4720e..c0eda0e8 100644
--- a/manual/CHAPTER_Basics.tex
+++ b/manual/CHAPTER_Basics.tex
@@ -56,7 +56,7 @@ and how they relate to different kinds of synthesis.
Regardless of the way a lower level representation of a circuit is
obtained (synthesis or manual design), the lower level representation is usually
verified by comparing simulation results of the lower level and the higher level
-representation \footnote{In the last years formal equivalence
+representation \footnote{In recent years formal equivalence
checking also became an important verification method for validating RTL and
lower abstraction representation of the design.}.
Therefore even if no synthesis is used, there must still be a simulatable
@@ -71,7 +71,7 @@ be considered a ``High-Level Language'' today.
\subsection{System Level}
The System Level abstraction of a system only looks at its biggest building
-blocks like CPUs and computing cores. On this level the circuit is usually described
+blocks like CPUs and computing cores. At this level the circuit is usually described
using traditional programming languages like C/C++ or Matlab. Sometimes special
software libraries are used that are aimed at simulation circuits on the system
level, such as SystemC.
@@ -177,9 +177,9 @@ synthesis operations.
\subsection{Logical Gate Level}
-On the logical gate level the design is represented by a netlist that uses only
+At the logical gate level the design is represented by a netlist that uses only
cells from a small number of single-bit cells, such as basic logic gates (AND,
-OR, NOT, XOR, etc.) and Registers (usually D-Type Flip-flops).
+OR, NOT, XOR, etc.) and registers (usually D-Type Flip-flops).
A number of netlist formats exists that can be used on this level, e.g.~the Electronic Design
Interchange Format (EDIF), but for ease of simulation often a HDL netlist is used. The latter
@@ -191,8 +191,8 @@ within the gate level netlist and second the optimal (or at least good) mapping
gate netlist to an equivalent netlist of physically available gate types.
The simplest approach to logic synthesis is {\it two-level logic synthesis}, where a logic function
-is converted into a sum-of-products representation, e.g.~using a karnaugh map.
-This is a simple approach, but has exponential worst-case effort and can not make efficient use of
+is converted into a sum-of-products representation, e.g.~using a Karnaugh map.
+This is a simple approach, but has exponential worst-case effort and cannot make efficient use of
physical gates other than AND/NAND-, OR/NOR- and NOT-Gates.
Therefore modern logic synthesis tools utilize much more complicated {\it multi-level logic
@@ -287,7 +287,7 @@ applications to be used with a richer set of Verilog features.
\subsection{Behavioural Modelling}
Code that utilizes the Verilog {\tt always} statement is using {\it Behavioural
-Modelling}. In behavioural, modelling a circuit is described by means of imperative
+Modelling}. In behavioural modelling, a circuit is described by means of imperative
program code that is executed on certain events, namely any change, a rising
edge, or a falling edge of a signal. This is a very flexible construct during
simulation but is only synthesizable when one of the following is modelled:
@@ -457,7 +457,7 @@ Correctness is crucial. In some areas this is obvious (such as
correct synthesis of basic behavioural models). But it is also crucial for the
areas that concern minor details of the standard, such as the exact rules
for handling signed expressions, even when the HDL code does not target
-different synthesis tools. This is because (different to software source code that
+different synthesis tools. This is because (unlike software source code that
is only processed by compilers), in most design flows HDL code is not only
processed by the synthesis tool but also by one or more simulators and sometimes
even a formal verification tool. It is key for this verification process
@@ -467,9 +467,9 @@ that all these tools use the same interpretation for the HDL code.
Generally it is hard to give a one-dimensional description of how well a synthesis tool
optimizes the design. First of all because not all optimizations are applicable to all
-designs and all synthesis tasks. Some optimizations work (best) on a coarse grain level
-(with complex cells such as adders or multipliers) and others work (best) on a fine
-grain level (single bit gates). Some optimizations target area and others target speed.
+designs and all synthesis tasks. Some optimizations work (best) on a coarse-grained level
+(with complex cells such as adders or multipliers) and others work (best) on a fine-grained
+level (single bit gates). Some optimizations target area and others target speed.
Some work well on large designs while others don't scale well and can only be applied
to small designs.
@@ -610,7 +610,7 @@ The lexer is usually generated by a lexer generator (e.g.~{\tt flex} \citeweblin
description file that is using regular expressions to specify the text pattern that should match
the individual tokens.
-The lexer is also responsible for skipping ignored characters (such as white spaces outside string
+The lexer is also responsible for skipping ignored characters (such as whitespace outside string
constants and comments in the case of Verilog) and converting the original text snippet to a token
value.
@@ -714,11 +714,11 @@ be connected in two different ways: through {\it Single-Pass Pipelining} and by
Traditionally a parser and lexer are connected using the pipelined approach: The lexer provides a function that
is called by the parser. This function reads data from the input until a complete lexical token has been read. Then
this token is returned to the parser. So the lexer does not first generate a complete list of lexical tokens
-and then passes it to the parser. Instead they are running concurrently and the parser can consume tokens as
+and then pass it to the parser. Instead they run concurrently and the parser can consume tokens as
the lexer produces them.
-The single-pass pipelining approach has the advantage of lower memory footprint (at no time the complete design
-must be kept in memory) but has the disadvantage of tighter coupling between the interacting components.
+The single-pass pipelining approach has the advantage of lower memory footprint (at no time must the complete design
+be kept in memory) but has the disadvantage of tighter coupling between the interacting components.
Therefore single-pass pipelining should only be used when the lower memory footprint is required or the
components are also conceptually tightly coupled. The latter certainly is the case for a parser and its lexer.
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index e7895521..64d3633e 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -97,12 +97,6 @@ The width of the output port \B{Y}.
Table~\ref{tab:CellLib_binary} lists all cells for binary RTL operators.
-The additional cell type {\tt \$bu0} is similar to {\tt \$pos}, but always
-extends unsigned arguments with zeros. ({\tt \$pos} extends unsigned arguments
-with {\tt x}-bits if the most significant bit is {\tt x}.) This is used
-internally to correctly implement the {\tt ==} and {\tt !=} operators for
-constant arguments.
-
\subsection{Multiplexers}
Multiplexers are generated by the Verilog HDL frontend for {\tt
@@ -125,10 +119,6 @@ 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 \$safe\_pmux} behaves similarly to the {\tt \$pmux} cell type. But when more than one bit
-of \B{S} is set, it is guaranteed that this cell type will output the value of the \B{A} input instead of
-an undefined value.
-
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
@@ -256,8 +246,9 @@ If this parameter is set to {\tt 1'b1}, a read and write to the same address in
return the new value. Otherwise the old value is returned.
\end{itemize}
-The {\tt \$memwr} cells have a clock input \B{CLK}, an enable input \B{EN}, an address input \B{ADDR}
-and a data input \B{DATA}. They also have the following parameters:
+The {\tt \$memwr} cells have a clock input \B{CLK}, an enable input \B{EN} (one
+enable bit for each data bit), an address input \B{ADDR} and a data input
+\B{DATA}. They also have the following parameters:
\begin{itemize}
\item \B{MEMID} \\
@@ -341,7 +332,7 @@ This input is \B{RD\_PORTS}*\B{WIDTH} bits wide, containing all data signals for
This input is \B{WR\_PORTS} bits wide, containing all clock signals for the write ports.
\item \B{WR\_EN} \\
-This input is \B{WR\_PORTS} bits wide, containing all enable signals for the write ports.
+This input is \B{WR\_PORTS}*\B{WIDTH} bits wide, containing all enable signals for the write ports.
\item \B{WR\_ADDR} \\
This input is \B{WR\_PORTS}*\B{ABITS} bits wide, containing all address signals for the write ports.
@@ -374,7 +365,7 @@ source tree.
\begin{tabular}[t]{ll}
Verilog & Cell Type \\
\hline
-\lstinline[language=Verilog]; Y = ~A; & {\tt \$\_INV\_} \\
+\lstinline[language=Verilog]; Y = ~A; & {\tt \$\_NOT\_} \\
\lstinline[language=Verilog]; Y = A & B; & {\tt \$\_AND\_} \\
\lstinline[language=Verilog]; Y = A | B; & {\tt \$\_OR\_} \\
\lstinline[language=Verilog]; Y = A ^ B; & {\tt \$\_XOR\_} \\
@@ -401,7 +392,7 @@ $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 \$\_INV\_}, {\tt \$\_AND\_}, {\tt \$\_OR\_}, {\tt \$\_XOR\_} and {\tt \$\_MUX\_}
+{\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.
@@ -433,3 +424,11 @@ Add information about {\tt \$assert} cells.
Add information about {\tt \$slice} and {\tt \$concat} cells.
\end{fixme}
+\begin{fixme}
+Add information about {\tt \$alu}, {\tt \$macc}, {\tt \$fa}, and {\tt \$lcu} cells.
+\end{fixme}
+
+\begin{fixme}
+Add information about {\tt \$\_NAND\_}, {\tt \$\_NOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
+\end{fixme}
+
diff --git a/manual/CHAPTER_Intro.tex b/manual/CHAPTER_Intro.tex
index 675d2402..f735d46b 100644
--- a/manual/CHAPTER_Intro.tex
+++ b/manual/CHAPTER_Intro.tex
@@ -45,7 +45,7 @@ researched field. All the information required to write such tools has been open
available for a long time, and it is therefore likely that a FOSS HDL synthesis tool
with a feature-complete Verilog or VHDL front end must exist which can be used as a basis for a custom RTL synthesis tool.
-Due to the authors preference for Verilog over VHDL it has been decided early
+Due to the author's preference for Verilog over VHDL it was decided early
on to go for Verilog instead of VHDL\footnote{A quick investigation into FOSS
VHDL tools yielded similar grim results for FOSS VHDL synthesis tools.}.
So the existing FOSS Verilog synthesis tools were evaluated (see
@@ -56,12 +56,12 @@ is discussed in this document.
\section{Structure of this Document}
-The structure of this document is a follows:
+The structure of this document is as follows:
Chapter~\ref{chapter:intro} is this introduction.
Chapter~\ref{chapter:basics} covers a short introduction to the world of HDL
-synthesis. Basic principles and the terminology is outlined in this chapter.
+synthesis. Basic principles and the terminology are outlined in this chapter.
Chapter~\ref{chapter:approach} gives the quickest possible outline to how the
problem of implementing a HDL synthesis tool is approached in the case of
@@ -82,7 +82,7 @@ Yosys source code. The chapter concludes with an example loadable module
for Yosys.
Chapters~\ref{chapter:verilog}, \ref{chapter:opt}, and \ref{chapter:techmap}
-cover three improtant pieces of the synthesis pileline: The Verilog frontend,
+cover three important pieces of the synthesis pipeline: The Verilog frontend,
the optimization passes and the technology mapping to the target architecture,
respectively.
diff --git a/manual/CHAPTER_Optimize.tex b/manual/CHAPTER_Optimize.tex
index c562650b..af8e2249 100644
--- a/manual/CHAPTER_Optimize.tex
+++ b/manual/CHAPTER_Optimize.tex
@@ -136,7 +136,7 @@ This pass performs trivial resource sharing. This means that this pass identifie
with identical inputs and replaces them with a single instance of the cell.
The option {\tt -nomux} can be used to disable resource sharing for multiplexer
-cells ({\tt \$mux}, {\tt \$pmux}, and {\tt \$safe\_pmux}). This can be useful as
+cells ({\tt \$mux} and {\tt \$pmux}. This can be useful as
it prevents multiplexer trees to be merged, which might prevent {\tt opt\_muxtree}
to identify possible optimizations.
diff --git a/manual/CHAPTER_Overview.tex b/manual/CHAPTER_Overview.tex
index b9df57d1..ec402231 100644
--- a/manual/CHAPTER_Overview.tex
+++ b/manual/CHAPTER_Overview.tex
@@ -3,8 +3,8 @@
\label{chapter:overview}
Yosys is an extensible open source hardware synthesis tool. It is aimed at
-designers who are looking for an easy accessible, universal, and vendor
-independent synthesis tool, and scientists who do research in
+designers who are looking for an easily accessible, universal, and
+vendor-independent synthesis tool, as well as scientists who do research in
electronic design automation (EDA) and are looking for an open synthesis
framework that can be used to test algorithms on complex real-world designs.
@@ -49,7 +49,7 @@ of the backends, namely the Verilog Backend for generating Verilog netlists
and the ILANG Backend for writing the RTLIL data in the same format that is
understood by the ILANG Frontend.
-With the exception of the AST Frontend, that is called by the high-level HDL
+With the exception of the AST Frontend, which is called by the high-level HDL
frontends and can't be called directly by the user, all program modules are
called by the user (usually using a synthesis script that contains text
commands for Yosys).
@@ -57,7 +57,7 @@ commands for Yosys).
By combining passes in different ways and/or adding additional passes to Yosys
it is possible to adapt Yosys to a wide range of applications. For this to be
possible it is key that (1) all passes operate on the same data structure
-(RTLIL) and (2) that this data structure is powerful enough represent the design
+(RTLIL) and (2) that this data structure is powerful enough to represent the design
in different stages of the synthesis.
\begin{figure}[t]
@@ -97,7 +97,7 @@ refers to the fact, that RTLIL also has a text representation, usually referred
The only exception are the high-level frontends that use the AST representation as an intermediate step before generating RTLIL
data.
-In order to avoid re-inventing names for the RTLIL classes, they are simply referred to by their full C++ name, i.e.~including
+In order to avoid reinventing names for the RTLIL classes, they are simply referred to by their full C++ name, i.e.~including
the {\tt RTLIL::} namespace prefix, in this document.
Figure~\ref{fig:Overview_RTLIL} shows a simplified Entity-Relationship Diagram (ER Diagram) of RTLIL. In $1:N$ relationships the arrow
@@ -105,7 +105,7 @@ points from the $N$ side to the $1$. For example one RTLIL::Design contains $N$
A two-pointed arrow indicates a $1:1$ relationship.
The RTLIL::Design is the root object of the RTLIL data structure. There is always one ``current design'' in memory
-on which passes operate, frontends add data to it and backends convert to exportable formats. But in some cases passes
+which passes operate on, frontends add data to and backends convert to exportable formats. But in some cases passes
internally generate additional RTLIL::Design objects. For example when a pass is reading an auxiliary Verilog file such
as a cell library, it might create an additional RTLIL::Design object and call the Verilog frontend with this
other object to parse the cell library.
@@ -154,12 +154,12 @@ transformed to an RTLIL-compatible representation by the HDL frontend. This incl
Verilog-features such as generate-blocks, loops and parameters.
The following sections contain a more detailed description of the different
-parts of RTLIL and rationales behind some of the design decisions.
+parts of RTLIL and rationale behind some of the design decisions.
\subsection{RTLIL Identifiers}
All identifiers in RTLIL (such as module names, port names, signal names, cell
-types, etc.) follow the following naming convention: They must either start with
+types, etc.) follow the following naming convention: they must either start with
a backslash (\textbackslash) or a dollar sign (\$).
Identifiers starting with a backslash are public visible identifiers. Usually
@@ -172,13 +172,13 @@ identifiers that start with a backslash.
This has three advantages:
\begin{itemize}
-\item Firstly it is impossible that an auto-generated identifier collides with
+\item First, it is impossible that an auto-generated identifier collides with
an identifier that was provided by the user.
-\item Secondly the information about which identifiers were originally
+\item Second, the information about which identifiers were originally
provided by the user is always available which can help guide some optimizations. For example the ``opt\_rmunused''
-is trying to preserve signals with a user-provided name but doesn't hesitate to delete signals that have
+tries to preserve signals with a user-provided name but doesn't hesitate to delete signals that have
auto-generated names when they just duplicate other signals.
-\item Thirdly the delicate job of finding suitable auto-generated public visible
+\item Third, the delicate job of finding suitable auto-generated public visible
names is deferred to one central location. Internally auto-generated names that
may hold important information for Yosys developers can be used without
disturbing external tools. For example the Verilog backend assigns names in the form {\tt \_{\it integer}\_}.
@@ -216,7 +216,7 @@ Verilog and VHDL both support parametric modules (known as ``generic entities''
format does not support parametric modules itself. Instead each module contains a callback function
into the AST frontend to generate a parametrized variation of the RTLIL::Module as needed. This
callback then returns the auto-generated name of the parametrized variation of the module. (A hash
-over the parameters and the module name is used to prohibit the same parametrized variation to be
+over the parameters and the module name is used to prohibit the same parametrized variation from being
generated twice. For modules with only a few parameters, a name directly containing all parameters
is generated instead of a hash string.)
@@ -233,7 +233,7 @@ An RTLIL::Wire object has the following properties:
\begin{itemize}
\item The wire name
\item A list of attributes
-\item A width (busses are just wires with a width > 1)
+\item A width (buses are just wires with a width > 1)
\item If the wire is a port: port number and direction (input/output/inout)
\end{itemize}
@@ -256,7 +256,7 @@ An RTLIL::Cell object has the following properties:
\end{itemize}
The connections of ports to wires are coded by assigning an RTLIL::SigSpec
-to each cell ports. The RTLIL::SigSpec data type is described in the next section.
+to each cell port. The RTLIL::SigSpec data type is described in the next section.
\subsection{RTLIL::SigSpec}
@@ -382,7 +382,7 @@ end
This pass has transformed the outer RTLIL::SwitchRule into a modified RTLIL::SyncRule object
for the {\tt \textbackslash{}reset} signal. Further processing converts the RTLIL::Process
-e.g.~into a d-type flip-flop with asynchronous reset and a multiplexer for the enable signal:
+into e.g.~a d-type flip-flop with asynchronous reset and a multiplexer for the enable signal:
\begin{lstlisting}[numbers=left,frame=single,language=rtlil]
cell $adff $procdff$6
@@ -442,31 +442,31 @@ The {\tt memory} pass performs this conversion and can (depending on the options
to it) transform the memories directly to d-type flip-flops and address logic or yield
multiport memory blocks (represented using {\tt \$mem} cells).
-See Sec.~\ref{sec:memcells} for details on the memory cell types.
+See Sec.~\ref{sec:memcells} for details about the memory cell types.
\section{Command Interface and Synthesis Scripts}
Yosys reads and processes commands from synthesis scripts, command line arguments and
an interactive command prompt. Yosys commands consist of a command name and an optional
-whitespace sparated list of arguments. Commands are terminated using the newline character
+whitespace separated list of arguments. Commands are terminated using the newline character
or a semicolon ({\tt ;}). Empty lines and lines starting with the hash sign ({\tt \#}) are ignored.
See Sec.~\ref{sec:typusecase} for an example synthesis script.
The command {\tt help} can be used to access the command reference manual.
-Most commands can operate not only on the entire design but also only on {\it selected}
+Most commands can operate not only on the entire design but also specifically on {\it selected}
parts of the design. For example the command {\tt dump} will print all selected objects
in the current design while {\tt dump foobar} will only print the module {\tt foobar}
and {\tt dump *} will print the entire design regardless of the current selection.
The selection mechanism is very powerful. For example the command {\tt dump */t:\$add
\%x:+[A] */w:* \%i} will print all wires that are connected to the \B{A} port of
-a {\tt \$add} cell. A detailed documentation of the select framework can be
+a {\tt \$add} cell. Detailed documentation of the select framework can be
found in the command reference for the {\tt select} command.
\section{Source Tree and Build System}
-The Yosys source tree is organized in the following top-level directories:
+The Yosys source tree is organized into the following top-level directories:
\begin{itemize}
@@ -512,15 +512,15 @@ and a {\tt Makefile.inc}. The Yosys kernel automatically detects all commands li
Yosys. So it is not needed to add additional commands to a central list of commands.
\end{sloppypar}
-A good starting point for reading example source code for learning how to write passes
+Good starting points for reading example source code to learn how to write passes
are {\tt passes/opt/opt\_rmdff.cc} and {\tt passes/opt/opt\_share.cc}.
See the top-level README file for a quick {\it Getting Started} guide and build
-instructions. Yosys is a pure Makefile based project.
+instructions. The Yosys build is based solely on Makefiles.
Users of the Qt Creator IDE can generate a QT Creator project file using {\tt
make qtcreator}. Users of the Eclipse IDE can use the ``Makefile Project with
Existing Code'' project type in the Eclipse ``New Project'' dialog (only
-available after the CDT plugin has been installed) to create an Eclipse Project
-for programming extensions to Yosys or just browsing the Yosys code base.
+available after the CDT plugin has been installed) to create an Eclipse project
+in order to programming extensions to Yosys or just browse the Yosys code base.
diff --git a/manual/CHAPTER_Prog/stubnets.cc b/manual/CHAPTER_Prog/stubnets.cc
index 1c71f78b..ef4b1245 100644
--- a/manual/CHAPTER_Prog/stubnets.cc
+++ b/manual/CHAPTER_Prog/stubnets.cc
@@ -21,7 +21,7 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
SigMap sigmap(module);
// count how many times a single-bit signal is used
- std::map<RTLIL::SigSpec, int> bit_usage_count;
+ std::map<RTLIL::SigBit, int> bit_usage_count;
// count ouput lines for this module (needed only for summary output at the end)
int line_count = 0;
@@ -29,24 +29,21 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
log("Looking for stub wires in module %s:\n", RTLIL::id2cstr(module->name));
// For all ports on all cells
- for (auto &cell_iter : module->cells)
- for (auto &conn : cell_iter.second->connections)
+ for (auto &cell_iter : module->cells_)
+ for (auto &conn : cell_iter.second->connections())
{
// Get the signals on the port
// (use sigmap to get a uniqe signal name)
RTLIL::SigSpec sig = sigmap(conn.second);
- // split the signal up into single-bit chunks
- sig.expand();
-
- // add each chunk to bit_usage_count, unless it is a constant
- for (auto &c : sig.chunks)
- if (c.wire != NULL)
- bit_usage_count[c]++;
+ // add each bit to bit_usage_count, unless it is a constant
+ for (auto &bit : sig)
+ if (bit.wire != NULL)
+ bit_usage_count[bit]++;
}
// for each wire in the module
- for (auto &wire_iter : module->wires)
+ for (auto &wire_iter : module->wires_)
{
RTLIL::Wire *wire = wire_iter.second;
@@ -60,15 +57,13 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
// we will record which bits of the (possibly multi-bit) wire are stub signals
std::set<int> stub_bits;
- // get a signal description for this wire and split it into seperate bits
+ // get a signal description for this wire and split it into separate bits
RTLIL::SigSpec sig = sigmap(wire);
- sig.expand();
// for each bit (unless it is a constant):
// check if it is used at least two times and add to stub_bits otherwise
- for (size_t i = 0; i < sig.chunks.size(); i++)
- if (sig.chunks[i].wire != NULL && (bit_usage_count[sig.chunks[i]] +
- usage_offset) < 2)
+ for (int i = 0; i < SIZE(sig); i++)
+ if (sig[i].wire != NULL && (bit_usage_count[sig[i]] + usage_offset) < 2)
stub_bits.insert(i);
// continue if no stub bits found
@@ -77,7 +72,7 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
// report stub bits and/or stub wires, don't report single bits
// if called with report_bits set to false.
- if (int(stub_bits.size()) == sig.width) {
+ if (SIZE(stub_bits) == SIZE(sig)) {
log(" found stub wire: %s\n", RTLIL::id2cstr(wire->name));
} else {
if (!report_bits)
@@ -125,7 +120,7 @@ struct StubnetsPass : public Pass {
// call find_stub_nets() for each module that is either
// selected as a whole or contains selected objects.
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
if (design->selected_module(it.first))
find_stub_nets(design, it.second, report_bits);
}
diff --git a/manual/CHAPTER_StateOfTheArt/simlib_yosys.v b/manual/CHAPTER_StateOfTheArt/simlib_yosys.v
index a2df8f64..54c07661 100644
--- a/manual/CHAPTER_StateOfTheArt/simlib_yosys.v
+++ b/manual/CHAPTER_StateOfTheArt/simlib_yosys.v
@@ -20,12 +20,12 @@
* The internal logic cell simulation library.
*
* This verilog library contains simple simulation models for the internal
- * logic cells (_INV_, _AND_, ...) that are generated by the default technology
+ * logic cells (_NOT_, _AND_, ...) that are generated by the default technology
* mapper (see "stdcells.v" in this directory) and expected by the "abc" pass.
*
*/
-module _INV_(A, Y);
+module _NOT_(A, Y);
input A;
output Y;
assign Y = ~A;
diff --git a/manual/CHAPTER_Techmap.tex b/manual/CHAPTER_Techmap.tex
index be74c356..e5c7456c 100644
--- a/manual/CHAPTER_Techmap.tex
+++ b/manual/CHAPTER_Techmap.tex
@@ -27,12 +27,12 @@ cells with the provided implementation.
When no map file is provided, {\tt techmap} uses a built-in map file that
maps the Yosys RTL cell types to the internal gate library used by Yosys.
-The curious reader may find this map file as {\tt techlibs/common/stdcells.v} in
+The curious reader may find this map file as {\tt techlibs/common/techmap.v} in
the Yosys source tree.
Additional features have been added to {\tt techmap} to allow for conditional
mapping of cells (see {\tt help techmap} or Sec.~\ref{cmd:techmap}). This can
-for example be usefull if the target architecture supports hardware multipliers for
+for example be useful if the target architecture supports hardware multipliers for
certain bit-widths but not for others.
A usual synthesis flow would first use the {\tt techmap} pass to directly map
diff --git a/manual/CHAPTER_Verilog.tex b/manual/CHAPTER_Verilog.tex
index 96074774..485b4f35 100644
--- a/manual/CHAPTER_Verilog.tex
+++ b/manual/CHAPTER_Verilog.tex
@@ -444,7 +444,7 @@ on the AST data structure:
\begin{itemize}
\item Inline all task and function calls.
\item Evaluate all \lstinline[language=Verilog]{generate}-statements and unroll all \lstinline[language=Verilog]{for}-loops.
-\item Perform const folding where it is neccessary (e.g.~in the value part of {\tt AST\_PARAMETER}, {\tt AST\_LOCALPARAM},
+\item Perform const folding where it is necessary (e.g.~in the value part of {\tt AST\_PARAMETER}, {\tt AST\_LOCALPARAM},
{\tt AST\_PARASET} and {\tt AST\_RANGE} nodes).
\item Replace {\tt AST\_PRIMITIVE} nodes with appropriate {\tt AST\_ASSIGN} nodes.
\item Replace dynamic bit ranges in the left-hand-side of assignments with {\tt AST\_CASE} nodes with {\tt AST\_COND} children
@@ -819,7 +819,7 @@ the \C{RTLIL::SyncRule}s that describe the output registers.
%
\item {\tt proc\_dff} \\
This pass replaces the \C{RTLIL::SyncRule}s to d-type flip-flops (with
-asynchronous resets if neccessary).
+asynchronous resets if necessary).
%
\item {\tt proc\_clean} \\
A final call to {\tt proc\_clean} removes the now empty \C{RTLIL::Process} objects.
@@ -827,7 +827,7 @@ A final call to {\tt proc\_clean} removes the now empty \C{RTLIL::Process} objec
Performing these last processing steps in passes instead of in the Verilog frontend has two important benefits:
-First it improves the transparency of the process. Everything that happens in a seperate pass is easier to debug,
+First it improves the transparency of the process. Everything that happens in a separate pass is easier to debug,
as the RTLIL data structures can be easily investigated before and after each of the steps.
Second it improves flexibility. This scheme can easily be extended to support other types of storage-elements, such
diff --git a/manual/PRESENTATION_ExAdv.tex b/manual/PRESENTATION_ExAdv.tex
index 21c5cdec..471516b4 100644
--- a/manual/PRESENTATION_ExAdv.tex
+++ b/manual/PRESENTATION_ExAdv.tex
@@ -87,21 +87,21 @@ cd .. # switch back to design
\end{lstlisting}
\bigskip
-Note: Most synthesis script never switch to module context. But it is a very powerful
+Note: Most synthesis scripts never switch to module context. But it is a very powerful
tool for interactive design investigation.
\end{frame}
\subsubsection{Selecting by object property or type}
\begin{frame}[fragile]{\subsubsecname}
-Special pattern can be used to select by object property or type. For example:
+Special patterns can be used to select by object property or type. For example:
\bigskip
\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
select w:reg_* # select all wires whose names start with reg_
select a:foobar # select all objects with the attribute foobar set
select a:foobar=42 # select all objects with the attribute foobar set to 42
-select A:blabla # select all module with the attribute blabla set
+select A:blabla # select all modules with the attribute blabla set
select foo/t:$add # select all $add cells from the module foo
\end{lstlisting}
@@ -113,8 +113,8 @@ reference to the {\tt select} command.
\subsubsection{Combining selection}
\begin{frame}[fragile]{\subsubsecname}
-When more than one selection expression is used in one statement they are
-pushed on a stack. At the final elements on the stack are combined into a union:
+When more than one selection expression is used in one statement, then they are
+pushed on a stack. The final elements on the stack are combined into a union:
\medskip
\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
@@ -169,8 +169,8 @@ See {\tt help select} for full documentation of this expressions.
\subsubsection{Incremental selection}
\begin{frame}[fragile]{\subsubsecname}
-Sometime a selection can most easily described by a series of add/delete operations.
-For the commands {\tt select -add} and {\tt select -del} add or remove objects
+Sometimes a selection can most easily be described by a series of add/delete operations.
+The commands {\tt select -add} and {\tt select -del} respectively add or remove objects
from the current selection instead of overwriting it.
\medskip
@@ -223,11 +223,11 @@ show -color red @cone_ab -color magenta @cone_a -color blue @cone_b
\begin{frame}[fragile]{\subsubsecname{} -- Example}
\begin{columns}
\column[t]{4cm}
-\lstinputlisting[basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/select_01.v}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/select.v}
\column[t]{7cm}
-\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExAdv/select_01.ys}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExAdv/select.ys}
\end{columns}
-\hfil\includegraphics[width=\linewidth,trim=0 0cm 0 0cm]{PRESENTATION_ExAdv/select_01.pdf}
+\hfil\includegraphics[width=\linewidth,trim=0 0cm 0 0cm]{PRESENTATION_ExAdv/select.pdf}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -239,10 +239,233 @@ show -color red @cone_ab -color magenta @cone_a -color blue @cone_b
\subsectionpagesuffix
\end{frame}
-\subsubsection{TBD}
+\subsubsection{Introduction to techmap}
\begin{frame}{\subsubsecname}
-TBD
+\begin{itemize}
+\item
+The {\tt techmap} command replaces cells in the design with implementations given
+as verilog code (called ``map files''). It can replace Yosys' internal cell
+types (such as {\tt \$or}) as well as user-defined cell types.
+\medskip\item
+Verilog parameters are used extensively to customize the internal cell types.
+\medskip\item
+Additional special parameters are used by techmap to communicate meta-data to the
+map files.
+\medskip\item
+Special wires are used to instruct techmap how to handle a module in the map file.
+\medskip\item
+Generate blocks and recursion are powerful tools for writing map files.
+\end{itemize}
+\end{frame}
+
+\begin{frame}[t]{\subsubsecname{} -- Example 1/2}
+\vskip-0.2cm
+To map the Verilog OR-reduction operator to 3-input OR gates:
+\vskip-0.2cm
+\begin{columns}
+\column[t]{0.35\linewidth}
+\lstinputlisting[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, lastline=24]{PRESENTATION_ExAdv/red_or3x1_map.v}
+\column[t]{0.65\linewidth}
+\lstinputlisting[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=25]{PRESENTATION_ExAdv/red_or3x1_map.v}
+\end{columns}
+\end{frame}
+
+\begin{frame}[t]{\subsubsecname{} -- Example 2/2}
+\vbox to 0cm{
+\hfil\includegraphics[width=10cm,trim=0 0cm 0 0cm]{PRESENTATION_ExAdv/red_or3x1.pdf}
+\vss
+}
+\begin{columns}
+\column[t]{6cm}
+\column[t]{4cm}
+\vskip-0.6cm\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, firstline=4, lastline=4, frame=single]{PRESENTATION_ExAdv/red_or3x1_test.ys}
+\vskip-0.2cm\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/red_or3x1_test.v}
+\end{columns}
+\end{frame}
+
+\subsubsection{Conditional techmap}
+
+\begin{frame}{\subsubsecname}
+\begin{itemize}
+\item In some cases only cells with certain properties should be substituted.
+\medskip
+\item The special wire {\tt \_TECHMAP\_FAIL\_} can be used to disable a module
+in the map file for a certain set of parameters.
+\medskip
+\item The wire {\tt \_TECHMAP\_FAIL\_} must be set to a constant value. If it
+is non-zero then the module is disabled for this set of parameters.
+\medskip
+\item Example use-cases:
+\begin{itemize}
+\item coarse-grain cell types that only operate on certain bit widths
+\item memory resources for different memory geometries (width, depth, ports, etc.)
+\end{itemize}
+\end{itemize}
+\end{frame}
+
+\begin{frame}[t]{\subsubsecname{} -- Example}
+\vbox to 0cm{
+\vskip-0.5cm
+\hfill\includegraphics[width=6cm,trim=0 0cm 0 0cm]{PRESENTATION_ExAdv/sym_mul.pdf}
+\vss
+}
+\vskip-0.5cm
+\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/sym_mul_map.v}
+\begin{columns}
+\column[t]{6cm}
+\vskip-0.5cm\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=verilog]{PRESENTATION_ExAdv/sym_mul_test.v}
+\column[t]{4cm}
+\vskip-0.5cm\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=ys, lastline=4]{PRESENTATION_ExAdv/sym_mul_test.ys}
+\end{columns}
+\end{frame}
+
+\subsubsection{Scripting in map modules}
+
+\begin{frame}{\subsubsecname}
+\begin{itemize}
+\item The special wires {\tt \_TECHMAP\_DO\_*} can be used to run Yosys scripts
+in the context of the replacement module.
+\medskip
+\item The wire that comes first in alphabetical oder is interpreted as string (must
+be connected to constants) that is executed as script. Then the wire is removed. Repeat.
+\medskip
+\item You can even call techmap recursively!
+\medskip
+\item Example use-cases:
+\begin{itemize}
+\item Using always blocks in map module: call {\tt proc}
+\item Perform expensive optimizations (such as {\tt freduce}) on cells where
+this is known to work well.
+\item Interacting with custom commands.
+\end{itemize}
+\end{itemize}
+
+\scriptsize
+PROTIP: Commands such as {\tt shell}, {\tt show -pause}, and {\tt dump} can be use
+in the {\tt \_TECHMAP\_DO\_*} scripts for debugging map modules.
+\end{frame}
+
+\begin{frame}[t]{\subsubsecname{} -- Example}
+\vbox to 0cm{
+\vskip4.2cm
+\hskip0.5cm\includegraphics[width=10cm,trim=0 0cm 0 0cm]{PRESENTATION_ExAdv/mymul.pdf}
+\vss
+}
+\vskip-0.6cm
+\begin{columns}
+\column[t]{6cm}
+\vskip-0.6cm
+\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/mymul_map.v}
+\column[t]{4.2cm}
+\vskip-0.6cm
+\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=verilog]{PRESENTATION_ExAdv/mymul_test.v}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=ys, lastline=5]{PRESENTATION_ExAdv/mymul_test.ys}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, frame=single, language=ys, firstline=7, lastline=12]{PRESENTATION_ExAdv/mymul_test.ys}
+\end{columns}
+\end{frame}
+
+\subsubsection{Handling constant inputs}
+
+\begin{frame}{\subsubsecname}
+\begin{itemize}
+\item The special parameters {\tt \_TECHMAP\_CONSTMSK\_\it <port-name>\tt \_} and
+{\tt \_TECHMAP\_CONSTVAL\_\it <port-name>\tt \_} can be used to handle constant
+input values to cells.
+\medskip
+\item The former contains 1-bits for all constant input bits on the port.
+\medskip
+\item The latter contains the constant bits or undef (x) for non-constant bits.
+\medskip
+\item Example use-cases:
+\begin{itemize}
+\item Converting arithmetic (for example multiply to shift)
+\item Identify constant addresses or enable bits in memory interfaces.
+\end{itemize}
+\end{itemize}
+\end{frame}
+
+\begin{frame}[t]{\subsubsecname{} -- Example}
+\vbox to 0cm{
+\vskip5.2cm
+\hskip6.5cm\includegraphics[width=5cm,trim=0 0cm 0 0cm]{PRESENTATION_ExAdv/mulshift.pdf}
+\vss
+}
+\vskip-0.6cm
+\begin{columns}
+\column[t]{6cm}
+\vskip-0.4cm
+\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/mulshift_map.v}
+\column[t]{4.2cm}
+\vskip-0.6cm
+\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=verilog]{PRESENTATION_ExAdv/mulshift_test.v}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=ys, lastline=5]{PRESENTATION_ExAdv/mulshift_test.ys}
+\end{columns}
+\end{frame}
+
+\subsubsection{Handling shorted inputs}
+
+\begin{frame}{\subsubsecname}
+\begin{itemize}
+\item The special parameters {\tt \_TECHMAP\_BITS\_CONNMAP\_} and
+{\tt \_TECHMAP\_CONNMAP\_\it <port-name>\tt \_} can be used to handle shorted inputs.
+\medskip
+\item Each bit of the port correlates to an {\tt \_TECHMAP\_BITS\_CONNMAP\_} bits wide
+number in {\tt \_TECHMAP\_CONNMAP\_\it <port-name>\tt \_}.
+\medskip
+\item Each unique signal bit is assigned its own number. Identical fields in the {\tt
+\_TECHMAP\_CONNMAP\_\it <port-name>\tt \_} parameters mean shorted signal bits.
+\medskip
+\item The numbers 0-3 are reserved for {\tt 0}, {\tt 1}, {\tt x}, and {\tt z} respectively.
+\medskip
+\item Example use-cases:
+\begin{itemize}
+\item Detecting shared clock or control signals in memory interfaces.
+\item In some cases this can be used for for optimization.
+\end{itemize}
+\end{itemize}
+\end{frame}
+
+\begin{frame}[t]{\subsubsecname{} -- Example}
+\vbox to 0cm{
+\vskip4.5cm
+\hskip6.5cm\includegraphics[width=5cm,trim=0 0cm 0 0cm]{PRESENTATION_ExAdv/addshift.pdf}
+\vss
+}
+\vskip-0.6cm
+\begin{columns}
+\column[t]{6cm}
+\vskip-0.4cm
+\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/addshift_map.v}
+\column[t]{4.2cm}
+\vskip-0.6cm
+\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=verilog]{PRESENTATION_ExAdv/addshift_test.v}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=ys, lastline=5]{PRESENTATION_ExAdv/addshift_test.ys}
+\end{columns}
+\end{frame}
+
+\subsubsection{Notes on using techmap}
+
+\begin{frame}{\subsubsecname}
+\begin{itemize}
+\item Don't use positional cell parameters in map modules.
+\medskip
+\item Don't try to implement basic logic optimization with techmap. \\
+{\small (So the OR-reduce using OR3X1 cells map was actually a bad example.)}
+\medskip
+\item You can use the {\tt \$\_\,\_}-prefix for internal cell types to avoid
+collisions with the user-namespace. But always use two underscores or the
+internal consistency checker will trigger on this cells.
+\medskip
+\item Techmap has two major use cases:
+\begin{itemize}
+\item Creating good logic-level representation of arithmetic functions. \\
+This also means using dedicated hardware resources such as half- and full-adder
+cells in ASICS or dedicated carry logic in FPGAs.
+\smallskip
+\item Mapping of coarse-grain resources such as block memory or DSP cells.
+\end{itemize}
+\end{itemize}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -254,12 +477,328 @@ TBD
\subsectionpagesuffix
\end{frame}
-\subsubsection{TBD}
+\subsubsection{Intro to coarse-grain synthesis}
+
+\begin{frame}[fragile]{\subsubsecname}
+In coarse-grain synthesis the target architecure has cells of the same
+complexity or larger complexity than the internal RTL representation.
+
+For example:
+\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]
+ wire [15:0] a, b;
+ wire [31:0] c, y;
+ assign y = a * b + c;
+\end{lstlisting}
+
+This circuit contains two cells in the RTL representation: one multiplier and
+one adder. In some architectures this circuit can be implemented using
+a single circuit element, for example an FPGA DSP core. Coarse grain synthesis
+is this mapping of groups of circuit elements to larger components.
+
+\bigskip
+Fine-grain synthesis would be matching the circuit elements to smaller
+components, such as LUTs, gates, or half- and full-adders.
+\end{frame}
+
+\subsubsection{The extract pass}
+
+\begin{frame}{\subsubsecname}
+\begin{itemize}
+\item Like the {\tt techmap} pass, the {\tt extract} pass is called with
+a map file. It compares the circuits inside the modules of the map file
+with the design and looks for sub-circuits in the design that match any
+of the modules in the map file.
+\bigskip
+\item If a match is found, the {\tt extract} pass will replace the matching
+subcircuit with an instance of the module from the map file.
+\bigskip
+\item In a way the {\tt extract} pass is the inverse of the techmap pass.
+\end{itemize}
+\end{frame}
+
+\begin{frame}[t, fragile]{\subsubsecname{} -- Example 1/2}
+\vbox to 0cm{
+\vskip2cm
+\begin{tikzpicture}
+ \node at (0,0) {\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_simple_test_00a.pdf}};
+ \node at (3,-3) {\includegraphics[width=8cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_simple_test_00b.pdf}};
+ \draw[yshift=0.2cm,thick,-latex] (1,-1) -- (2,-2);
+\end{tikzpicture}
+\vss}
+\vskip-1.2cm
+\begin{columns}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/macc_simple_test.v}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=verilog]{PRESENTATION_ExAdv/macc_simple_xmap.v}
+\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=ys]
+read_verilog macc_simple_test.v
+hierarchy -check -top test
+
+extract -map macc_simple_xmap.v;;
+\end{lstlisting}
+\end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{\subsubsecname{} -- Example 2/2}
+\hfil\begin{tabular}{cc}
+\fbox{\hbox to 5cm {\lstinputlisting[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/macc_simple_test_01.v}}} &
+\fbox{\hbox to 5cm {\lstinputlisting[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/macc_simple_test_02.v}}} \\
+$\downarrow$ & $\downarrow$ \\
+\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_simple_test_01a.pdf}} &
+\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_simple_test_02a.pdf}} \\
+$\downarrow$ & $\downarrow$ \\
+\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_simple_test_01b.pdf}} &
+\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_simple_test_02b.pdf}} \\
+\end{tabular}
+\end{frame}
+
+\subsubsection{The wrap-extract-unwrap method}
\begin{frame}{\subsubsecname}
-TBD
+\scriptsize
+Often a coarse-grain element has a constant bit-width, but can be used to
+implement oprations with a smaller bit-width. For example, a 18x25-bit multiplier
+can also be used to implement 16x20-bit multiplication.
+
+\bigskip
+A way of mapping such elements in coarse grain synthesis is the wrap-extract-unwrap method:
+
+\begin{itemize}
+\item {\bf wrap} \\
+Identify candidate-cells in the circuit and wrap them in a cell with a constant
+wider bit-width using {\tt techmap}. The wrappers use the same parameters as the original cell, so
+the information about the original width of the ports is preserved. \\
+Then use the {\tt connwrappers} command to connect up the bit-extended in- and
+outputs of the wrapper cells.
+\item {\bf extract} \\
+Now all operations are encoded using the same bit-width as the coarse grain element. The {\tt
+extract} command can be used to replace circuits with cells of the target architecture.
+\item {\bf unwrap} \\
+The remaining wrapper cell can be unwrapped using {\tt techmap}.
+\end{itemize}
+
+\bigskip
+The following sides detail an example that shows how to map MACC operations of
+arbitrary size to MACC cells with a 18x25-bit multiplier and a 48-bit adder (such as
+the Xilinx DSP48 cells).
+\end{frame}
+
+\subsubsection{Example: DSP48\_MACC}
+
+\begin{frame}[t, fragile]{\subsubsecname{} -- 1/13}
+Preconditioning: {\tt macc\_xilinx\_swap\_map.v} \\
+Make sure {\tt A} is the smaller port on all multipliers
+
+\begin{columns}
+\column{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, lastline=15]{PRESENTATION_ExAdv/macc_xilinx_swap_map.v}
+\column{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=16]{PRESENTATION_ExAdv/macc_xilinx_swap_map.v}
+\end{columns}
+\end{frame}
+
+\begin{frame}[t, fragile]{\subsubsecname{} -- 2/13}
+Wrapping multipliers: {\tt macc\_xilinx\_wrap\_map.v}
+
+\begin{columns}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, lastline=23]{PRESENTATION_ExAdv/macc_xilinx_wrap_map.v}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=24, lastline=46]{PRESENTATION_ExAdv/macc_xilinx_wrap_map.v}
+\end{columns}
+\end{frame}
+
+\begin{frame}[t, fragile]{\subsubsecname{} -- 3/13}
+Wrapping adders: {\tt macc\_xilinx\_wrap\_map.v}
+
+\begin{columns}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=48, lastline=67]{PRESENTATION_ExAdv/macc_xilinx_wrap_map.v}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=68, lastline=89]{PRESENTATION_ExAdv/macc_xilinx_wrap_map.v}
+\end{columns}
+\end{frame}
+
+\begin{frame}[t, fragile]{\subsubsecname{} -- 4/13}
+Extract: {\tt macc\_xilinx\_xmap.v}
+
+\lstinputlisting[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=1, lastline=17]{PRESENTATION_ExAdv/macc_xilinx_xmap.v}
+
+.. simply use the same wrapping commands on this module as on the design to create a template for the {\tt extract} command.
+\end{frame}
+
+\begin{frame}[t, fragile]{\subsubsecname{} -- 5/13}
+Unwrapping multipliers: {\tt macc\_xilinx\_unwrap\_map.v}
+
+\begin{columns}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=1, lastline=17]{PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=18, lastline=30]{PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v}
+\end{columns}
+\end{frame}
+
+\begin{frame}[t, fragile]{\subsubsecname{} -- 6/13}
+Unwrapping adders: {\tt macc\_xilinx\_unwrap\_map.v}
+
+\begin{columns}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=32, lastline=48]{PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=49, lastline=61]{PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v}
+\end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{\subsubsecname{} -- 7/13}
+\hfil\begin{tabular}{cc}
+{\tt test1} & {\tt test2} \\
+\fbox{\hbox to 5cm {\lstinputlisting[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, firstline=1, lastline=6, language=verilog]{PRESENTATION_ExAdv/macc_xilinx_test.v}}} &
+\fbox{\hbox to 5cm {\lstinputlisting[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, firstline=8, lastline=13, language=verilog]{PRESENTATION_ExAdv/macc_xilinx_test.v}}} \\
+$\downarrow$ & $\downarrow$ \\
+\end{tabular}
+\vskip-0.5cm
+\begin{lstlisting}[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
+ read_verilog macc_xilinx_test.v
+ hierarchy -check
+\end{lstlisting}
+\vskip-0.5cm
+\hfil\begin{tabular}{cc}
+$\downarrow$ & $\downarrow$ \\
+\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1a.pdf}} &
+\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2a.pdf}} \\
+\end{tabular}
+\end{frame}
+
+\begin{frame}[fragile]{\subsubsecname{} -- 8/13}
+\hfil\begin{tabular}{cc}
+{\tt test1} & {\tt test2} \\
+\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1a.pdf}} &
+\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2a.pdf}} \\
+$\downarrow$ & $\downarrow$ \\
+\end{tabular}
+\vskip-0.2cm
+\begin{lstlisting}[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
+ techmap -map macc_xilinx_swap_map.v ;;
+\end{lstlisting}
+\vskip-0.2cm
+\hfil\begin{tabular}{cc}
+$\downarrow$ & $\downarrow$ \\
+\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1b.pdf}} &
+\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2b.pdf}} \\
+\end{tabular}
\end{frame}
+\begin{frame}[t, fragile]{\subsubsecname{} -- 9/13}
+Wrapping in {\tt test1}:
+\begin{columns}
+\column[t]{5cm}
+\vbox to 0cm{\fbox{\includegraphics[width=4.5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1b.pdf}}\vss}
+\column[t]{6cm}
+\begin{lstlisting}[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
+techmap -map macc_xilinx_wrap_map.v
+
+connwrappers -unsigned $__mul_wrapper \
+ Y Y_WIDTH \
+ -unsigned $__add_wrapper \
+ Y Y_WIDTH ;;
+\end{lstlisting}
+\end{columns}
+
+\vskip1cm
+\hfil\includegraphics[width=\linewidth,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1c.pdf}
+\end{frame}
+
+\begin{frame}[t, fragile]{\subsubsecname{} -- 10/13}
+Wrapping in {\tt test2}:
+\begin{columns}
+\column[t]{5cm}
+\vbox to 0cm{\fbox{\includegraphics[width=4.5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2b.pdf}}\vss}
+\column[t]{6cm}
+\begin{lstlisting}[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
+techmap -map macc_xilinx_wrap_map.v
+
+connwrappers -unsigned $__mul_wrapper \
+ Y Y_WIDTH \
+ -unsigned $__add_wrapper \
+ Y Y_WIDTH ;;
+\end{lstlisting}
+\end{columns}
+
+\vskip1cm
+\hfil\includegraphics[width=\linewidth,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2c.pdf}
+\end{frame}
+
+\begin{frame}[t, fragile]{\subsubsecname{} -- 11/13}
+Extract in {\tt test1}:
+\begin{columns}
+\column[t]{4.5cm}
+\vbox to 0cm{
+\begin{lstlisting}[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
+design -push
+read_verilog macc_xilinx_xmap.v
+techmap -map macc_xilinx_swap_map.v
+techmap -map macc_xilinx_wrap_map.v;;
+design -save __macc_xilinx_xmap
+design -pop
+\end{lstlisting}
+\vss}
+\column[t]{5.5cm}
+\vskip-1cm
+\begin{lstlisting}[linewidth=5.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
+extract -constports -ignore_parameters \
+ -map %__macc_xilinx_xmap \
+ -swap $__add_wrapper A,B ;;
+\end{lstlisting}
+\vbox to 0cm{\fbox{\includegraphics[width=4.5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1c.pdf}}\vss}
+\end{columns}
+
+\vskip2cm
+\hfil\includegraphics[width=11cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1d.pdf}
+\end{frame}
+
+\begin{frame}[t, fragile]{\subsubsecname{} -- 12/13}
+Extract in {\tt test2}:
+\begin{columns}
+\column[t]{4.5cm}
+\vbox to 0cm{
+\begin{lstlisting}[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
+design -push
+read_verilog macc_xilinx_xmap.v
+techmap -map macc_xilinx_swap_map.v
+techmap -map macc_xilinx_wrap_map.v;;
+design -save __macc_xilinx_xmap
+design -pop
+\end{lstlisting}
+\vss}
+\column[t]{5.5cm}
+\vskip-1cm
+\begin{lstlisting}[linewidth=5.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
+extract -constports -ignore_parameters \
+ -map %__macc_xilinx_xmap \
+ -swap $__add_wrapper A,B ;;
+\end{lstlisting}
+\vbox to 0cm{\fbox{\includegraphics[width=4.5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2c.pdf}}\vss}
+\end{columns}
+
+\vskip2cm
+\hfil\includegraphics[width=11cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2d.pdf}
+\end{frame}
+
+\begin{frame}[t, fragile]{\subsubsecname{} -- 13/13}
+Unwrap in {\tt test2}:
+
+\hfil\begin{tikzpicture}
+\node at (0,0) {\includegraphics[width=11cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2d.pdf}};
+\node at (0,-4) {\includegraphics[width=11cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2e.pdf}};
+\node at (1,-1.7) {\begin{lstlisting}[linewidth=5.5cm, frame=single, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
+techmap -map macc_xilinx_unwrap_map.v ;;
+\end{lstlisting}};
+\draw[-latex] (4,-0.7) .. controls (5,-1.7) .. (4,-2.7);
+\end{tikzpicture}
+\end{frame}
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Automatic design changes}
@@ -269,10 +808,67 @@ TBD
\subsectionpagesuffix
\end{frame}
-\subsubsection{TBD}
+\subsubsection{Changing the design from Yosys}
\begin{frame}{\subsubsecname}
-TBD
+Yosys commands can be used to change the design in memory. Examples of this are:
+
+\begin{itemize}
+\item {\bf Changes in design hierarchy} \\
+Commands such as {\tt flatten} and {\tt submod} can be used to change the design hierarchy, i.e.
+flatten the hierarchy or moving parts of a module to a submodule. This has applications in synthesis
+scripts as well as in reverse engineering and analysis.
+
+\item {\bf Behavioral changes} \\
+Commands such as {\tt techmap} can be used to make behavioral changes to the design, for example
+changing asynchonous resets to synchronous resets. This has applications in design space exploration
+(evaluation of various architectures for one circuit).
+\end{itemize}
+\end{frame}
+
+\subsubsection{Example: Async reset to sync reset}
+
+\begin{frame}[t, fragile]{\subsubsecname}
+The following techmap map file replaces all positive-edge async reset flip-flops with
+positive-edge sync reset flip-flops. The code is taken from the example Yosys script
+for ASIC synthesis of the Amber ARMv2 CPU.
+
+\begin{columns}
+\column[t]{6cm}
+\vbox to 0cm{
+\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog]
+(* techmap_celltype = "$adff" *)
+module adff2dff (CLK, ARST, D, Q);
+
+ parameter WIDTH = 1;
+ parameter CLK_POLARITY = 1;
+ parameter ARST_POLARITY = 1;
+ parameter ARST_VALUE = 0;
+
+ input CLK, ARST;
+ input [WIDTH-1:0] D;
+ output reg [WIDTH-1:0] Q;
+
+ wire [1023:0] _TECHMAP_DO_ = "proc";
+
+ wire _TECHMAP_FAIL_ = !CLK_POLARITY || !ARST_POLARITY;
+\end{lstlisting}
+\vss}
+\column[t]{4cm}
+\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog]
+// ..continued..
+
+
+ always @(posedge CLK)
+ if (ARST)
+ Q <= ARST_VALUE;
+ else
+ <= D;
+
+endmodule
+\end{lstlisting}
+\end{columns}
+
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -281,10 +877,8 @@ TBD
\begin{frame}{\subsecname}
\begin{itemize}
-\item TBD
-\item TBD
-\item TBD
-\item TBD
+\item A lot can be achived in Yosys just with the standard set of commands.
+\item The commands {\tt techmap} and {\tt extract} can be used to prototype many complex synthesis tasks.
\end{itemize}
\bigskip
diff --git a/manual/PRESENTATION_ExAdv/Makefile b/manual/PRESENTATION_ExAdv/Makefile
index f38bd6ce..993a9d9e 100644
--- a/manual/PRESENTATION_ExAdv/Makefile
+++ b/manual/PRESENTATION_ExAdv/Makefile
@@ -1,6 +1,28 @@
-all: select_01.pdf
+all: select.pdf red_or3x1.pdf sym_mul.pdf mymul.pdf mulshift.pdf addshift.pdf \
+ macc_simple_xmap.pdf macc_xilinx_xmap.pdf
-select_01.pdf: select_01.v select_01.ys
- ../../yosys select_01.ys
+select.pdf: select.v select.ys
+ ../../yosys select.ys
+
+red_or3x1.pdf: red_or3x1_*
+ ../../yosys red_or3x1_test.ys
+
+sym_mul.pdf: sym_mul_*
+ ../../yosys sym_mul_test.ys
+
+mymul.pdf: mymul_*
+ ../../yosys mymul_test.ys
+
+mulshift.pdf: mulshift_*
+ ../../yosys mulshift_test.ys
+
+addshift.pdf: addshift_*
+ ../../yosys addshift_test.ys
+
+macc_simple_xmap.pdf: macc_simple_*.v macc_simple_test.ys
+ ../../yosys macc_simple_test.ys
+
+macc_xilinx_xmap.pdf: macc_xilinx_*.v macc_xilinx_test.ys
+ ../../yosys macc_xilinx_test.ys
diff --git a/manual/PRESENTATION_ExAdv/addshift_map.v b/manual/PRESENTATION_ExAdv/addshift_map.v
new file mode 100644
index 00000000..b6d91b01
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/addshift_map.v
@@ -0,0 +1,20 @@
+module \$add (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ parameter _TECHMAP_BITS_CONNMAP_ = 0;
+ parameter _TECHMAP_CONNMAP_A_ = 0;
+ parameter _TECHMAP_CONNMAP_B_ = 0;
+
+ wire _TECHMAP_FAIL_ = A_WIDTH != B_WIDTH || B_WIDTH < Y_WIDTH ||
+ _TECHMAP_CONNMAP_A_ != _TECHMAP_CONNMAP_B_;
+
+ assign Y = A << 1;
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/addshift_test.v b/manual/PRESENTATION_ExAdv/addshift_test.v
new file mode 100644
index 00000000..b53271fa
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/addshift_test.v
@@ -0,0 +1,5 @@
+module test (A, B, X, Y);
+input [7:0] A, B;
+output [7:0] X = A + B;
+output [7:0] Y = A + A;
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/addshift_test.ys b/manual/PRESENTATION_ExAdv/addshift_test.ys
new file mode 100644
index 00000000..c08f1106
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/addshift_test.ys
@@ -0,0 +1,6 @@
+read_verilog addshift_test.v
+hierarchy -check -top test
+
+techmap -map addshift_map.v;;
+
+show -prefix addshift -format pdf -notitle
diff --git a/manual/PRESENTATION_ExAdv/macc_simple_test.v b/manual/PRESENTATION_ExAdv/macc_simple_test.v
new file mode 100644
index 00000000..6358a47c
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/macc_simple_test.v
@@ -0,0 +1,6 @@
+module test(a, b, c, d, y);
+input [15:0] a, b;
+input [31:0] c, d;
+output [31:0] y;
+assign y = a * b + c + d;
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/macc_simple_test.ys b/manual/PRESENTATION_ExAdv/macc_simple_test.ys
new file mode 100644
index 00000000..8d106a28
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/macc_simple_test.ys
@@ -0,0 +1,37 @@
+read_verilog macc_simple_test.v
+hierarchy -check -top test;;
+
+show -prefix macc_simple_test_00a -format pdf -notitle -lib macc_simple_xmap.v
+
+extract -constports -map macc_simple_xmap.v;;
+show -prefix macc_simple_test_00b -format pdf -notitle -lib macc_simple_xmap.v
+
+#################################################
+
+design -reset
+read_verilog macc_simple_test_01.v
+hierarchy -check -top test;;
+
+show -prefix macc_simple_test_01a -format pdf -notitle -lib macc_simple_xmap.v
+
+extract -map macc_simple_xmap.v;;
+show -prefix macc_simple_test_01b -format pdf -notitle -lib macc_simple_xmap.v
+
+#################################################
+
+design -reset
+read_verilog macc_simple_test_02.v
+hierarchy -check -top test;;
+
+show -prefix macc_simple_test_02a -format pdf -notitle -lib macc_simple_xmap.v
+
+extract -map macc_simple_xmap.v;;
+show -prefix macc_simple_test_02b -format pdf -notitle -lib macc_simple_xmap.v
+
+#################################################
+
+design -reset
+read_verilog macc_simple_xmap.v
+hierarchy -check -top macc_16_16_32;;
+
+show -prefix macc_simple_xmap -format pdf -notitle
diff --git a/manual/PRESENTATION_ExAdv/macc_simple_test_01.v b/manual/PRESENTATION_ExAdv/macc_simple_test_01.v
new file mode 100644
index 00000000..8391fb38
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/macc_simple_test_01.v
@@ -0,0 +1,6 @@
+module test(a, b, c, d, x, y);
+input [15:0] a, b, c, d;
+input [31:0] x;
+output [31:0] y;
+assign y = a*b + c*d + x;
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/macc_simple_test_02.v b/manual/PRESENTATION_ExAdv/macc_simple_test_02.v
new file mode 100644
index 00000000..3630102f
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/macc_simple_test_02.v
@@ -0,0 +1,6 @@
+module test(a, b, c, d, x, y);
+input [15:0] a, b, c, d;
+input [31:0] x;
+output [31:0] y;
+assign y = a*b + (c*d + x);
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/macc_simple_xmap.v b/manual/PRESENTATION_ExAdv/macc_simple_xmap.v
new file mode 100644
index 00000000..42f5bae9
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/macc_simple_xmap.v
@@ -0,0 +1,6 @@
+module macc_16_16_32(a, b, c, y);
+input [15:0] a, b;
+input [31:0] c;
+output [31:0] y;
+assign y = a*b + c;
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/macc_xilinx_swap_map.v b/manual/PRESENTATION_ExAdv/macc_xilinx_swap_map.v
new file mode 100644
index 00000000..e3696722
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/macc_xilinx_swap_map.v
@@ -0,0 +1,28 @@
+(* techmap_celltype = "$mul" *)
+module mul_swap_ports (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire _TECHMAP_FAIL_ = A_WIDTH <= B_WIDTH;
+
+\$mul #(
+ .A_SIGNED(B_SIGNED),
+ .B_SIGNED(A_SIGNED),
+ .A_WIDTH(B_WIDTH),
+ .B_WIDTH(A_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+) _TECHMAP_REPLACE_ (
+ .A(B),
+ .B(A),
+ .Y(Y)
+);
+
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/macc_xilinx_test.v b/manual/PRESENTATION_ExAdv/macc_xilinx_test.v
new file mode 100644
index 00000000..683d9d84
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/macc_xilinx_test.v
@@ -0,0 +1,13 @@
+module test1(a, b, c, d, e, f, y);
+ input [19:0] a, b, c;
+ input [15:0] d, e, f;
+ output [41:0] y;
+ assign y = a*b + c*d + e*f;
+endmodule
+
+module test2(a, b, c, d, e, f, y);
+ input [19:0] a, b, c;
+ input [15:0] d, e, f;
+ output [41:0] y;
+ assign y = a*b + (c*d + e*f);
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/macc_xilinx_test.ys b/manual/PRESENTATION_ExAdv/macc_xilinx_test.ys
new file mode 100644
index 00000000..f3e8af4f
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/macc_xilinx_test.ys
@@ -0,0 +1,43 @@
+read_verilog macc_xilinx_test.v
+read_verilog -lib -icells macc_xilinx_unwrap_map.v
+read_verilog -lib -icells macc_xilinx_xmap.v
+hierarchy -check ;;
+
+show -prefix macc_xilinx_test1a -format pdf -notitle test1
+show -prefix macc_xilinx_test2a -format pdf -notitle test2
+
+techmap -map macc_xilinx_swap_map.v;;
+
+show -prefix macc_xilinx_test1b -format pdf -notitle test1
+show -prefix macc_xilinx_test2b -format pdf -notitle test2
+
+techmap -map macc_xilinx_wrap_map.v
+
+connwrappers -unsigned $__mul_wrapper Y Y_WIDTH \
+ -unsigned $__add_wrapper Y Y_WIDTH;;
+
+show -prefix macc_xilinx_test1c -format pdf -notitle test1
+show -prefix macc_xilinx_test2c -format pdf -notitle test2
+
+design -push
+read_verilog macc_xilinx_xmap.v
+techmap -map macc_xilinx_swap_map.v
+techmap -map macc_xilinx_wrap_map.v;;
+design -save __macc_xilinx_xmap
+design -pop
+
+extract -constports -ignore_parameters \
+ -map %__macc_xilinx_xmap \
+ -swap $__add_wrapper A,B ;;
+
+show -prefix macc_xilinx_test1d -format pdf -notitle test1
+show -prefix macc_xilinx_test2d -format pdf -notitle test2
+
+techmap -map macc_xilinx_unwrap_map.v;;
+
+show -prefix macc_xilinx_test1e -format pdf -notitle test1
+show -prefix macc_xilinx_test2e -format pdf -notitle test2
+
+design -load __macc_xilinx_xmap
+show -prefix macc_xilinx_xmap -format pdf -notitle
+
diff --git a/manual/PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v b/manual/PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v
new file mode 100644
index 00000000..9dfaef13
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v
@@ -0,0 +1,61 @@
+module \$__mul_wrapper (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [17:0] A;
+input [24:0] B;
+output [47:0] Y;
+
+wire [A_WIDTH-1:0] A_ORIG = A;
+wire [B_WIDTH-1:0] B_ORIG = B;
+wire [Y_WIDTH-1:0] Y_ORIG;
+assign Y = Y_ORIG;
+
+\$mul #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+) _TECHMAP_REPLACE_ (
+ .A(A_ORIG),
+ .B(B_ORIG),
+ .Y(Y_ORIG)
+);
+
+endmodule
+
+module \$__add_wrapper (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [47:0] A;
+input [47:0] B;
+output [47:0] Y;
+
+wire [A_WIDTH-1:0] A_ORIG = A;
+wire [B_WIDTH-1:0] B_ORIG = B;
+wire [Y_WIDTH-1:0] Y_ORIG;
+assign Y = Y_ORIG;
+
+\$add #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+) _TECHMAP_REPLACE_ (
+ .A(A_ORIG),
+ .B(B_ORIG),
+ .Y(Y_ORIG)
+);
+
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/macc_xilinx_wrap_map.v b/manual/PRESENTATION_ExAdv/macc_xilinx_wrap_map.v
new file mode 100644
index 00000000..f23f6c02
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/macc_xilinx_wrap_map.v
@@ -0,0 +1,89 @@
+(* techmap_celltype = "$mul" *)
+module mul_wrap (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire [17:0] A_18 = A;
+wire [24:0] B_25 = B;
+wire [47:0] Y_48;
+assign Y = Y_48;
+
+wire [1023:0] _TECHMAP_DO_ = "proc; clean";
+
+reg _TECHMAP_FAIL_;
+initial begin
+ _TECHMAP_FAIL_ <= 0;
+ if (A_SIGNED || B_SIGNED)
+ _TECHMAP_FAIL_ <= 1;
+ if (A_WIDTH < 4 || B_WIDTH < 4)
+ _TECHMAP_FAIL_ <= 1;
+ if (A_WIDTH > 18 || B_WIDTH > 25)
+ _TECHMAP_FAIL_ <= 1;
+ if (A_WIDTH*B_WIDTH < 100)
+ _TECHMAP_FAIL_ <= 1;
+end
+
+\$__mul_wrapper #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+) _TECHMAP_REPLACE_ (
+ .A(A_18),
+ .B(B_25),
+ .Y(Y_48)
+);
+
+endmodule
+
+(* techmap_celltype = "$add" *)
+module add_wrap (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire [47:0] A_48 = A;
+wire [47:0] B_48 = B;
+wire [47:0] Y_48;
+assign Y = Y_48;
+
+wire [1023:0] _TECHMAP_DO_ = "proc; clean";
+
+reg _TECHMAP_FAIL_;
+initial begin
+ _TECHMAP_FAIL_ <= 0;
+ if (A_SIGNED || B_SIGNED)
+ _TECHMAP_FAIL_ <= 1;
+ if (A_WIDTH < 10 && B_WIDTH < 10)
+ _TECHMAP_FAIL_ <= 1;
+end
+
+\$__add_wrapper #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+) _TECHMAP_REPLACE_ (
+ .A(A_48),
+ .B(B_48),
+ .Y(Y_48)
+);
+
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/macc_xilinx_xmap.v b/manual/PRESENTATION_ExAdv/macc_xilinx_xmap.v
new file mode 100644
index 00000000..06372f5a
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/macc_xilinx_xmap.v
@@ -0,0 +1,10 @@
+module DSP48_MACC (a, b, c, y);
+
+input [17:0] a;
+input [24:0] b;
+input [47:0] c;
+output [47:0] y;
+
+assign y = a*b + c;
+
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/mulshift_map.v b/manual/PRESENTATION_ExAdv/mulshift_map.v
new file mode 100644
index 00000000..4a3c2a06
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/mulshift_map.v
@@ -0,0 +1,26 @@
+module MYMUL(A, B, Y);
+ parameter WIDTH = 1;
+ input [WIDTH-1:0] A, B;
+ output reg [WIDTH-1:0] Y;
+
+ parameter _TECHMAP_CONSTVAL_A_ = WIDTH'bx;
+ parameter _TECHMAP_CONSTVAL_B_ = WIDTH'bx;
+
+ reg _TECHMAP_FAIL_;
+ wire [1023:0] _TECHMAP_DO_ = "proc; clean";
+
+ integer i;
+ always @* begin
+ _TECHMAP_FAIL_ <= 1;
+ for (i = 0; i < WIDTH; i=i+1) begin
+ if (_TECHMAP_CONSTVAL_A_ === WIDTH'd1 << i) begin
+ _TECHMAP_FAIL_ <= 0;
+ Y <= B << i;
+ end
+ if (_TECHMAP_CONSTVAL_B_ === WIDTH'd1 << i) begin
+ _TECHMAP_FAIL_ <= 0;
+ Y <= A << i;
+ end
+ end
+ end
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/mulshift_test.v b/manual/PRESENTATION_ExAdv/mulshift_test.v
new file mode 100644
index 00000000..4b975f41
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/mulshift_test.v
@@ -0,0 +1,5 @@
+module test (A, X, Y);
+input [7:0] A;
+output [7:0] X = A * 8'd 6;
+output [7:0] Y = A * 8'd 8;
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/mulshift_test.ys b/manual/PRESENTATION_ExAdv/mulshift_test.ys
new file mode 100644
index 00000000..c5dac49e
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/mulshift_test.ys
@@ -0,0 +1,7 @@
+read_verilog mulshift_test.v
+hierarchy -check -top test
+
+techmap -map sym_mul_map.v \
+ -map mulshift_map.v;;
+
+show -prefix mulshift -format pdf -notitle -lib sym_mul_cells.v
diff --git a/manual/PRESENTATION_ExAdv/mymul_map.v b/manual/PRESENTATION_ExAdv/mymul_map.v
new file mode 100644
index 00000000..e888a7a7
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/mymul_map.v
@@ -0,0 +1,15 @@
+module MYMUL(A, B, Y);
+ parameter WIDTH = 1;
+ input [WIDTH-1:0] A, B;
+ output reg [WIDTH-1:0] Y;
+
+ wire [1023:0] _TECHMAP_DO_ = "proc; clean";
+
+ integer i;
+ always @* begin
+ Y = 0;
+ for (i = 0; i < WIDTH; i=i+1)
+ if (A[i])
+ Y = Y + (B << i);
+ end
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/mymul_test.v b/manual/PRESENTATION_ExAdv/mymul_test.v
new file mode 100644
index 00000000..620a06d9
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/mymul_test.v
@@ -0,0 +1,4 @@
+module test(A, B, Y);
+ input [1:0] A, B;
+ output [1:0] Y = A * B;
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/mymul_test.ys b/manual/PRESENTATION_ExAdv/mymul_test.ys
new file mode 100644
index 00000000..48203e31
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/mymul_test.ys
@@ -0,0 +1,15 @@
+read_verilog mymul_test.v
+hierarchy -check -top test
+
+techmap -map sym_mul_map.v \
+ -map mymul_map.v;;
+
+rename test test_mapped
+read_verilog mymul_test.v
+miter -equiv test test_mapped miter
+flatten miter
+
+sat -verify -prove trigger 0 miter
+
+splitnets -ports test_mapped/A
+show -prefix mymul -format pdf -notitle test_mapped
diff --git a/manual/PRESENTATION_ExAdv/red_or3x1_cells.v b/manual/PRESENTATION_ExAdv/red_or3x1_cells.v
new file mode 100644
index 00000000..0750a130
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/red_or3x1_cells.v
@@ -0,0 +1,5 @@
+module OR3X1(A, B, C, Y);
+ input A, B, C;
+ output Y;
+ assign Y = A | B | C;
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/red_or3x1_map.v b/manual/PRESENTATION_ExAdv/red_or3x1_map.v
new file mode 100644
index 00000000..24ca9dab
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/red_or3x1_map.v
@@ -0,0 +1,48 @@
+module \$reduce_or (A, Y);
+
+ parameter A_SIGNED = 0;
+ parameter A_WIDTH = 0;
+ parameter Y_WIDTH = 0;
+
+ input [A_WIDTH-1:0] A;
+ output [Y_WIDTH-1:0] Y;
+
+ function integer min;
+ input integer a, b;
+ begin
+ if (a < b)
+ min = a;
+ else
+ min = b;
+ end
+ endfunction
+
+ genvar i;
+ generate begin
+ if (A_WIDTH == 0) begin
+ assign Y = 0;
+ end
+ if (A_WIDTH == 1) begin
+ assign Y = A;
+ end
+ if (A_WIDTH == 2) begin
+ wire ybuf;
+ OR3X1 g (.A(A[0]), .B(A[1]), .C(1'b0), .Y(ybuf));
+ assign Y = ybuf;
+ end
+ if (A_WIDTH == 3) begin
+ wire ybuf;
+ OR3X1 g (.A(A[0]), .B(A[1]), .C(A[2]), .Y(ybuf));
+ assign Y = ybuf;
+ end
+ if (A_WIDTH > 3) begin
+ localparam next_stage_sz = (A_WIDTH+2) / 3;
+ wire [next_stage_sz-1:0] next_stage;
+ for (i = 0; i < next_stage_sz; i = i+1) begin
+ localparam bits = min(A_WIDTH - 3*i, 3);
+ assign next_stage[i] = |A[3*i +: bits];
+ end
+ assign Y = |next_stage;
+ end
+ end endgenerate
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/red_or3x1_test.v b/manual/PRESENTATION_ExAdv/red_or3x1_test.v
new file mode 100644
index 00000000..bcdd32cb
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/red_or3x1_test.v
@@ -0,0 +1,5 @@
+module test (A, Y);
+ input [6:0] A;
+ output Y;
+ assign Y = |A;
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/red_or3x1_test.ys b/manual/PRESENTATION_ExAdv/red_or3x1_test.ys
new file mode 100644
index 00000000..b9234603
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/red_or3x1_test.ys
@@ -0,0 +1,7 @@
+read_verilog red_or3x1_test.v
+hierarchy -check -top test
+
+techmap -map red_or3x1_map.v;;
+
+splitnets -ports
+show -prefix red_or3x1 -format pdf -notitle -lib red_or3x1_cells.v
diff --git a/manual/PRESENTATION_ExAdv/select_01.v b/manual/PRESENTATION_ExAdv/select.v
index 1b0bb7ee..1b0bb7ee 100644
--- a/manual/PRESENTATION_ExAdv/select_01.v
+++ b/manual/PRESENTATION_ExAdv/select.v
diff --git a/manual/PRESENTATION_ExAdv/select_01.ys b/manual/PRESENTATION_ExAdv/select.ys
index a7fe2728..9832c104 100644
--- a/manual/PRESENTATION_ExAdv/select_01.ys
+++ b/manual/PRESENTATION_ExAdv/select.ys
@@ -1,10 +1,10 @@
-read_verilog select_01.v
+read_verilog select.v
hierarchy -check -top test
proc; opt
cd test
select -set cone_a state_a %ci*:-$dff
select -set cone_b state_b %ci*:-$dff
select -set cone_ab @cone_a @cone_b %i
-show -prefix select_01 -format pdf -notitle \
+show -prefix select -format pdf -notitle \
-color red @cone_ab -color magenta @cone_a \
-color blue @cone_b
diff --git a/manual/PRESENTATION_ExAdv/sym_mul_cells.v b/manual/PRESENTATION_ExAdv/sym_mul_cells.v
new file mode 100644
index 00000000..ce177154
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/sym_mul_cells.v
@@ -0,0 +1,6 @@
+module MYMUL(A, B, Y);
+ parameter WIDTH = 1;
+ input [WIDTH-1:0] A, B;
+ output [WIDTH-1:0] Y;
+ assign Y = A * B;
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/sym_mul_map.v b/manual/PRESENTATION_ExAdv/sym_mul_map.v
new file mode 100644
index 00000000..293c5b84
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/sym_mul_map.v
@@ -0,0 +1,15 @@
+module \$mul (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ wire _TECHMAP_FAIL_ = A_WIDTH != B_WIDTH || B_WIDTH != Y_WIDTH;
+
+ MYMUL #( .WIDTH(Y_WIDTH) ) g ( .A(A), .B(B), .Y(Y) );
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/sym_mul_test.v b/manual/PRESENTATION_ExAdv/sym_mul_test.v
new file mode 100644
index 00000000..eb715f83
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/sym_mul_test.v
@@ -0,0 +1,5 @@
+module test(A, B, C, Y1, Y2);
+ input [7:0] A, B, C;
+ output [7:0] Y1 = A * B;
+ output [15:0] Y2 = A * C;
+endmodule
diff --git a/manual/PRESENTATION_ExAdv/sym_mul_test.ys b/manual/PRESENTATION_ExAdv/sym_mul_test.ys
new file mode 100644
index 00000000..0c07e7e8
--- /dev/null
+++ b/manual/PRESENTATION_ExAdv/sym_mul_test.ys
@@ -0,0 +1,6 @@
+read_verilog sym_mul_test.v
+hierarchy -check -top test
+
+techmap -map sym_mul_map.v;;
+
+show -prefix sym_mul -format pdf -notitle -lib sym_mul_cells.v
diff --git a/manual/PRESENTATION_ExOth.tex b/manual/PRESENTATION_ExOth.tex
index 13ec3d19..f86dcd7a 100644
--- a/manual/PRESENTATION_ExOth.tex
+++ b/manual/PRESENTATION_ExOth.tex
@@ -6,11 +6,10 @@
\end{frame}
\begin{frame}{Overview}
-This section contains 3 subsections:
+This section contains 2 subsections:
\begin{itemize}
\item Interactive Design Investigation
\item Symbolic Model Checking
-\item Reverse Engineering
\end{itemize}
\end{frame}
@@ -23,10 +22,70 @@ This section contains 3 subsections:
\subsectionpagesuffix
\end{frame}
-\subsubsection{TBD}
+\begin{frame}{\subsecname}
+Yosys can also be used to investigate designs (or netlists created
+from other tools).
+
+\begin{itemize}
+\item
+The selection mechanism (see slides ``Using Selections''), especially patterns such
+as {\tt \%ci} and {\tt \%co}, can be used to figure out how parts of the design
+are connected.
+
+\item
+Commands such as {\tt submod}, {\tt expose}, {\tt splice}, \dots can be used
+to transform the design into an equivialent design that is easier to analyse.
+
+\item
+Commands such as {\tt eval} and {\tt sat} can be used to investigate the
+behavior of the circuit.
+\end{itemize}
+\end{frame}
-\begin{frame}{\subsubsecname}
-TBD
+\begin{frame}[t, fragile]{Example: Reorganizing a module}
+\begin{columns}
+\column[t]{4cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont, language=verilog]{PRESENTATION_ExOth/scrambler.v}
+\column[t]{7cm}
+\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]
+read_verilog scrambler.v
+
+hierarchy; proc;;
+
+cd scrambler
+submod -name xorshift32 \
+ xs %c %ci %D %c %ci:+[D] %D \
+ %ci*:-$dff xs %co %ci %d
+\end{lstlisting}
+\end{columns}
+
+\hfil\includegraphics[width=11cm,trim=0 0cm 0 1.5cm]{PRESENTATION_ExOth/scrambler_p01.pdf}
+
+\hfil\includegraphics[width=11cm,trim=0 0cm 0 2cm]{PRESENTATION_ExOth/scrambler_p02.pdf}
+\end{frame}
+
+\begin{frame}[t, fragile]{Example: Analysis of circuit behavior}
+\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
+> read_verilog scrambler.v
+> hierarchy; proc;; cd scrambler
+> submod -name xorshift32 xs %c %ci %D %c %ci:+[D] %D %ci*:-$dff xs %co %ci %d
+
+> cd xorshift32
+> rename n2 in
+> rename n1 out
+
+> eval -set in 1 -show out
+Eval result: \out = 270369.
+
+> eval -set in 270369 -show out
+Eval result: \out = 67634689.
+
+> sat -set out 632435482
+Signal Name Dec Hex Bin
+-------------------- ---------- ---------- -------------------------------------
+\in 745495504 2c6f5bd0 00101100011011110101101111010000
+\out 632435482 25b2331a 00100101101100100011001100011010
+\end{lstlisting}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -38,25 +97,107 @@ TBD
\subsectionpagesuffix
\end{frame}
-\subsubsection{TBD}
+\begin{frame}{\subsecname}
+Symbolic Model Checking (SMC) is used to formally prove that a circuit has
+(or has not) a given property.
+
+\bigskip
+One appliction is Formal Equivalence Checking: Proving that two circuits
+are identical. For example this is a very useful feature when debugging custom
+passes in Yosys.
+
+\bigskip
+Other applications include checking if a module conforms to interface
+standards.
+
+\bigskip
+The {\tt sat} command in Yosys can be used to perform Symbolic Model Checking.
+\end{frame}
+
+\begin{frame}[t]{Example: Formal Equivalence Checking (1/2)}
+Remember the following example?
+\vskip1em
-\begin{frame}{\subsubsecname}
-TBD
+\vbox to 0cm{
+\vskip-0.3cm
+\lstinputlisting[basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont, language=verilog]{PRESENTATION_ExSyn/techmap_01_map.v}
+}\vbox to 0cm{
+\vskip-0.5cm
+\lstinputlisting[xleftmargin=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=verilog]{PRESENTATION_ExSyn/techmap_01.v}
+\lstinputlisting[xleftmargin=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExSyn/techmap_01.ys}}
+
+\vskip5cm\hskip5cm
+Lets see if it is correct..
\end{frame}
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\begin{frame}[t, fragile]{Example: Formal Equivalence Checking (2/2)}
+\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]
+# read test design
+read_verilog techmap_01.v
+hierarchy -top test
-\subsection{Reverse Engineering}
+# create two version of the design: test_orig and test_mapped
+copy test test_orig
+rename test test_mapped
-\begin{frame}
-\subsectionpage
-\subsectionpagesuffix
+# apply the techmap only to test_mapped
+techmap -map techmap_01_map.v test_mapped
+
+# create a miter circuit to test equivialence
+miter -equiv -make_assert -make_outputs test_orig test_mapped miter
+flatten miter
+
+# run equivialence check
+sat -verify -prove-asserts -show-inputs -show-outputs miter
+\end{lstlisting}
+
+\dots
+\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
+Solving problem with 945 variables and 2505 clauses..
+SAT proof finished - no model found: SUCCESS!
+\end{lstlisting}
+\end{frame}
+
+\begin{frame}[t, fragile]{Example: Symbolic Model Checking (1/2)}
+\small
+The following AXI4 Stream Master has a bug. But the bug is not exposed if the
+slave keeps {\tt tready} asserted all the time. (Something a test bench might do.)
+
+\medskip
+Symbolic Model Checking can be used to expose the bug and find a sequence
+of values for {\tt tready} that yield the incorrect behavior.
+
+\vskip-1em
+\begin{columns}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{5pt}{6pt}\selectfont, language=verilog]{PRESENTATION_ExOth/axis_master.v}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{5pt}{6pt}\selectfont, language=verilog]{PRESENTATION_ExOth/axis_test.v}
+\end{columns}
\end{frame}
-\subsubsection{TBD}
+\begin{frame}[t, fragile]{Example: Symbolic Model Checking (2/2)}
+\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]
+read_verilog -sv axis_master.v axis_test.v
+hierarchy -top axis_test
-\begin{frame}{\subsubsecname}
-TBD
+proc; flatten;;
+sat -seq 50 -prove-asserts
+\end{lstlisting}
+
+\bigskip
+\dots with unmodified {\tt axis\_master.v}:
+\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
+Solving problem with 159344 variables and 442126 clauses..
+SAT proof finished - model found: FAIL!
+\end{lstlisting}
+
+\bigskip
+\dots with fixed {\tt axis\_master.v}:
+\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
+Solving problem with 159144 variables and 441626 clauses..
+SAT proof finished - no model found: SUCCESS!
+\end{lstlisting}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -65,10 +206,10 @@ TBD
\begin{frame}{\subsecname}
\begin{itemize}
-\item TBD
-\item TBD
-\item TBD
-\item TBD
+\item Yosys provides useful features beyond synthesis.
+\item The commands {\tt sat} and {\tt eval} can be used to analyse the behavior of a circuit.
+\item The {\tt sat} command can also be used for symbolic model checking.
+\item This can be useful for debugging and testing designs and Yosys extensions alike.
\end{itemize}
\bigskip
diff --git a/manual/PRESENTATION_ExOth/.gitignore b/manual/PRESENTATION_ExOth/.gitignore
new file mode 100644
index 00000000..cf658897
--- /dev/null
+++ b/manual/PRESENTATION_ExOth/.gitignore
@@ -0,0 +1 @@
+*.dot
diff --git a/manual/PRESENTATION_ExOth/Makefile b/manual/PRESENTATION_ExOth/Makefile
new file mode 100644
index 00000000..4864d8d5
--- /dev/null
+++ b/manual/PRESENTATION_ExOth/Makefile
@@ -0,0 +1,16 @@
+
+all: scrambler_p01.pdf scrambler_p02.pdf equiv.log axis_test.log
+
+scrambler_p01.pdf: scrambler.ys scrambler.v
+ ../../yosys scrambler.ys
+
+scrambler_p02.pdf: scrambler_p01.pdf
+
+equiv.log: equiv.ys
+ ../../yosys -l equiv.log_new equiv.ys
+ mv equiv.log_new equiv.log
+
+axis_test.log: axis_test.ys axis_master.v axis_test.v
+ ../../yosys -l axis_test.log_new axis_test.ys
+ mv axis_test.log_new axis_test.log
+
diff --git a/manual/PRESENTATION_ExOth/axis_master.v b/manual/PRESENTATION_ExOth/axis_master.v
new file mode 100644
index 00000000..25a1feee
--- /dev/null
+++ b/manual/PRESENTATION_ExOth/axis_master.v
@@ -0,0 +1,27 @@
+module axis_master(aclk, aresetn, tvalid, tready, tdata);
+ input aclk, aresetn, tready;
+ output reg tvalid;
+ output reg [7:0] tdata;
+
+ reg [31:0] state;
+ always @(posedge aclk) begin
+ if (!aresetn) begin
+ state <= 314159265;
+ tvalid <= 0;
+ tdata <= 'bx;
+ end else begin
+ if (tvalid && tready)
+ tvalid <= 0;
+ if (!tvalid || !tready) begin
+ // ^- should be not inverted!
+ state = state ^ state << 13;
+ state = state ^ state >> 7;
+ state = state ^ state << 17;
+ if (state[9:8] == 0) begin
+ tvalid <= 1;
+ tdata <= state;
+ end
+ end
+ end
+ end
+endmodule
diff --git a/manual/PRESENTATION_ExOth/axis_test.v b/manual/PRESENTATION_ExOth/axis_test.v
new file mode 100644
index 00000000..0be833f1
--- /dev/null
+++ b/manual/PRESENTATION_ExOth/axis_test.v
@@ -0,0 +1,27 @@
+module axis_test(aclk, tready);
+ input aclk, tready;
+ wire aresetn, tvalid;
+ wire [7:0] tdata;
+
+ integer counter = 0;
+ reg aresetn = 0;
+
+ axis_master uut (aclk, aresetn, tvalid, tready, tdata);
+
+ always @(posedge aclk) begin
+ if (aresetn && tready && tvalid) begin
+ if (counter == 0) assert(tdata == 19);
+ if (counter == 1) assert(tdata == 99);
+ if (counter == 2) assert(tdata == 1);
+ if (counter == 3) assert(tdata == 244);
+ if (counter == 4) assert(tdata == 133);
+ if (counter == 5) assert(tdata == 209);
+ if (counter == 6) assert(tdata == 241);
+ if (counter == 7) assert(tdata == 137);
+ if (counter == 8) assert(tdata == 176);
+ if (counter == 9) assert(tdata == 6);
+ counter <= counter + 1;
+ end
+ aresetn <= 1;
+ end
+endmodule
diff --git a/manual/PRESENTATION_ExOth/axis_test.ys b/manual/PRESENTATION_ExOth/axis_test.ys
new file mode 100644
index 00000000..19663ac7
--- /dev/null
+++ b/manual/PRESENTATION_ExOth/axis_test.ys
@@ -0,0 +1,5 @@
+read_verilog -sv axis_master.v axis_test.v
+hierarchy -top axis_test
+
+proc; flatten;;
+sat -falsify -seq 50 -prove-asserts
diff --git a/manual/PRESENTATION_ExOth/equiv.ys b/manual/PRESENTATION_ExOth/equiv.ys
new file mode 100644
index 00000000..09a4045d
--- /dev/null
+++ b/manual/PRESENTATION_ExOth/equiv.ys
@@ -0,0 +1,17 @@
+# read test design
+read_verilog ../PRESENTATION_ExSyn/techmap_01.v
+hierarchy -top test
+
+# create two version of the design: test_orig and test_mapped
+copy test test_orig
+rename test test_mapped
+
+# apply the techmap only to test_mapped
+techmap -map ../PRESENTATION_ExSyn/techmap_01_map.v test_mapped
+
+# create a miter circuit to test equivialence
+miter -equiv -make_assert -make_outputs test_orig test_mapped miter
+flatten miter
+
+# run equivialence check
+sat -verify -prove-asserts -show-inputs -show-outputs miter
diff --git a/manual/PRESENTATION_ExOth/scrambler.v b/manual/PRESENTATION_ExOth/scrambler.v
new file mode 100644
index 00000000..d4c1fa2b
--- /dev/null
+++ b/manual/PRESENTATION_ExOth/scrambler.v
@@ -0,0 +1,14 @@
+module scrambler(
+ input clk, rst, in_bit,
+ output reg out_bit
+);
+ reg [31:0] xs;
+ always @(posedge clk) begin
+ if (rst)
+ xs = 1;
+ xs = xs ^ (xs << 13);
+ xs = xs ^ (xs >> 17);
+ xs = xs ^ (xs << 5);
+ out_bit <= in_bit ^ xs[0];
+ end
+endmodule
diff --git a/manual/PRESENTATION_ExOth/scrambler.ys b/manual/PRESENTATION_ExOth/scrambler.ys
new file mode 100644
index 00000000..2ef14c56
--- /dev/null
+++ b/manual/PRESENTATION_ExOth/scrambler.ys
@@ -0,0 +1,23 @@
+
+read_verilog scrambler.v
+
+hierarchy; proc;;
+
+cd scrambler
+submod -name xorshift32 xs %c %ci %D %c %ci:+[D] %D %ci*:-$dff xs %co %ci %d
+cd ..
+
+show -prefix scrambler_p01 -format pdf -notitle scrambler
+show -prefix scrambler_p02 -format pdf -notitle xorshift32
+
+echo on
+
+cd xorshift32
+rename n2 in
+rename n1 out
+
+eval -set in 1 -show out
+eval -set in 270369 -show out
+
+sat -set out 632435482
+
diff --git a/manual/PRESENTATION_ExSyn.tex b/manual/PRESENTATION_ExSyn.tex
index 35d0b8a7..80398229 100644
--- a/manual/PRESENTATION_ExSyn.tex
+++ b/manual/PRESENTATION_ExSyn.tex
@@ -12,7 +12,7 @@
\begin{frame}{\subsecname}
\begin{itemize}
\item Reading and elaborating the design
-\item High-level synthesis and optimization
+\item Higher-level synthesis and optimization
\begin{itemize}
\item Converting {\tt always}-blocks to logic and registers
\item Perform coarse-grain optimizations (resource sharing, const folding, ...)
@@ -21,7 +21,7 @@
\end{itemize}
\item Convert remaining logic to bit-level logic functions
\item Perform optimizations on bit-level logic functions
-\item Map bit-level logic and register to gates from cell library
+\item Map bit-level logic gates and registers to cell library
\item Write results to output file
\end{itemize}
\end{frame}
@@ -64,8 +64,8 @@ all needed variations of parametric modules.
#
hierarchy
-# recommended form. fail if parts of the design hierarchy are missing. remove
-# everything that is unreachable by the top module. mark the top module.
+# recommended form. fails if parts of the design hierarchy are missing, removes
+# everything that is unreachable from the top module, and marks the top module.
#
hierarchy -check -top top_module
\end{lstlisting}
@@ -223,7 +223,7 @@ The designs in {\tt yosys-bigsim} are a good playground for experimenting with
the effects of calling {\tt opt} in various places of the flow.
\bigskip
-It generally is a good idea us call {\tt opt} before inherently expensive
+It generally is a good idea to call {\tt opt} before inherently expensive
commands such as {\tt sat} or {\tt freduce}, as the possible gain is much
higher in this cases as the possible loss.
@@ -253,7 +253,7 @@ memory_dff
# into one multi-port memory cell.
memory_collect
-# this takes the multi-port memory cells and transforms it to address decoder
+# this takes the multi-port memory cell and transforms it to address decoder
# logic and registers. This step is skipped if "memory" is called with -nomap.
memory_map
\end{lstlisting}
@@ -279,7 +279,7 @@ memory -nomap; techmap -map my_memory_map.v; memory_map
\end{frame}
\begin{frame}[t, fragile]{\subsecname{} -- Example 2/2}
-\vbox to 0cm{\hfill\includegraphics[width=7.5cm,trim=0cm 0cm 0cm -6cm]{PRESENTATION_ExSyn/memory_02.pdf}\vss}
+\vbox to 0cm{\hfill\includegraphics[width=7.5cm,trim=0cm 0cm 0cm -5cm]{PRESENTATION_ExSyn/memory_02.pdf}\vss}
\vskip-1cm
\begin{columns}
\column[t]{5cm}
@@ -303,11 +303,11 @@ fsm_detect # unless got option -nodetect
fsm_extract
fsm_opt
-opt_clean
+clean
fsm_opt
fsm_expand # if got option -expand
-opt_clean # if got option -expand
+clean # if got option -expand
fsm_opt # if got option -expand
fsm_recode # unless got option -norecode
@@ -346,7 +346,7 @@ Finally the {\tt fsm\_map} command can be used to convert the (optimized) {\tt
\subsection{The {\tt techmap} command}
\begin{frame}[t]{\subsecname}
-\vbox to 0cm{\includegraphics[width=12cm,trim=-18cm 0cm 0cm -34cm]{PRESENTATION_ExSyn/techmap_01.pdf}\vss}
+\vbox to 0cm{\includegraphics[width=12cm,trim=-15cm 0cm 0cm -20cm]{PRESENTATION_ExSyn/techmap_01.pdf}\vss}
\vskip-0.8cm
The {\tt techmap} command replaces cells with implementations given as
verilog source. For example implementing a 32 bit adder using 16 bit adders:
@@ -366,8 +366,8 @@ When {\tt techmap} is used without a map file, it uses a built-in map file
to map all RTL cell types to a generic library of built-in logic gates and registers.
\bigskip
-\begin{block}{The build-in logic gate types are:}
-{\tt \$\_INV\_ \$\_AND\_ \$\_OR\_ \$\_XOR\_ \$\_MUX\_}
+\begin{block}{The built-in logic gate types are:}
+{\tt \$\_NOT\_ \$\_AND\_ \$\_OR\_ \$\_XOR\_ \$\_MUX\_}
\end{block}
\bigskip
@@ -496,7 +496,7 @@ the next part (Section 3, ``Advanced Synthesis'') of this presentation.}
\begin{itemize}
\item Yosys provides commands for each phase of the synthesis.
\item Each command solves a (more or less) simple problem.
-\item Complex command are often only front-ends to simple commands.
+\item Complex commands are often only front-ends to simple commands.
\item {\tt proc; opt; memory; opt; fsm; opt; techmap; opt; abc;;}
\end{itemize}
diff --git a/manual/PRESENTATION_ExSyn/Makefile b/manual/PRESENTATION_ExSyn/Makefile
index bcff48aa..c34eae3f 100644
--- a/manual/PRESENTATION_ExSyn/Makefile
+++ b/manual/PRESENTATION_ExSyn/Makefile
@@ -8,7 +8,7 @@ TARGETS += abc_01
all: $(addsuffix .pdf,$(TARGETS))
define make_pdf_template
-$(1).pdf: $(1).v $(1).ys
+$(1).pdf: $(1)*.v $(1)*.ys
../../yosys -p 'script $(1).ys; show -notitle -prefix $(1) -format pdf'
endef
diff --git a/manual/PRESENTATION_ExSyn/techmap_01_map.v b/manual/PRESENTATION_ExSyn/techmap_01_map.v
index 64c0b87c..4fd86e85 100644
--- a/manual/PRESENTATION_ExSyn/techmap_01_map.v
+++ b/manual/PRESENTATION_ExSyn/techmap_01_map.v
@@ -13,9 +13,9 @@ output [Y_WIDTH-1:0] Y;
generate
if ((A_WIDTH == 32) && (B_WIDTH == 32))
begin
- wire [15:0] CARRY = |{A[15:0], B[15:0]} && ~|Y[15:0];
- assign Y[15:0] = A[15:0] + B[15:0];
- assign Y[31:16] = A[31:16] + B[31:16] + CARRY;
+ wire [16:0] S1 = A[15:0] + B[15:0];
+ wire [15:0] S2 = A[31:16] + B[31:16] + S1[16];
+ assign Y = {S2[15:0], S1[15:0]};
end
else
wire _TECHMAP_FAIL_ = 1;
diff --git a/manual/PRESENTATION_Intro.tex b/manual/PRESENTATION_Intro.tex
index 312cb898..7697266d 100644
--- a/manual/PRESENTATION_Intro.tex
+++ b/manual/PRESENTATION_Intro.tex
@@ -5,6 +5,7 @@
\sectionpage
\end{frame}
+\iffalse
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Representations of (digital) Circuits}
@@ -51,6 +52,7 @@
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\fi
\subsection{Levels of Abstraction for Digital Circuits}
@@ -74,7 +76,7 @@
\only<6>{Physical Gate Level}%
\only<7>{Switch Level}}
\only<1>{
- Overall view of the circuit: E.g. block-diagrams or instruction-set architecture descriptions
+ Overall view of the circuit. E.g. block-diagrams or instruction-set architecture descriptions.
}%
\only<2>{
Functional implementation of circuit in high-level programming language (C, C++, SystemC, Matlab, Python, etc.).
@@ -94,7 +96,7 @@
\only<6>{
Netlist of cells that actually are available on the target architecture
(such as CMOS gates in an ASCI or LUTs in an FPGA). Optimized for
- area and/or and/or speed (static timing or number of logic levels).
+ area, power, and/or speed (static timing or number of logic levels).
}%
\only<7>{
Netlist of individual transistors.
@@ -179,8 +181,8 @@ as Qflow\footnote[frame]{\url{http://opencircuitdesign.com/qflow/}} for ASIC des
This scripts contain three types of commands:
\begin{itemize}
\item {\bf Frontends}, that read input files (usually Verilog).
- \item {\bf Passes}, that perform transformation on the design in memory.
- \item {\bf Backends}, that write the design in memory to a file (various formats are available, e.g. Verilog, BLIF, EDIF, SPICE, BTOR, etc.).
+ \item {\bf Passes}, that perform transformations on the design in memory.
+ \item {\bf Backends}, that write the design in memory to a file (various formats are available: Verilog, BLIF, EDIF, SPICE, BTOR, \dots).
\end{itemize}
\bigskip
@@ -247,26 +249,23 @@ as Qflow\footnote[frame]{\url{http://opencircuitdesign.com/qflow/}} for ASIC des
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\subsection{Example Problem}
+\subsection{Example Project}
-\begin{frame}[fragile]{\subsecname{} -- Verilog Source: \tt counter.v}
-\lstinputlisting[xleftmargin=1cm, language=Verilog]{PRESENTATION_Intro/counter.v}
-\end{frame}
-
-\begin{frame}[fragile]{\subsecname{} -- Cell Library: \tt mycells.lib}
-\begin{columns}
-\column[t]{5cm}
-\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=liberty, lastline=20]{PRESENTATION_Intro/mycells.lib}
-\column[t]{5cm}
-\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=liberty, firstline=21]{PRESENTATION_Intro/mycells.lib}
-\end{columns}
+\begin{frame}[t]{\subsecname}
+The following slides cover an example project. This project contains three files:
+\begin{itemize}
+\item A simple ASIC synthesis script
+\item A digital design written in Verilog
+\item A simple CMOS cell library
+\end{itemize}
+\vfill
+Direct link to the files: \\ \footnotesize
+\url{https://github.com/cliffordwolf/yosys/tree/master/manual/PRESENTATION_Intro}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\subsection{Example Synthesis Script}
-
-\begin{frame}[t]{\subsecname}
+\begin{frame}[t]{\subsecname{} -- Synthesis Script}
\setbeamercolor{alerted text}{fg=white,bg=red}
@@ -283,9 +282,6 @@ as Qflow\footnote[frame]{\url{http://opencircuitdesign.com/qflow/}} for ASIC des
\medskip
{\color{YosysGreen}\# mapping to internal cell library}\\
\boxalert<9>{techmap}; \boxalert<10>{opt}
-
-\bigskip
-\it continued\dots
\end{minipage}
\begin{minipage}[t]{5cm}
\tt\scriptsize
@@ -326,8 +322,8 @@ as Qflow\footnote[frame]{\url{http://opencircuitdesign.com/qflow/}} for ASIC des
Read Verilog source file and convert to internal representation.
}%
\only<2>{
- Elaborate the design hierarchy. Should alsways be the first
- command after reading the design.
+ Elaborate the design hierarchy. Should always be the first
+ command after reading the design. Can re-run AST front-end.
}%
\only<3>{
Convert ``processes'' (the internal representation of behavioral
@@ -359,7 +355,7 @@ as Qflow\footnote[frame]{\url{http://opencircuitdesign.com/qflow/}} for ASIC des
Map registers to available hardware flip-flops.
}%
\only<12>{
- Map logix to available hardware gates.
+ Map logic to available hardware gates.
}%
\only<13>{
Clean up the design (just the last step of {\tt opt}).
@@ -373,6 +369,21 @@ as Qflow\footnote[frame]{\url{http://opencircuitdesign.com/qflow/}} for ASIC des
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\begin{frame}[fragile]{\subsecname{} -- Verilog Source: \tt counter.v}
+\lstinputlisting[xleftmargin=1cm, language=Verilog]{PRESENTATION_Intro/counter.v}
+\end{frame}
+
+\begin{frame}[fragile]{\subsecname{} -- Cell Library: \tt mycells.lib}
+\begin{columns}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=liberty, lastline=20]{PRESENTATION_Intro/mycells.lib}
+\column[t]{5cm}
+\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=liberty, firstline=21]{PRESENTATION_Intro/mycells.lib}
+\end{columns}
+\end{frame}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
\subsection{Running the Synthesis Script}
\begin{frame}[t, fragile]{\subsecname{} -- Step 1/4}
@@ -410,8 +421,8 @@ abc -liberty mycells.lib
clean
\end{verbatim}
-\vfill
-\includegraphics[width=\linewidth,trim=0 0cm 0 0cm]{PRESENTATION_Intro/counter_03.pdf}
+\vfill\hfil
+\includegraphics[width=10cm,trim=0 0cm 0 0cm]{PRESENTATION_Intro/counter_03.pdf}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -422,7 +433,7 @@ clean
Command reference:
\begin{itemize}
\item Use ``{\tt help}'' for a command list and ``{\tt help \it command}'' for details.
-\item Or run ``{\tt yosys -H}'' and ``{\tt yosys -h \it command}''.
+\item Or run ``{\tt yosys -H}'' or ``{\tt yosys -h \it command}''.
\item Or go to \url{http://www.clifford.at/yosys/documentation.html}.
\end{itemize}
@@ -560,7 +571,7 @@ endmodule
module cam(clk, wr_enable, wr_addr, wr_data, rd_data, rd_addr, rd_match);
parameter WIDTH = 8;
parameter DEPTH = 16;
- localparam ADDR_BITS = $clog2(DEPTH);
+ localparam ADDR_BITS = $clog2(DEPTH-1);
input clk, wr_enable;
input [ADDR_BITS-1:0] wr_addr;
@@ -588,6 +599,23 @@ endmodule
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Currently unsupported Verilog-2005 language features}
+
+\begin{frame}{\subsecname}
+\begin{itemize}
+\item Multi-dimensional arrays (memories)
+\item Writing to arrays using bit- and part-selects (todo for 0.4.0)
+\item The wor/wand wire types (maybe for 0.4.0)
+\item Tri-state logic
+
+\bigskip
+\item Latched logic (is synthesized as logic with feedback loops)
+\item Some non-synthesizable features that should be ignored in synthesis are not supported by the parser and cause a parser error (file a bug report if you encounter this problem)
+\end{itemize}
+\end{frame}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
\subsection{Verification of Yosys}
\begin{frame}{\subsecname}
@@ -595,7 +623,7 @@ Contiously checking the correctness of Yosys and making sure that new features
do not break old ones is a high priority in Yosys.
\bigskip
-There are two external test suites build for Yosys: VlogHammer and yosys-bigsim
+Two external test suites have been built for Yosys: VlogHammer and yosys-bigsim
(see next slides)
\bigskip
@@ -608,8 +636,8 @@ the internal state after each command.
\begin{frame}[fragile]{\subsecname{} -- VlogHammer}
VlogHammer is a Verilog regression test suite developed to test the different
-subsystems in Yosys by comparing them to each other and the implementations
-generated by some proprietary tools (Xilinx Vivado, Xilinx XST, Altera Quartus II, ...).
+subsystems in Yosys by comparing them to each other and to the output created
+by some other tools (Xilinx Vivado, Xilinx XST, Altera Quartus II, ...).
\bigskip
Yosys Subsystems tested: Verilog frontend, const folding, const eval, technology mapping,
@@ -624,8 +652,8 @@ assign y11 = (~&(-{(-3'sd3),($unsigned($signed($unsigned({p0,b4,b1}))))}));
\end{lstlisting}
\bigskip
-Some bugs in Yosys where found and fixed thanks to VlogHammer. Over 20 bugs in
-the proprietary tools used as external reference where found and reported.
+Some bugs in Yosys where found and fixed thanks to VlogHammer. Over 50 bugs in
+the other tools used as external reference where found and reported so far.
\end{frame}
\begin{frame}{\subsecname{} -- yosys-bigsim}
@@ -634,7 +662,7 @@ benches. yosys-bigsim compares the testbench outpus of simulations of the origin
Verilog code and synthesis results.
\bigskip
-The following designs are part of yosys-bigsim:
+The following designs are included in yosys-bigsim (excerpt):
\begin{itemize}
\item {\tt openmsp430} -- an MSP430 compatible 16 bit CPU
\item {\tt aes\_5cycle\_2stage} -- an AES encryption core
@@ -651,6 +679,19 @@ The following designs are part of yosys-bigsim:
\subsection{Benefits of Open Source HDL Synthesis}
+\begin{frame}{\subsecname}
+\begin{itemize}
+\item Cost (also applies to ``free as in free beer'' solutions)
+\item Availablity and Reproducability
+\item Framework- and all-in-one-aspects
+\item Educational Tool
+\end{itemize}
+
+\bigskip
+
+Yosys is open source under the ISC license.
+\end{frame}
+
\begin{frame}{\subsecname{} -- 1/3}
\begin{itemize}
\item Cost (also applies to ``free as in free beer'' solutions): \smallskip\par
@@ -680,7 +721,7 @@ basic functionality. Extensibility was one of Yosys' design goals.
Because of the framework characterisitcs of Yosys, an increasing number of features
become available in one tool. Yosys not only can be used for circuit synthesis but
also for formal equivialence checking, SAT solving, and for circuit analysis, to
-name just a few other application domains. With propritaery software one needs to
+name just a few other application domains. With proprietary software one needs to
learn a new tool for each of this applications.
\end{itemize}
\end{frame}
@@ -688,14 +729,13 @@ learn a new tool for each of this applications.
\begin{frame}{\subsecname{} -- 3/3}
\begin{itemize}
\item Educational Tool: \smallskip\par
-Propritaery synthesis tools are at times where secretive about their inner
-workings. They often are ``black boxes'' where a design goes in and synthesis
-results come out. Yosys is very open about its internals and it is easy to
-observe the different steps of synthesis.
+Propritaery synthesis tools are at times very secretive about their inner
+workings. They often are ``black boxes''. Yosys is very open about its
+internals and it is easy to observe the different steps of synthesis.
\end{itemize}
\bigskip
-\begin{block}{BTW: Yosys is licensed under the ISC license:}
+\begin{block}{Yosys is licensed under the ISC license:}
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.
@@ -721,6 +761,67 @@ but also formal verification, reverse engineering, ...}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Projects (that I know of) using Yosys}
+
+\begin{frame}{\subsecname{} -- (1/2)}
+\begin{itemize}
+\item Ongoing PhD project on coarse grain synthesis \\
+{\setlength{\parindent}{0.5cm}\footnotesize
+Johann Glaser and Clifford Wolf. Methodology and Example-Driven Interconnect
+Synthesis for Designing Heterogeneous Coarse-Grain Reconfigurable
+Architectures. In Jan Haase, editor, \it Models, Methods, and Tools for Complex
+Chip Design. Lecture Notes in Electrical Engineering. Volume 265, 2014, pp
+201-221. Springer, 2013.}
+
+\bigskip
+\item I know several people that use Yosys simply as Verilog frontend for other
+flows (using either the BLIF and BTOR backends).
+
+\bigskip
+\item I know some analog chip designers that use Yosys for small digital
+control logic because it is simpler than setting up a commercial flow.
+\end{itemize}
+\end{frame}
+
+\begin{frame}{\subsecname{} -- (2/2)}
+\begin{itemize}
+\item Efabless
+\begin{itemize}
+\smallskip \item Not much information on the website (\url{http://efabless.com}) yet.
+\smallskip \item Very cheap 180nm prototyping process (partnering with various fabs)
+\smallskip \item A semiconductor company, NOT an EDA company
+\smallskip \item Web-based design environment
+\smallskip \item HDL Synthesis using Yosys
+\smallskip \item Custom place\&route tool
+
+\bigskip
+\item efabless is building an Open Source IC as reference design. \\
+\hskip1cm (to be announced soon: \url{http://www.openic.io})
+\end{itemize}
+\end{itemize}
+\end{frame}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\subsection{Supported Platforms}
+
+\begin{frame}{\subsecname}
+\begin{itemize}
+\item Main development OS: Kubuntu 14.04
+\item There is a PPA for ubuntu (not maintained by me)
+\item Any current Debian-based system should work out of the box
+\item When building on other Linux distributions:
+\begin{itemize}
+\item Needs compiler with some C++11 support
+\item Post to the subreddit if you get stuck
+\end{itemize}
+\item Ported to OS X (Darwin) and OpenBSD
+\item No win32 support (yet)
+\end{itemize}
+\end{frame}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
\subsection{Other Open Source Tools}
\begin{frame}{\subsecname}
@@ -743,24 +844,24 @@ but also formal verification, reverse engineering, ...}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\subsection{What the Yosys project needs from you}
+\subsection{Yosys needs you}
\begin{frame}{\subsecname}
-We need you as an active user:
+\dots as an active user:
\begin{itemize}
-\item Use Yosys for on your own designs
+\item Use Yosys for on your own projects
\item .. even if you are not using it as final synthesis tool
\item Join the discussion on the Subreddit
\item Report bugs and send in feature requests
\end{itemize}
\bigskip
-We need you as a developer:
+\dots as a developer:
\begin{itemize}
-\item Use Yosys as environment for your research work
+\item Use Yosys as environment for your (research) work
\item .. you might also want to look into ABC for logic-level stuff
\item Fork the project on github or create loadable plugins
-\item We desperately need a VHDL frontend or a VHDL-to-Verilog converter
+\item We need a VHDL frontend or a good VHDL-to-Verilog converter
\end{itemize}
\end{frame}
@@ -794,7 +895,7 @@ We need you as a developer:
\begin{frame}{\subsecname}
\begin{itemize}
\item Yosys is a powerful tool and framework for Verilog synthesis.
-\item Is uses a command-based interface and can be controlled by scripts.
+\item It uses a command-based interface and can be controlled by scripts.
\item By combining existing commands and implementing new commands Yosys can
be used in a wide range of application far beyond simple synthesis.
\end{itemize}
diff --git a/manual/PRESENTATION_Intro/counter.ys b/manual/PRESENTATION_Intro/counter.ys
index bcfe387e..8b3390ed 100644
--- a/manual/PRESENTATION_Intro/counter.ys
+++ b/manual/PRESENTATION_Intro/counter.ys
@@ -2,17 +2,18 @@
read_verilog counter.v
hierarchy -check -top counter
-show -stretch -format pdf -prefix counter_00
+show -notitle -stretch -format pdf -prefix counter_00
# the high-level stuff
proc; opt; memory; opt; fsm; opt
-show -stretch -format pdf -prefix counter_01
+show -notitle -stretch -format pdf -prefix counter_01
# mapping to internal cell library
-techmap; splitnets -ports; opt
+techmap; opt
-show -stretch -format pdf -prefix counter_02
+splitnets -ports;;
+show -notitle -stretch -format pdf -prefix counter_02
# mapping flip-flops to mycells.lib
dfflibmap -liberty mycells.lib
@@ -23,4 +24,4 @@ abc -liberty mycells.lib
# cleanup
clean
-show -stretch -lib mycells.v -format pdf -prefix counter_03
+show -notitle -stretch -lib mycells.v -format pdf -prefix counter_03
diff --git a/manual/PRESENTATION_Prog.tex b/manual/PRESENTATION_Prog.tex
index 45f0cb0c..590451be 100644
--- a/manual/PRESENTATION_Prog.tex
+++ b/manual/PRESENTATION_Prog.tex
@@ -1,5 +1,5 @@
-\section{Programming Yosys Extensions}
+\section{Writing Yosys extensions in C++}
\begin{frame}
\sectionpage
@@ -7,14 +7,6 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\subsection{Why writing Yosys extensions?}
-
-\begin{frame}{\subsecname}
-TBD
-\end{frame}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
\subsection{Program Components and Data Formats}
\begin{frame}{\subsecname}
@@ -51,8 +43,9 @@ TBD
\subsection{Simplified RTLIL Entity-Relationship Diagram}
\begin{frame}{\subsecname}
-Between passses and frontends/backends the design in stored in Yosys' internal RTLIL (RTL Intermediate Language) format. For
-writing Yosys extensions it is key to understand this format.
+Between passses and frontends/backends the design is stored in Yosys' internal
+RTLIL (RTL Intermediate Language) format. For writing Yosys extensions it is
+key to understand this format.
\bigskip
\begin{center}
@@ -79,7 +72,8 @@ writing Yosys extensions it is key to understand this format.
\subsection{RTLIL without memories and processes}
\begin{frame}[fragile]{\subsecname}
-After the command {\tt proc} and {\tt memory} (or {\tt memory -nomap}), we are left with a much simpler version of RTLIL:
+After the commands {\tt proc} and {\tt memory} (or {\tt memory -nomap}), we are
+left with a much simpler version of RTLIL:
\begin{center}
\begin{tikzpicture}[scale=0.6, every node/.style={transform shape}]
@@ -93,7 +87,7 @@ After the command {\tt proc} and {\tt memory} (or {\tt memory -nomap}), we are l
\end{center}
\bigskip
-Many command simply choose to only work on this simpler version:
+Many commands simply choose to only work on this simpler version:
\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
if (module->processes.size() != 0 || module->memories.size() != 0)
log_error("This command does not operate on modules with processes "
@@ -109,55 +103,293 @@ For simplicity we only discuss this version of RTLIL in this presentation.
\subsection{Using dump and show commands}
\begin{frame}{\subsecname}
-TBD
+\begin{itemize}
+\item The {\tt dump} command prints the design (or parts of it) in ILANG format. This is
+a text representation of RTLIL.
+
+\bigskip
+\item The {\tt show} command visualizes how the components in the design are connected.
+\end{itemize}
+
+\bigskip
+When trying to understand what a command does, create a small test case and
+look at the output of {\tt dump} and {\tt show} before and after the command
+has been executed.
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\subsection{The RTLIL::Const Structure}
+\subsection{The RTLIL Data Structures}
\begin{frame}{\subsecname}
-TBD
+The RTLIL data structures are simple structs utilizing C++ {\tt std::}
+containers.
+
+\bigskip
+\begin{itemize}
+\item Most operations are performed directly on the RTLIL structs without
+setter or getter functions.
+
+\bigskip
+\item In debug builds a consistency checker is run over the in-memory design
+between commands to make sure that the RTLIL representation is intact.
+
+\bigskip
+\item Most RTLIL structs have helper methods that perform the most common operations.
+\end{itemize}
+
+\bigskip
+See {\tt yosys/kernel/rtlil.h} for details.
\end{frame}
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection{RTLIL::IdString}
-\subsection{The RTLIL::SigSpec Structure}
+\begin{frame}{\subsubsecname}{}
+{\tt RTLIL::IdString} is a simple wrapper for {\tt std::string}. It is used for names of RTLIL objects.
-\begin{frame}{\subsecname}
-TBD
+\medskip
+The first character of a {\tt RTLIL::IdString} specifies if the name is {\it public\/} or {\it private\/}:
+
+\medskip
+\begin{itemize}
+\item {\tt RTLIL::IdString[0] == '\textbackslash\textbackslash'}: \\
+This is a public name. Usually this means it is a name that was declared in a Verilog file.
+
+\bigskip
+\item {\tt RTLIL::IdString[0] == '\$'}: \\
+This is a private name. It was assigned by Yosys.
+\end{itemize}
+
+\bigskip
+Use the {\tt NEW\_ID} macro to create a new unique private name.
\end{frame}
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection{RTLIL::Design and RTLIL::Module}
-\subsection{RTLIL::Design, RTLIL::Module}
+\begin{frame}[t, fragile]{\subsubsecname}
+The {\tt RTLIL::Design} and {\tt RTLIL::Module} structs are the top-level RTLIL
+data structures.
-\begin{frame}{\subsecname}
-TBD
+Yosys always operates on one active design, but can hold many designs in memory.
+
+\bigskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+struct RTLIL::Design {
+ std::map<RTLIL::IdString, RTLIL::Module*> modules;
+ ...
+};
+
+struct RTLIL::Module {
+ RTLIL::IdString name;
+ std::map<RTLIL::IdString, RTLIL::Wire*> wires;
+ std::map<RTLIL::IdString, RTLIL::Cell*> cells;
+ std::vector<RTLIL::SigSig> connections;
+ ...
+};
+\end{lstlisting}
\end{frame}
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection{The RTLIL::Wire Structure}
-\subsection{RTLIL::Wire and connections}
+\begin{frame}[t, fragile]{\subsubsecname}
+Each wire in the design is represented by a {\tt RTLIL::Wire} struct:
-\begin{frame}{\subsecname}
-TBD
+\medskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+struct RTLIL::Wire {
+ RTLIL::IdString name;
+ int width, start_offset, port_id;
+ bool port_input, port_output;
+ ...
+};
+\end{lstlisting}
+
+\medskip
+\hfil\begin{tabular}{p{3cm}l}
+{\tt width} \dotfill & The total number of bits. E.g. 10 for {\tt [9:0]}. \\
+{\tt start\_offset} \dotfill & The lowest bit index. E.g. 3 for {\tt [5:3]}. \\
+{\tt port\_id} \dotfill & Zero for non-ports. Positive index for ports. \\
+{\tt port\_input} \dotfill & True for {\tt input} and {\tt inout} ports. \\
+{\tt port\_output} \dotfill & True for {\tt output} and {\tt inout} ports. \\
+\end{tabular}
\end{frame}
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection{RTLIL::State and RTLIL::Const}
+
+\begin{frame}[t, fragile]{\subsubsecname}
+The {\tt RTLIL::State} enum represents a simple 1-bit logic level:
+
+\smallskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+enum RTLIL::State {
+ S0 = 0,
+ S1 = 1,
+ Sx = 2, // undefined value or conflict
+ Sz = 3, // high-impedance / not-connected
+ Sa = 4, // don't care (used only in cases)
+ Sm = 5 // marker (used internally by some passes)
+};
+\end{lstlisting}
-\subsection{RTLIL::Cell}
+\bigskip
+The {\tt RTLIL::Const} struct represents a constant multi-bit value:
+
+\smallskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+struct RTLIL::Const {
+ std::vector<RTLIL::State> bits;
+ ...
+};
+\end{lstlisting}
-\begin{frame}{\subsecname}
-TBD
+\bigskip
+Notice that Yosys is not using special {\tt VCC} or {\tt GND} driver cells to represent constants. Instead
+constants are part of the RTLIL representation itself.
+\end{frame}
+
+\subsubsection{The RTLIL::SigSpec Structure}
+
+\begin{frame}[t, fragile]{\subsubsecname}
+The {\tt RTLIL::SigSpec} struct represents a signal vector. Each bit can either be a bit from a wire
+or a constant value. Consecutive bits from a wire or consecutive constant bits are consolidated into
+a {\tt RTLIL::SigChunk}:
+
+\bigskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+struct RTLIL::SigChunk {
+ RTLIL::Wire *wire;
+ RTLIL::Const data; // only used if wire == NULL
+ int width, offset;
+ ...
+};
+
+struct RTLIL::SigSpec {
+ std::vector<RTLIL::SigChunk> chunks; // LSB at index 0
+ int width;
+ ...
+};
+\end{lstlisting}
+
+\bigskip
+The {\tt RTLIL::SigSpec} struct has a ton of additional helper methods to compare, analyze, and
+manipulate instances of {\tt RTLIL::SigSpec}.
+\end{frame}
+
+\subsubsection{The RTLIL::Cell Structure}
+
+\begin{frame}[t, fragile]{\subsubsecname (1/2)}
+The {\tt RTLIL::Cell} struct represents an instance of a module or library cell.
+
+\smallskip
+The ports of the cell
+are associated with {\tt RTLIL::SigSpec} instances and the parameters are associated with {\tt RTLIL::Const}
+instances:
+
+\bigskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+struct RTLIL::Cell {
+ RTLIL::IdString name, type;
+ std::map<RTLIL::IdString, RTLIL::SigSpec> connections;
+ std::map<RTLIL::IdString, RTLIL::Const> parameters;
+ ...
+};
+\end{lstlisting}
+
+\bigskip
+The {\tt type} may refer to another module in the same design, a cell name from a cell library, or a
+cell name from the internal cell library:
+
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont]
+$not $pos $neg $and $or $xor $xnor $reduce_and $reduce_or $reduce_xor $reduce_xnor
+$reduce_bool $shl $shr $sshl $sshr $lt $le $eq $ne $eqx $nex $ge $gt $add $sub $mul $div $mod
+$pow $logic_not $logic_and $logic_or $mux $pmux $slice $concat $lut $assert $sr $dff
+$dffsr $adff $dlatch $dlatchsr $memrd $memwr $mem $fsm $_NOT_ $_AND_ $_OR_ $_XOR_ $_MUX_ $_SR_NN_
+$_SR_NP_ $_SR_PN_ $_SR_PP_ $_DFF_N_ $_DFF_P_ $_DFF_NN0_ $_DFF_NN1_ $_DFF_NP0_ $_DFF_NP1_ $_DFF_PN0_
+$_DFF_PN1_ $_DFF_PP0_ $_DFF_PP1_ $_DFFSR_NNN_ $_DFFSR_NNP_ $_DFFSR_NPN_ $_DFFSR_NPP_ $_DFFSR_PNN_
+$_DFFSR_PNP_ $_DFFSR_PPN_ $_DFFSR_PPP_ $_DLATCH_N_ $_DLATCH_P_ $_DLATCHSR_NNN_ $_DLATCHSR_NNP_
+$_DLATCHSR_NPN_ $_DLATCHSR_NPP_ $_DLATCHSR_PNN_ $_DLATCHSR_PNP_ $_DLATCHSR_PPN_ $_DLATCHSR_PPP_
+\end{lstlisting}
+\end{frame}
+
+\begin{frame}[t, fragile]{\subsubsecname (2/2)}
+Simulation models (i.e. {\it documentation\/} :-) for the internal cell library:
+
+\smallskip
+\hskip2em {\tt yosys/techlibs/common/simlib.v} and \\
+\hskip2em {\tt yosys/techlibs/common/simcells.v}
+
+\bigskip
+The lower-case cell types (such as {\tt \$and}) are parameterized cells of variable
+width. This so-called {\it RTL Cells\/} are the cells described in {\tt simlib.v}.
+
+\bigskip
+The upper-case cell types (such as {\tt \$\_AND\_}) are single-bit cells that are not
+parameterized. This so-called {\it Internal Logic Gates} are the cells described
+in {\tt simcells.v}.
+
+\bigskip
+The consistency checker also checks the interfaces to the internal cell library.
+If you want to use private cell types for your own purposes, use the {\tt \$\_\_}-prefix
+to avoid name collisions.
+\end{frame}
+
+\subsubsection{Connecting wires or constant drivers}
+
+\begin{frame}[t, fragile]{\subsubsecname}
+Additional connections between wires or between wires and constants are modelled using
+{\tt RTLIL::Module::connections}:
+
+\bigskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+typedef std::pair<RTLIL::SigSpec, RTLIL::SigSpec> RTLIL::SigSig;
+
+struct RTLIL::Module {
+ ...
+ std::vector<RTLIL::SigSig> connections;
+ ...
+};
+\end{lstlisting}
+
+\bigskip
+{\tt RTLIL::SigSig::first} is the driven signal and {\tt RTLIL::SigSig::second} is the driving signal.
+Example usage (setting wire {\tt foo} to value {\tt 42}):
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+module->connections.push_back(RTLIL::SigSig(module->wires.at("\\foo"),
+ RTLIL::SigSpec(42, module->wires.at("\\foo")->width)));
+\end{lstlisting}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Creating modules from scratch}
-\begin{frame}{\subsecname}
-TBD
+\begin{frame}[t, fragile]{\subsecname}
+Let's create the following module using the RTLIL API:
+
+\smallskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog]
+module absval(input signed [3:0] a, output [3:0] y);
+ assign y = a[3] ? -a : a;
+endmodule
+\end{lstlisting}
+
+\smallskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+RTLIL::Module *module = new RTLIL::Module;
+module->name = "\\absval";
+
+RTLIL::Wire *a = module->new_wire(4, "\\a");
+a->port_input = true;
+a->port_id = 1;
+
+RTLIL::Wire *y = module->new_wire(4, "\\y");
+y->port_output = true;
+y->port_id = 2;
+
+RTLIL::Wire *a_inv = module->new_wire(4, NEW_ID);
+module->addNeg(NEW_ID, a, a_inv, true);
+module->addMux(NEW_ID, a, a_inv, RTLIL::SigSpec(a, 1, 3), y);
+\end{lstlisting}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -165,39 +397,163 @@ TBD
\subsection{Modifying modules}
\begin{frame}{\subsecname}
-TBD
+Most commands modify existing modules, not create new ones.
+
+When modifying existing modules, stick to the following DOs and DON'Ts:
+
+\begin{itemize}
+\item Do not remove wires. Simply disconnect them and let a successive {\tt clean} command worry about removing it.
+
+\item Use {\tt module->fixup\_ports()} after changing the {\tt port\_*} properties of wires.
+
+\item You can safely remove cells or change the {\tt connetions} property of a cell, but be careful when
+changing the size of the {\tt SigSpec} connected to a cell port.
+
+\item Use the {\tt SigMap} helper class (see next slide) when you need a unique handle for each signal bit.
+\end{itemize}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Using the SigMap helper class}
-\begin{frame}{\subsecname}
-TBD
+\begin{frame}[t, fragile]{\subsecname}
+Consider the following module:
+
+\smallskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog]
+module test(input a, output x, y);
+ assign x = a, y = a;
+endmodule
+\end{lstlisting}
+
+In this case {\tt a}, {\tt x}, and {\tt y} are all different names for the same signal. However:
+
+\smallskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+RTLIL::SigSpec a(module->wires.at("\\a")), x(module->wires.at("\\x")),
+ y(module->wires.at("\\y"));
+log("%d %d %d\n", a == x, x == y, y == a); // will print "0 0 0"
+\end{lstlisting}
+
+The {\tt SigMap} helper class can be used to map all such aliasing signals to a
+unique signal from the group (usually the wire that is directly driven by a cell or port).
+
+\smallskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+SigMap sigmap(module);
+log("%d %d %d\n", sigmap(a) == sigmap(x), sigmap(x) == sigmap(y),
+ sigmap(y) == sigmap(a)); // will print "1 1 1"
+\end{lstlisting}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Printing log messages}
-\begin{frame}{\subsecname}
-TBD
+\begin{frame}[t, fragile]{\subsecname}
+The {\tt log()} function is a {\tt printf()}-like function that can be used to create log messages.
+
+\medskip
+Use {\tt log\_signal()} to create a C-string for a SigSpec object\footnote[frame]{The pointer returned
+by {\tt log\_signal()} is automatically freed by the log framework at a later time.}:
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+log("Mapped signal x: %s\n", log_signal(sigmap(x)));
+\end{lstlisting}
+
+\medskip
+Use {\tt RTLIL::id2cstr()} to create a C-string for an {\tt RTLIL::IdString}:
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+log("Name of this module: %s\n", RTLIL::id2cstr(module->name));
+\end{lstlisting}
+
+\medskip
+Use {\tt log\_header()} and {\tt log\_push()}/{\tt log\_pop()} to structure log messages:
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+log_header("Doing important stuff!\n");
+log_push();
+for (int i = 0; i < 10; i++)
+ log("Log message #%d.\n", i);
+log_pop();
+\end{lstlisting}
+\end{frame}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\subsection{Error handling}
+
+\begin{frame}[t, fragile]{\subsecname}
+Use {\tt log\_error()} to report a non-recoverable error:
+
+\medskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+if (design->modules.count(module->name) != 0)
+ log_error("A module with the name %s already exists!\n",
+ RTLIL::id2cstr(module->name));
+\end{lstlisting}
+
+\bigskip
+Use {\tt log\_cmd\_error()} to report a recoverable error:
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+if (design->selection_stack.back().empty())
+ log_cmd_error("This command can't operator on an empty selection!\n");
+\end{lstlisting}
+
+\bigskip
+Use {\tt log\_assert()} and {\tt log\_abort()} instead of {\tt assert()} and {\tt abort()}.
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Creating a command}
-\begin{frame}{\subsecname}
-TBD
+\begin{frame}[t, fragile]{\subsecname}
+Simply create a global instance of a class derived from {\tt Pass} to create
+a new yosys command:
+
+\bigskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+#include "kernel/rtlil.h"
+#include "kernel/register.h"
+#include "kernel/log.h"
+
+struct MyPass : public Pass {
+ MyPass() : Pass("my_cmd", "just a simple test") { }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log("Arguments to my_cmd:\n");
+ for (auto &arg : args)
+ log(" %s\n", arg.c_str());
+
+ log("Modules in current design:\n");
+ for (auto &mod : design->modules)
+ log(" %s (%zd wires, %zd cells)\n", RTLIL::id2cstr(mod.first),
+ mod.second->wires.size(), mod.second->cells.size());
+ }
+} MyPass;
+\end{lstlisting}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Creating a plugin}
-\begin{frame}{\subsecname}
-TBD
+\begin{frame}[fragile]{\subsecname}
+Yosys can be extended by adding additional C++ code to the Yosys code base, or
+by loading plugins into Yosys.
+
+\bigskip
+Use the following command to compile a Yosys plugin:
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
+yosys-config --exec --cxx --cxxflags --ldflags \
+ -o my_cmd.so -shared my_cmd.cc --ldlibs
+\end{lstlisting}
+
+\bigskip
+Load the plugin using the yosys {\tt -m} option:
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
+yosys -m ./my_cmd.so -p 'my_cmd foo bar'
+\end{lstlisting}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -206,10 +562,12 @@ TBD
\begin{frame}{\subsecname}
\begin{itemize}
-\item TBD
-\item TBD
-\item TBD
-\item TBD
+\item Writing Yosys extensions is very straight-forward.
+\item \dots and even simpler if you don't need RTLIL::Memory or RTLIL::Process objects.
+
+\bigskip
+\item Writing synthesis software? Consider learning the Yosys API and make your stuff
+part of the Yosys framework.
\end{itemize}
\bigskip
diff --git a/manual/PRESENTATION_Prog/.gitignore b/manual/PRESENTATION_Prog/.gitignore
new file mode 100644
index 00000000..7fd56076
--- /dev/null
+++ b/manual/PRESENTATION_Prog/.gitignore
@@ -0,0 +1 @@
+my_cmd.so
diff --git a/manual/PRESENTATION_Prog/Makefile b/manual/PRESENTATION_Prog/Makefile
new file mode 100644
index 00000000..794f5c12
--- /dev/null
+++ b/manual/PRESENTATION_Prog/Makefile
@@ -0,0 +1,18 @@
+
+all: test0.log test1.log test2.log
+
+my_cmd.so: my_cmd.cc
+ ../../yosys-config --exec --cxx --cxxflags --ldflags -o my_cmd.so -shared my_cmd.cc --ldlibs
+
+test0.log: my_cmd.so
+ ../../yosys -Ql test0.log_new -m ./my_cmd.so -p 'my_cmd foo bar' absval_ref.v
+ mv test0.log_new test0.log
+
+test1.log: my_cmd.so
+ ../../yosys -Ql test1.log_new -m ./my_cmd.so -p 'clean; test1; dump' absval_ref.v
+ mv test1.log_new test1.log
+
+test2.log: my_cmd.so
+ ../../yosys -Ql test2.log_new -m ./my_cmd.so -p 'test2' sigmap_test.v
+ mv test2.log_new test2.log
+
diff --git a/manual/PRESENTATION_Prog/absval_ref.v b/manual/PRESENTATION_Prog/absval_ref.v
new file mode 100644
index 00000000..ca0a115a
--- /dev/null
+++ b/manual/PRESENTATION_Prog/absval_ref.v
@@ -0,0 +1,3 @@
+module absval_ref(input signed [3:0] a, output [3:0] y);
+ assign y = a[3] ? -a : a;
+endmodule
diff --git a/manual/PRESENTATION_Prog/my_cmd.cc b/manual/PRESENTATION_Prog/my_cmd.cc
new file mode 100644
index 00000000..381b0587
--- /dev/null
+++ b/manual/PRESENTATION_Prog/my_cmd.cc
@@ -0,0 +1,71 @@
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+struct MyPass : public Pass {
+ MyPass() : Pass("my_cmd", "just a simple test") { }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log("Arguments to my_cmd:\n");
+ for (auto &arg : args)
+ log(" %s\n", arg.c_str());
+
+ log("Modules in current design:\n");
+ for (auto mod : design->modules())
+ log(" %s (%zd wires, %zd cells)\n", log_id(mod),
+ SIZE(mod->wires()), SIZE(mod->cells()));
+ }
+} MyPass;
+
+
+struct Test1Pass : public Pass {
+ Test1Pass() : Pass("test1", "creating the absval module") { }
+ virtual void execute(std::vector<std::string>, RTLIL::Design *design)
+ {
+ if (design->has("\\absval") != 0)
+ log_error("A module with the name absval already exists!\n");
+
+ RTLIL::Module *module = design->addModule("\\absval");
+
+ RTLIL::Wire *a = module->addWire("\\a", 4);
+ a->port_input = true;
+ a->port_id = 1;
+
+ RTLIL::Wire *y = module->addWire("\\y", 4);
+ y->port_output = true;
+ y->port_id = 2;
+
+ RTLIL::Wire *a_inv = module->addWire(NEW_ID, 4);
+ module->addNeg(NEW_ID, a, a_inv, true);
+ module->addMux(NEW_ID, a, a_inv, RTLIL::SigSpec(a, 3), y);
+
+ log("Name of this module: %s\n", log_id(module));
+ }
+} Test1Pass;
+
+
+struct Test2Pass : public Pass {
+ Test2Pass() : Pass("test2", "demonstrating sigmap on test module") { }
+ virtual void execute(std::vector<std::string>, RTLIL::Design *design)
+ {
+ if (design->selection_stack.back().empty())
+ log_cmd_error("This command can't operator on an empty selection!\n");
+
+ RTLIL::Module *module = design->modules_.at("\\test");
+
+ RTLIL::SigSpec a(module->wire("\\a")), x(module->wire("\\x")), y(module->wire("\\y"));
+ log("%d %d %d\n", a == x, x == y, y == a); // will print "0 0 0"
+
+ SigMap sigmap(module);
+ log("%d %d %d\n", sigmap(a) == sigmap(x), sigmap(x) == sigmap(y),
+ sigmap(y) == sigmap(a)); // will print "1 1 1"
+
+ log("Mapped signal x: %s\n", log_signal(sigmap(x)));
+
+ log_header("Doing important stuff!\n");
+ log_push();
+ for (int i = 0; i < 10; i++)
+ log("Log message #%d.\n", i);
+ log_pop();
+ }
+} Test2Pass;
+
diff --git a/manual/PRESENTATION_Prog/sigmap_test.v b/manual/PRESENTATION_Prog/sigmap_test.v
new file mode 100644
index 00000000..18dcf5eb
--- /dev/null
+++ b/manual/PRESENTATION_Prog/sigmap_test.v
@@ -0,0 +1,3 @@
+module test(input a, output x, y);
+assign x = a, y = a;
+endmodule
diff --git a/manual/clean.sh b/manual/clean.sh
index 13554c01..f4a2ea83 100755
--- a/manual/clean.sh
+++ b/manual/clean.sh
@@ -1,2 +1,2 @@
#!/bin/bash
-for f in $( find -name .gitignore ); do sed -re "s,^,find ${f%.gitignore} -name ',; s,$,' | xargs -r rm -vf,;" $f; done | bash -v
+for f in $( find . -name .gitignore ); do sed -re "s,^,find ${f%.gitignore} -name ',; s,$,' | xargs -r rm -f,;" $f; done | bash -v
diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex
index 54fec542..35249ed8 100644
--- a/manual/command-reference-manual.tex
+++ b/manual/command-reference-manual.tex
@@ -85,10 +85,10 @@ This is just a shortcut for 'select -clear'.
This is identical to 'opt_clean', but less verbose.
-When commands are seperated using the ';;' token, this command will be executed
+When commands are separated using the ';;' token, this command will be executed
between the commands.
-When commands are seperated using the ';;;' token, this command will be executed
+When commands are separated using the ';;;' token, this command will be executed
in -purge mode between the commands.
\end{lstlisting}
@@ -419,7 +419,7 @@ commands.
hierarchy [-check] [-top <module>]
hierarchy -generate <cell-types> <port-decls>
-In parametric designs, a module might exists in serveral variations with
+In parametric designs, a module might exists in several variations with
different parameter values. This pass looks at all modules in the current
design an re-runs the language frontends for the parametric modules as
needed.
@@ -881,7 +881,7 @@ The following options can be used to set up a sequential problem:
-set-def-at <N> <signal>
-set-any-undef-at <N> <signal>
-set-all-undef-at <N> <signal>
- add undef contraints in the given timestep.
+ add undef constraints in the given timestep.
-set-init <signal> <value>
set the initial value for the register driving the signal to the value
@@ -942,7 +942,7 @@ design.
-all_cell_types
Usually this command only considers internal non-memory cells. With
- this option set, all cells are considered. For unkown cells all ports
+ this option set, all cells are considered. For unknown cells all ports
are assumed to be bidirectional 'inout' ports.
-set_attr <name> <value>
@@ -1089,7 +1089,7 @@ The following actions can be performed on the top sets on the stack:
(i.e. select all cells connected to selected wires and select all
wires connected to selected cells) The rules specify which cell
ports to use for this. the syntax for a rule is a '-' for exclusion
- and a '+' for inclusion, followed by an optional comma seperated
+ and a '+' for inclusion, followed by an optional comma separated
list of cell types followed by an optional comma separated list of
cell ports in square brackets. a rule can also be just a cell or wire
name that limits the expansion (is included but does not go beyond).
@@ -1204,7 +1204,7 @@ unless another prefix is specified using -prefix <prefix>.
This pass maps a small selection of simple coarse-grain cells to yosys gate
primitives. The following internal cell types are mapped by this pass:
- $not, $pos, $bu0, $and, $or, $xor, $xnor
+ $not, $pos, $and, $or, $xor, $xnor
$reduce_and, $reduce_or, $reduce_xor, $reduce_xnor, $reduce_bool
$logic_not, $logic_and, $logic_or, $mux
$sr, $dff, $dffsr, $adff, $dlatch
@@ -1452,7 +1452,7 @@ Write the current design to an BLIF file.
-false <cell-type> <out-port>
use the specified cell types to drive nets that are constant 1 or 0
-The following options can be usefull when the generated file is not going to be
+The following options can be useful when the generated file is not going to be
read by a BLIF parser but a custom tool. It is recommended to not name the output
file *.blif when any of this options is used.
diff --git a/manual/manual.tex b/manual/manual.tex
index d6ffd95a..19d3b7b2 100644
--- a/manual/manual.tex
+++ b/manual/manual.tex
@@ -140,11 +140,11 @@ bookmarksopen=false%
\eject
\chapter*{Abstract}
-Most of todays digital design is done in HDL code (mostly Verilog or VHDL) and
+Most of today's digital design is done in HDL code (mostly Verilog or VHDL) and
with the help of HDL synthesis tools.
In special cases such as synthesis for coarse-grain cell libraries or when
-testing new synthesis algorithms it might be neccessary to write a custom HDL
+testing new synthesis algorithms it might be necessary to write a custom HDL
synthesis tool or add new features to an existing one. It this cases the
availability of a Free and Open Source (FOSS) synthesis tool that can be used
as basis for custom tools would be helpful.
@@ -158,7 +158,7 @@ by Yosys to perform advanced gate-level optimizations.
An evaluation of Yosys based on real-world designs is included. It is shown
that Yosys can be used as-is to synthesize such designs. The results produced
by Yosys in this tests where successflly verified using formal verification
-and are compareable in quality to the results produced by a commercial
+and are comparable in quality to the results produced by a commercial
synthesis tool.
\bigskip
diff --git a/manual/presentation.sh b/manual/presentation.sh
index 6771ba7c..980e1772 100755
--- a/manual/presentation.sh
+++ b/manual/presentation.sh
@@ -29,6 +29,8 @@ if ! $fast_mode; then
make -C PRESENTATION_Intro
make -C PRESENTATION_ExSyn
make -C PRESENTATION_ExAdv
+ make -C PRESENTATION_ExOth
+ make -C PRESENTATION_Prog
fi
set -ex
diff --git a/manual/presentation.tex b/manual/presentation.tex
index 35a409cb..9a876de0 100644
--- a/manual/presentation.tex
+++ b/manual/presentation.tex
@@ -81,7 +81,7 @@
\title{Yosys Open SYnthesis Suite}
\author{Clifford Wolf}
-\institute{http://www.clifford.at/}
+\institute{http://www.clifford.at/yosys/}
\usetheme{Madrid}
\usecolortheme{seagull}
@@ -102,7 +102,7 @@
\titlepage
\end{frame}
-\setcounter{section}{-2}
+\setcounter{section}{-3}
\section{Abstract}
\begin{frame}{Abstract}
@@ -122,6 +122,22 @@ non-synthesis applications (such as formal equivialence checking) and
writing extensions to Yosys using the C++ API.
\end{frame}
+\section{About me}
+\begin{frame}{About me}
+Hi! I'm Clifford Wolf.
+
+\bigskip
+I like writing open source software. For example:
+\begin{itemize}
+\item Yosys
+\item OpenSCAD (now maintained by Marius Kintel)
+\item SPL (a not very popular scripting language)
+\item EmbedVM (a very simple compiler+vm for 8 bit micros)
+\item Lib(X)SVF (a library to play SVF/XSVF files over JTAG, used at LHC)
+\item ROCK Linux (discontinued since 2010)
+\end{itemize}
+\end{frame}
+
\section{Outline}
\begin{frame}{Outline}
Yosys is an Open Source Verilog synthesis tool, and more.
@@ -133,7 +149,7 @@ Outline of this presentation:
\item Yosys by example: synthesis
\item Yosys by example: advanced synthesis
\item Yosys by example: beyond synthesis
-\item Programming Yosys extensions
+\item Writing Yosys extensions in C++
\end{itemize}
\end{frame}
diff --git a/manual/weblinks.bib b/manual/weblinks.bib
index 9b6032ed..5215a6ca 100644
--- a/manual/weblinks.bib
+++ b/manual/weblinks.bib
@@ -132,9 +132,3 @@
note = {\url{http://mattmccutchen.net/bigint/}}
}
-@misc{smallsha1,
- author = {Micael Hildenborg},
- title = {{smallsha1}},
- note = {\url{https://code.google.com/p/smallsha1/}}
-}
-
diff --git a/passes/abc/abc.cc b/passes/abc/abc.cc
index 5aa13572..f1d56b23 100644
--- a/passes/abc/abc.cc
+++ b/passes/abc/abc.cc
@@ -29,65 +29,88 @@
// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558–562, doi:10.1145/368996.369025
// http://en.wikipedia.org/wiki/Topological_sorting
-#define ABC_COMMAND_LIB "strash; retime; balance; dch; map; topo"
-#define ABC_COMMAND_CTR "strash; retime; balance; dch; map; topo; buffer; upsize; dnsize; stime"
-#define ABC_COMMAND_LUT "strash; retime; balance; dch; if"
-#define ABC_COMMAND_DFL "strash; retime; balance; dch; map"
+#define ABC_COMMAND_LIB "strash; scorr -v; ifraig -v; retime -v {D}; strash; dch -vf; map -v {D}"
+#define ABC_COMMAND_CTR "strash; scorr -v; ifraig -v; retime -v {D}; strash; dch -vf; map -v {D}; buffer -v; upsize -v {D}; dnsize -v {D}; stime -p"
+#define ABC_COMMAND_LUT "strash; scorr -v; ifraig -v; retime -v; strash; dch -vf; if -v"
+#define ABC_COMMAND_DFL "strash; scorr -v; ifraig -v; retime -v; strash; dch -vf; map -v"
+
+#define ABC_FAST_COMMAND_LIB "retime -v {D}; map -v {D}"
+#define ABC_FAST_COMMAND_CTR "retime -v {D}; map -v {D}; buffer -v; upsize -v {D}; dnsize -v {D}; stime -p"
+#define ABC_FAST_COMMAND_LUT "retime -v; if -v"
+#define ABC_FAST_COMMAND_DFL "retime -v; map -v"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <unistd.h>
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
+#include <cerrno>
#include <sstream>
+#include <climits>
#include "blifparse.h"
+enum class gate_type_t {
+ G_NONE,
+ G_FF,
+ G_NOT,
+ G_AND,
+ G_NAND,
+ G_OR,
+ G_NOR,
+ G_XOR,
+ G_XNOR,
+ G_MUX,
+ G_AOI3,
+ G_OAI3,
+ G_AOI4,
+ G_OAI4
+};
+
+#define G(_name) gate_type_t::G_ ## _name
+
struct gate_t
{
int id;
- char type;
- int in1, in2, in3;
+ gate_type_t type;
+ int in1, in2, in3, in4;
bool is_port;
- RTLIL::SigSpec sig;
+ RTLIL::SigBit bit;
};
static int map_autoidx;
static SigMap assign_map;
static RTLIL::Module *module;
static std::vector<gate_t> signal_list;
-static std::map<RTLIL::SigSpec, int> signal_map;
+static std::map<RTLIL::SigBit, int> signal_map;
static bool clk_polarity;
static RTLIL::SigSpec clk_sig;
-static int map_signal(RTLIL::SigSpec sig, char gate_type = -1, int in1 = -1, int in2 = -1, int in3 = -1)
+static int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1)
{
- assert(sig.width == 1);
- assert(sig.chunks.size() == 1);
+ assign_map.apply(bit);
- assign_map.apply(sig);
-
- if (signal_map.count(sig) == 0) {
+ if (signal_map.count(bit) == 0) {
gate_t gate;
gate.id = signal_list.size();
- gate.type = -1;
+ gate.type = G(NONE);
gate.in1 = -1;
gate.in2 = -1;
gate.in3 = -1;
+ gate.in4 = -1;
gate.is_port = false;
- gate.sig = sig;
+ gate.bit = bit;
signal_list.push_back(gate);
- signal_map[sig] = gate.id;
+ signal_map[bit] = gate.id;
}
- gate_t &gate = signal_list[signal_map[sig]];
+ gate_t &gate = signal_list[signal_map[bit]];
- if (gate_type >= 0)
+ if (gate_type != G(NONE))
gate.type = gate_type;
if (in1 >= 0)
gate.in1 = in1;
@@ -95,62 +118,64 @@ static int map_signal(RTLIL::SigSpec sig, char gate_type = -1, int in1 = -1, int
gate.in2 = in2;
if (in3 >= 0)
gate.in3 = in3;
+ if (in4 >= 0)
+ gate.in4 = in4;
return gate.id;
}
static void mark_port(RTLIL::SigSpec sig)
{
- assign_map.apply(sig);
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire != NULL && signal_map.count(c) > 0)
- signal_list[signal_map[c]].is_port = true;
- }
+ for (auto &bit : assign_map(sig))
+ if (bit.wire != NULL && signal_map.count(bit) > 0)
+ signal_list[signal_map[bit]].is_port = true;
}
-static void extract_cell(RTLIL::Cell *cell)
+static void extract_cell(RTLIL::Cell *cell, bool keepff)
{
if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
{
if (clk_polarity != (cell->type == "$_DFF_P_"))
return;
- if (clk_sig != assign_map(cell->connections["\\C"]))
+ if (clk_sig != assign_map(cell->getPort("\\C")))
return;
- RTLIL::SigSpec sig_d = cell->connections["\\D"];
- RTLIL::SigSpec sig_q = cell->connections["\\Q"];
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+
+ if (keepff)
+ for (auto &c : sig_q.chunks())
+ if (c.wire != NULL)
+ c.wire->attributes["\\keep"] = 1;
assign_map.apply(sig_d);
assign_map.apply(sig_q);
- map_signal(sig_q, 'f', map_signal(sig_d));
+ map_signal(sig_q, G(FF), map_signal(sig_d));
- module->cells.erase(cell->name);
- delete cell;
+ module->remove(cell);
return;
}
- if (cell->type == "$_INV_")
+ if (cell->type == "$_NOT_")
{
- RTLIL::SigSpec sig_a = cell->connections["\\A"];
- RTLIL::SigSpec sig_y = cell->connections["\\Y"];
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
assign_map.apply(sig_a);
assign_map.apply(sig_y);
- map_signal(sig_y, 'n', map_signal(sig_a));
+ map_signal(sig_y, G(NOT), map_signal(sig_a));
- module->cells.erase(cell->name);
- delete cell;
+ module->remove(cell);
return;
}
- if (cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_")
+ if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
{
- RTLIL::SigSpec sig_a = cell->connections["\\A"];
- RTLIL::SigSpec sig_b = cell->connections["\\B"];
- RTLIL::SigSpec sig_y = cell->connections["\\Y"];
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
assign_map.apply(sig_a);
assign_map.apply(sig_b);
@@ -160,25 +185,30 @@ static void extract_cell(RTLIL::Cell *cell)
int mapped_b = map_signal(sig_b);
if (cell->type == "$_AND_")
- map_signal(sig_y, 'a', mapped_a, mapped_b);
+ map_signal(sig_y, G(AND), mapped_a, mapped_b);
+ else if (cell->type == "$_NAND_")
+ map_signal(sig_y, G(NAND), mapped_a, mapped_b);
else if (cell->type == "$_OR_")
- map_signal(sig_y, 'o', mapped_a, mapped_b);
+ map_signal(sig_y, G(OR), mapped_a, mapped_b);
+ else if (cell->type == "$_NOR_")
+ map_signal(sig_y, G(NOR), mapped_a, mapped_b);
else if (cell->type == "$_XOR_")
- map_signal(sig_y, 'x', mapped_a, mapped_b);
+ map_signal(sig_y, G(XOR), mapped_a, mapped_b);
+ else if (cell->type == "$_XNOR_")
+ map_signal(sig_y, G(XNOR), mapped_a, mapped_b);
else
log_abort();
- module->cells.erase(cell->name);
- delete cell;
+ module->remove(cell);
return;
}
if (cell->type == "$_MUX_")
{
- RTLIL::SigSpec sig_a = cell->connections["\\A"];
- RTLIL::SigSpec sig_b = cell->connections["\\B"];
- RTLIL::SigSpec sig_s = cell->connections["\\S"];
- RTLIL::SigSpec sig_y = cell->connections["\\Y"];
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_s = cell->getPort("\\S");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
assign_map.apply(sig_a);
assign_map.apply(sig_b);
@@ -189,15 +219,61 @@ static void extract_cell(RTLIL::Cell *cell)
int mapped_b = map_signal(sig_b);
int mapped_s = map_signal(sig_s);
- map_signal(sig_y, 'm', mapped_a, mapped_b, mapped_s);
+ map_signal(sig_y, G(MUX), mapped_a, mapped_b, mapped_s);
+
+ module->remove(cell);
+ return;
+ }
+
+ if (cell->type.in("$_AOI3_", "$_OAI3_"))
+ {
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_c = cell->getPort("\\C");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+
+ assign_map.apply(sig_a);
+ assign_map.apply(sig_b);
+ assign_map.apply(sig_c);
+ assign_map.apply(sig_y);
+
+ int mapped_a = map_signal(sig_a);
+ int mapped_b = map_signal(sig_b);
+ int mapped_c = map_signal(sig_c);
+
+ map_signal(sig_y, cell->type == "$_AOI3_" ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c);
+
+ module->remove(cell);
+ return;
+ }
+
+ if (cell->type.in("$_AOI4_", "$_OAI4_"))
+ {
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_c = cell->getPort("\\C");
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+
+ assign_map.apply(sig_a);
+ assign_map.apply(sig_b);
+ assign_map.apply(sig_c);
+ assign_map.apply(sig_d);
+ assign_map.apply(sig_y);
+
+ int mapped_a = map_signal(sig_a);
+ int mapped_b = map_signal(sig_b);
+ int mapped_c = map_signal(sig_c);
+ int mapped_d = map_signal(sig_d);
+
+ map_signal(sig_y, cell->type == "$_AOI4_" ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d);
- module->cells.erase(cell->name);
- delete cell;
+ module->remove(cell);
return;
}
}
-static std::string remap_name(std::string abc_name)
+static std::string remap_name(RTLIL::IdString abc_name)
{
std::stringstream sstr;
sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1);
@@ -211,8 +287,9 @@ static void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edge
log("Dumping loop state graph to slide %d.\n", ++nr);
- fprintf(f, "digraph slide%d {\n", nr);
- fprintf(f, " rankdir=\"LR\";\n");
+ fprintf(f, "digraph \"slide%d\" {\n", nr);
+ fprintf(f, " label=\"slide%d\";\n", nr);
+ fprintf(f, " rankdir=\"TD\";\n");
std::set<int> nodes;
for (auto &e : edges) {
@@ -222,7 +299,7 @@ static void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edge
}
for (auto n : nodes)
- fprintf(f, " n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].sig),
+ fprintf(f, " n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].bit),
n, in_counts[n], workpool.count(n) ? ", shape=box" : "");
for (auto &e : edges)
@@ -248,7 +325,7 @@ static void handle_loops()
// dot_f = fopen("test.dot", "w");
for (auto &g : signal_list) {
- if (g.type == -1 || g.type == 'f') {
+ if (g.type == G(NONE) || g.type == G(FF)) {
workpool.insert(g.id);
} else {
if (g.in1 >= 0) {
@@ -263,6 +340,10 @@ static void handle_loops()
edges[g.in3].insert(g.id);
in_edges_count[g.id]++;
}
+ if (g.in4 >= 0 && g.in4 != g.in3 && g.in4 != g.in2 && g.in4 != g.in1) {
+ edges[g.in4].insert(g.id);
+ in_edges_count[g.id]++;
+ }
}
}
@@ -273,10 +354,10 @@ static void handle_loops()
int id = *workpool.begin();
workpool.erase(id);
- // log("Removing non-loop node %d from graph: %s\n", id, log_signal(signal_list[id].sig));
+ // log("Removing non-loop node %d from graph: %s\n", id, log_signal(signal_list[id].bit));
for (int id2 : edges[id]) {
- assert(in_edges_count[id2] > 0);
+ log_assert(in_edges_count[id2] > 0);
if (--in_edges_count[id2] == 0)
workpool.insert(id2);
}
@@ -293,12 +374,12 @@ static void handle_loops()
for (auto &edge_it : edges) {
int id2 = edge_it.first;
- RTLIL::Wire *w1 = signal_list[id1].sig.chunks[0].wire;
- RTLIL::Wire *w2 = signal_list[id2].sig.chunks[0].wire;
- if (w1 != NULL)
- continue;
- else if (w2 == NULL)
+ RTLIL::Wire *w1 = signal_list[id1].bit.wire;
+ RTLIL::Wire *w2 = signal_list[id2].bit.wire;
+ if (w1 == NULL)
id1 = id2;
+ else if (w2 == NULL)
+ continue;
else if (w1->name[0] == '$' && w2->name[0] == '\\')
id1 = id2;
else if (w1->name[0] == '\\' && w2->name[0] == '$')
@@ -307,7 +388,7 @@ static void handle_loops()
id1 = id2;
else if (edges[id1].size() > edges[id2].size())
continue;
- else if (w1->name > w2->name)
+ else if (w2->name.str() < w1->name.str())
id1 = id2;
}
@@ -316,27 +397,27 @@ static void handle_loops()
continue;
}
- RTLIL::Wire *wire = new RTLIL::Wire;
+ log_assert(signal_list[id1].bit.wire != NULL);
+
std::stringstream sstr;
- sstr << "$abcloop$" << (RTLIL::autoidx++);
- wire->name = sstr.str();
- module->wires[wire->name] = wire;
+ sstr << "$abcloop$" << (autoidx++);
+ RTLIL::Wire *wire = module->addWire(sstr.str());
bool first_line = true;
for (int id2 : edges[id1]) {
if (first_line)
log("Breaking loop using new signal %s: %s -> %s\n", log_signal(RTLIL::SigSpec(wire)),
- log_signal(signal_list[id1].sig), log_signal(signal_list[id2].sig));
+ log_signal(signal_list[id1].bit), log_signal(signal_list[id2].bit));
else
log(" %*s %s -> %s\n", int(strlen(log_signal(RTLIL::SigSpec(wire)))), "",
- log_signal(signal_list[id1].sig), log_signal(signal_list[id2].sig));
+ log_signal(signal_list[id1].bit), log_signal(signal_list[id2].bit));
first_line = false;
}
int id3 = map_signal(RTLIL::SigSpec(wire));
signal_list[id1].is_port = true;
signal_list[id3].is_port = true;
- assert(id3 == int(in_edges_count.size()));
+ log_assert(id3 == int(in_edges_count.size()));
in_edges_count.push_back(0);
workpool.insert(id3);
@@ -347,10 +428,12 @@ static void handle_loops()
signal_list[id2].in2 = id3;
if (signal_list[id2].in3 == id1)
signal_list[id2].in3 = id3;
+ if (signal_list[id2].in4 == id1)
+ signal_list[id2].in4 = id3;
}
edges[id1].swap(edges[id3]);
- module->connections.push_back(RTLIL::SigSig(signal_list[id3].sig, signal_list[id1].sig));
+ module->connect(RTLIL::SigSig(signal_list[id3].bit, signal_list[id1].bit));
dump_loop_graph(dot_f, dot_nr, edges, workpool, in_edges_count);
}
}
@@ -359,11 +442,55 @@ static void handle_loops()
fclose(dot_f);
}
+static std::string add_echos_to_abc_cmd(std::string str)
+{
+ std::string new_str, token;
+ for (size_t i = 0; i < str.size(); i++) {
+ token += str[i];
+ if (str[i] == ';') {
+ while (i+1 < str.size() && str[i+1] == ' ')
+ i++;
+ if (!new_str.empty())
+ new_str += "echo; ";
+ new_str += "echo + " + token + " " + token + " ";
+ token.clear();
+ }
+ }
+
+ if (!token.empty()) {
+ if (!new_str.empty())
+ new_str += "echo; echo + " + token + "; ";
+ new_str += token;
+ }
+
+ return new_str;
+}
+
+static std::string fold_abc_cmd(std::string str)
+{
+ std::string token, new_str = " ";
+ int char_counter = 10;
+
+ for (size_t i = 0; i <= str.size(); i++) {
+ if (i < str.size())
+ token += str[i];
+ if (i == str.size() || str[i] == ';') {
+ if (char_counter + token.size() > 75)
+ new_str += "\n ", char_counter = 14;
+ new_str += token, char_counter += token.size();
+ token.clear();
+ }
+ }
+
+ return new_str;
+}
+
static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
- std::string liberty_file, std::string constr_file, bool cleanup, int lut_mode, bool dff_mode, std::string clk_str)
+ std::string liberty_file, std::string constr_file, bool cleanup, int lut_mode, bool dff_mode, std::string clk_str,
+ bool keepff, std::string delay_target, bool fast_mode)
{
module = current_module;
- map_autoidx = RTLIL::autoidx++;
+ map_autoidx = autoidx++;
signal_map.clear();
signal_list.clear();
@@ -393,33 +520,48 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
} else
abc_command = stringf("source %s", script_file.c_str());
} else if (lut_mode)
- abc_command = ABC_COMMAND_LUT;
+ abc_command = fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
else if (!liberty_file.empty())
- abc_command = constr_file.empty() ? ABC_COMMAND_LIB : ABC_COMMAND_CTR;
+ abc_command = constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
else
- abc_command = ABC_COMMAND_DFL;
+ abc_command = fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
+
+ for (size_t pos = abc_command.find("{D}"); pos != std::string::npos; pos = abc_command.find("{D}", pos))
+ abc_command = abc_command.substr(0, pos) + delay_target + abc_command.substr(pos+3);
+
+ abc_command = add_echos_to_abc_cmd(abc_command);
+
+ if (abc_command.size() > 128) {
+ for (size_t i = 0; i+1 < abc_command.size(); i++)
+ if (abc_command[i] == ';' && abc_command[i+1] == ' ')
+ abc_command[i+1] = '\n';
+ FILE *f = fopen(stringf("%s/abc.script", tempdir_name).c_str(), "wt");
+ fprintf(f, "%s\n", abc_command.c_str());
+ fclose(f);
+ abc_command = stringf("source %s/abc.script", tempdir_name);
+ }
if (clk_str.empty()) {
if (clk_str[0] == '!') {
clk_polarity = false;
clk_str = clk_str.substr(1);
}
- if (module->wires.count(RTLIL::escape_id(clk_str)) != 0)
- clk_sig = assign_map(RTLIL::SigSpec(module->wires.at(RTLIL::escape_id(clk_str)), 1));
+ if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0)
+ clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
}
- if (dff_mode && clk_sig.width == 0)
+ if (dff_mode && clk_sig.size() == 0)
{
int best_dff_counter = 0;
std::map<std::pair<bool, RTLIL::SigSpec>, int> dff_counters;
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
RTLIL::Cell *cell = it.second;
if (cell->type != "$_DFF_N_" && cell->type != "$_DFF_P_")
continue;
- std::pair<bool, RTLIL::SigSpec> key(cell->type == "$_DFF_P_", assign_map(cell->connections.at("\\C")));
+ std::pair<bool, RTLIL::SigSpec> key(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")));
if (++dff_counters[key] > best_dff_counter) {
best_dff_counter = dff_counters[key];
clk_polarity = key.first;
@@ -429,30 +571,30 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (dff_mode || !clk_str.empty()) {
- if (clk_sig.width == 0)
+ if (clk_sig.size() == 0)
log("No (matching) clock domain found. Not extracting any FF cells.\n");
else
log("Found (matching) %s clock domain: %s\n", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
}
- if (clk_sig.width != 0)
+ if (clk_sig.size() != 0)
mark_port(clk_sig);
std::vector<RTLIL::Cell*> cells;
- cells.reserve(module->cells.size());
- for (auto &it : module->cells)
+ cells.reserve(module->cells_.size());
+ for (auto &it : module->cells_)
if (design->selected(current_module, it.second))
cells.push_back(it.second);
for (auto c : cells)
- extract_cell(c);
+ extract_cell(c, keepff);
- for (auto &wire_it : module->wires) {
+ for (auto &wire_it : module->wires_) {
if (wire_it.second->port_id > 0 || wire_it.second->get_bool_attribute("\\keep"))
mark_port(RTLIL::SigSpec(wire_it.second));
}
- for (auto &cell_it : module->cells)
- for (auto &port_it : cell_it.second->connections)
+ for (auto &cell_it : module->cells_)
+ for (auto &port_it : cell_it.second->connections())
mark_port(port_it.second);
handle_loops();
@@ -468,17 +610,19 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
int count_input = 0;
fprintf(f, ".inputs");
for (auto &si : signal_list) {
- if (!si.is_port || si.type >= 0)
+ if (!si.is_port || si.type != G(NONE))
continue;
fprintf(f, " n%d", si.id);
count_input++;
}
+ if (count_input == 0)
+ fprintf(f, " dummy_input\n");
fprintf(f, "\n");
int count_output = 0;
fprintf(f, ".outputs");
for (auto &si : signal_list) {
- if (!si.is_port || si.type < 0)
+ if (!si.is_port || si.type == G(NONE))
continue;
fprintf(f, " n%d", si.id);
count_output++;
@@ -486,42 +630,70 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
fprintf(f, "\n");
for (auto &si : signal_list)
- fprintf(f, "# n%-5d %s\n", si.id, log_signal(si.sig));
+ fprintf(f, "# n%-5d %s\n", si.id, log_signal(si.bit));
for (auto &si : signal_list) {
- assert(si.sig.width == 1 && si.sig.chunks.size() == 1);
- if (si.sig.chunks[0].wire == NULL) {
+ if (si.bit.wire == NULL) {
fprintf(f, ".names n%d\n", si.id);
- if (si.sig.chunks[0].data.bits[0] == RTLIL::State::S1)
+ if (si.bit == RTLIL::State::S1)
fprintf(f, "1\n");
}
}
int count_gates = 0;
for (auto &si : signal_list) {
- if (si.type == 'n') {
+ if (si.type == G(NOT)) {
fprintf(f, ".names n%d n%d\n", si.in1, si.id);
fprintf(f, "0 1\n");
- } else if (si.type == 'a') {
+ } else if (si.type == G(AND)) {
fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
fprintf(f, "11 1\n");
- } else if (si.type == 'o') {
+ } else if (si.type == G(NAND)) {
+ fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, "0- 1\n");
+ fprintf(f, "-0 1\n");
+ } else if (si.type == G(OR)) {
fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
fprintf(f, "-1 1\n");
fprintf(f, "1- 1\n");
- } else if (si.type == 'x') {
+ } else if (si.type == G(NOR)) {
+ fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, "00 1\n");
+ } else if (si.type == G(XOR)) {
fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
fprintf(f, "01 1\n");
fprintf(f, "10 1\n");
- } else if (si.type == 'm') {
+ } else if (si.type == G(XNOR)) {
+ fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, "00 1\n");
+ fprintf(f, "11 1\n");
+ } else if (si.type == G(MUX)) {
fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
fprintf(f, "1-0 1\n");
fprintf(f, "-11 1\n");
- } else if (si.type == 'f') {
+ } else if (si.type == G(AOI3)) {
+ fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
+ fprintf(f, "-00 1\n");
+ fprintf(f, "0-0 1\n");
+ } else if (si.type == G(OAI3)) {
+ fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
+ fprintf(f, "00- 1\n");
+ fprintf(f, "--0 1\n");
+ } else if (si.type == G(AOI4)) {
+ fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
+ fprintf(f, "-0-0 1\n");
+ fprintf(f, "-00- 1\n");
+ fprintf(f, "0--0 1\n");
+ fprintf(f, "0-0- 1\n");
+ } else if (si.type == G(OAI4)) {
+ fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
+ fprintf(f, "00-- 1\n");
+ fprintf(f, "--00 1\n");
+ } else if (si.type == G(FF)) {
fprintf(f, ".latch n%d n%d\n", si.in1, si.id);
- } else if (si.type >= 0)
+ } else if (si.type != G(NONE))
log_abort();
- if (si.type >= 0)
+ if (si.type != G(NONE))
count_gates++;
}
@@ -543,11 +715,18 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
fprintf(f, "GATE ONE 1 Y=CONST1;\n");
fprintf(f, "GATE BUF 1 Y=A; PIN * NONINV 1 999 1 0 1 0\n");
- fprintf(f, "GATE INV 1 Y=!A; PIN * INV 1 999 1 0 1 0\n");
+ fprintf(f, "GATE NOT 1 Y=!A; PIN * INV 1 999 1 0 1 0\n");
fprintf(f, "GATE AND 1 Y=A*B; PIN * NONINV 1 999 1 0 1 0\n");
+ fprintf(f, "GATE NAND 1 Y=!(A*B); PIN * INV 1 999 1 0 1 0\n");
fprintf(f, "GATE OR 1 Y=A+B; PIN * NONINV 1 999 1 0 1 0\n");
+ fprintf(f, "GATE NOR 1 Y=!(A+B); PIN * INV 1 999 1 0 1 0\n");
fprintf(f, "GATE XOR 1 Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n");
+ fprintf(f, "GATE XNOR 1 Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n");
fprintf(f, "GATE MUX 1 Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n");
+ fprintf(f, "GATE AOI3 1 Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n");
+ fprintf(f, "GATE OAI3 1 Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n");
+ fprintf(f, "GATE AOI4 1 Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n");
+ fprintf(f, "GATE OAI4 1 Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n");
fclose(f);
free(p);
@@ -564,10 +743,10 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
std::string buffer;
if (!liberty_file.empty()) {
- buffer += stringf("%s -s -c 'read_blif %s/input.blif; read_lib %s; ",
+ buffer += stringf("%s -s -c 'read_blif %s/input.blif; read_lib -w %s; ",
exe_file.c_str(), tempdir_name, liberty_file.c_str());
if (!constr_file.empty())
- buffer += stringf("read_constr %s; ", constr_file.c_str());
+ buffer += stringf("read_constr -v %s; ", constr_file.c_str());
buffer += abc_command + "; ";
} else
if (lut_mode)
@@ -578,13 +757,53 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
exe_file.c_str(), tempdir_name, tempdir_name, abc_command.c_str());
buffer += stringf("write_blif %s/output.blif' 2>&1", tempdir_name);
+ log("%s\n", buffer.c_str());
+
errno = ENOMEM; // popen does not set errno if memory allocation fails, therefore set it by hand
f = popen(buffer.c_str(), "r");
if (f == NULL)
log_error("Opening pipe to `%s' for reading failed: %s\n", buffer.c_str(), strerror(errno));
+#if 0
char logbuf[1024];
while (fgets(logbuf, 1024, f) != NULL)
log("ABC: %s", logbuf);
+#else
+ bool got_cr = false;
+ int escape_seq_state = 0;
+ std::string linebuf;
+ char logbuf[1024];
+ while (fgets(logbuf, 1024, f) != NULL)
+ for (char *p = logbuf; *p; p++) {
+ if (escape_seq_state == 0 && *p == '\033') {
+ escape_seq_state = 1;
+ continue;
+ }
+ if (escape_seq_state == 1) {
+ escape_seq_state = *p == '[' ? 2 : 0;
+ continue;
+ }
+ if (escape_seq_state == 2) {
+ if ((*p < '0' || '9' < *p) && *p != ';')
+ escape_seq_state = 0;
+ continue;
+ }
+ escape_seq_state = 0;
+ if (*p == '\r') {
+ got_cr = true;
+ continue;
+ }
+ if (*p == '\n') {
+ log("ABC: %s\n", linebuf.c_str());
+ got_cr = false, linebuf.clear();
+ continue;
+ }
+ if (got_cr)
+ got_cr = false, linebuf.clear();
+ linebuf += *p;
+ }
+ if (!linebuf.empty())
+ log("ABC: %s\n", linebuf.c_str());
+#endif
errno = 0;
int ret = pclose(f);
if (ret < 0)
@@ -609,79 +828,84 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
free(p);
log_header("Re-integrating ABC results.\n");
- RTLIL::Module *mapped_mod = mapped_design->modules["\\netlist"];
+ RTLIL::Module *mapped_mod = mapped_design->modules_["\\netlist"];
if (mapped_mod == NULL)
log_error("ABC output file does not contain a module `netlist'.\n");
- for (auto &it : mapped_mod->wires) {
+ for (auto &it : mapped_mod->wires_) {
RTLIL::Wire *w = it.second;
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = remap_name(w->name);
- module->wires[wire->name] = wire;
+ RTLIL::Wire *wire = module->addWire(remap_name(w->name));
design->select(module, wire);
}
std::map<std::string, int> cell_stats;
if (builtin_lib)
{
- for (auto &it : mapped_mod->cells) {
+ for (auto &it : mapped_mod->cells_) {
RTLIL::Cell *c = it.second;
cell_stats[RTLIL::unescape_id(c->type)]++;
if (c->type == "\\ZERO" || c->type == "\\ONE") {
RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]);
conn.second = RTLIL::SigSpec(c->type == "\\ZERO" ? 0 : 1, 1);
- module->connections.push_back(conn);
+ module->connect(conn);
continue;
}
if (c->type == "\\BUF") {
RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
- conn.second = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
- module->connections.push_back(conn);
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]);
+ conn.second = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]);
+ module->connect(conn);
continue;
}
- if (c->type == "\\INV") {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->type = "$_INV_";
- cell->name = remap_name(c->name);
- cell->connections["\\A"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
- cell->connections["\\Y"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
- module->cells[cell->name] = cell;
+ if (c->type == "\\NOT") {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_NOT_");
+ cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
+ cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
design->select(module, cell);
continue;
}
- if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR") {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->type = "$_" + c->type.substr(1) + "_";
- cell->name = remap_name(c->name);
- cell->connections["\\A"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
- cell->connections["\\B"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\B"].chunks[0].wire->name)]);
- cell->connections["\\Y"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
- module->cells[cell->name] = cell;
+ if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR" || c->type == "\\NAND" || c->type == "\\NOR" || c->type == "\\XNOR") {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
+ cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
+ cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
+ cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
design->select(module, cell);
continue;
}
if (c->type == "\\MUX") {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->type = "$_MUX_";
- cell->name = remap_name(c->name);
- cell->connections["\\A"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
- cell->connections["\\B"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\B"].chunks[0].wire->name)]);
- cell->connections["\\S"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\S"].chunks[0].wire->name)]);
- cell->connections["\\Y"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
- module->cells[cell->name] = cell;
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX_");
+ cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
+ cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
+ cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)]));
+ cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
+ design->select(module, cell);
+ continue;
+ }
+ if (c->type == "\\AOI3" || c->type == "\\OAI3") {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
+ cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
+ cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
+ cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
+ cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
+ design->select(module, cell);
+ continue;
+ }
+ if (c->type == "\\AOI4" || c->type == "\\OAI4") {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
+ cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
+ cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
+ cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
+ cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
+ cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
design->select(module, cell);
continue;
}
if (c->type == "\\DFF") {
- log_assert(clk_sig.width == 1);
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->type = clk_polarity ? "$_DFF_P_" : "$_DFF_N_";
- cell->name = remap_name(c->name);
- cell->connections["\\D"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\D"].chunks[0].wire->name)]);
- cell->connections["\\Q"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Q"].chunks[0].wire->name)]);
- cell->connections["\\C"] = clk_sig;
- module->cells[cell->name] = cell;
+ log_assert(clk_sig.size() == 1);
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
+ cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
+ cell->setPort("\\C", clk_sig);
design->select(module, cell);
continue;
}
@@ -690,54 +914,48 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
else
{
- for (auto &it : mapped_mod->cells)
+ for (auto &it : mapped_mod->cells_)
{
RTLIL::Cell *c = it.second;
cell_stats[RTLIL::unescape_id(c->type)]++;
if (c->type == "\\_const0_" || c->type == "\\_const1_") {
RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires[remap_name(c->connections.begin()->second.chunks[0].wire->name)]);
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->connections().begin()->second.as_wire()->name)]);
conn.second = RTLIL::SigSpec(c->type == "\\_const0_" ? 0 : 1, 1);
- module->connections.push_back(conn);
+ module->connect(conn);
continue;
}
if (c->type == "\\_dff_") {
- log_assert(clk_sig.width == 1);
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->type = clk_polarity ? "$_DFF_P_" : "$_DFF_N_";
- cell->name = remap_name(c->name);
- cell->connections["\\D"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\D"].chunks[0].wire->name)]);
- cell->connections["\\Q"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Q"].chunks[0].wire->name)]);
- cell->connections["\\C"] = clk_sig;
- module->cells[cell->name] = cell;
+ log_assert(clk_sig.size() == 1);
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
+ cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
+ cell->setPort("\\C", clk_sig);
design->select(module, cell);
continue;
}
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->type = c->type;
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type);
cell->parameters = c->parameters;
- cell->name = remap_name(c->name);
- for (auto &conn : c->connections) {
+ for (auto &conn : c->connections()) {
RTLIL::SigSpec newsig;
- for (auto &c : conn.second.chunks) {
+ for (auto &c : conn.second.chunks()) {
if (c.width == 0)
continue;
- assert(c.width == 1);
- newsig.append(module->wires[remap_name(c.wire->name)]);
+ log_assert(c.width == 1);
+ newsig.append(module->wires_[remap_name(c.wire->name)]);
}
- cell->connections[conn.first] = newsig;
+ cell->setPort(conn.first, newsig);
}
- module->cells[cell->name] = cell;
design->select(module, cell);
}
}
- for (auto conn : mapped_mod->connections) {
+ for (auto conn : mapped_mod->connections()) {
if (!conn.first.is_fully_const())
- conn.first = RTLIL::SigSpec(module->wires[remap_name(conn.first.chunks[0].wire->name)]);
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(conn.first.as_wire()->name)]);
if (!conn.second.is_fully_const())
- conn.second = RTLIL::SigSpec(module->wires[remap_name(conn.second.chunks[0].wire->name)]);
- module->connections.push_back(conn);
+ conn.second = RTLIL::SigSpec(module->wires_[remap_name(conn.second.as_wire()->name)]);
+ module->connect(conn);
}
for (auto &it : cell_stats)
@@ -748,16 +966,16 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
char buffer[100];
snprintf(buffer, 100, "\\n%d", si.id);
RTLIL::SigSig conn;
- if (si.type >= 0) {
- conn.first = si.sig;
- conn.second = RTLIL::SigSpec(module->wires[remap_name(buffer)]);
+ if (si.type != G(NONE)) {
+ conn.first = si.bit;
+ conn.second = RTLIL::SigSpec(module->wires_[remap_name(buffer)]);
out_wires++;
} else {
- conn.first = RTLIL::SigSpec(module->wires[remap_name(buffer)]);
- conn.second = si.sig;
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(buffer)]);
+ conn.second = si.bit;
in_wires++;
}
- module->connections.push_back(conn);
+ module->connect(conn);
}
log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
log("ABC RESULTS: input signals: %8d\n", in_wires);
@@ -776,7 +994,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
struct dirent **namelist;
int n = scandir(tempdir_name, &namelist, 0, alphasort);
- assert(n >= 0);
+ log_assert(n >= 0);
for (int i = 0; i < n; i++) {
if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) {
if (asprintf(&p, "%s/%s", tempdir_name, namelist[i]->d_name) < 0) log_abort();
@@ -820,16 +1038,32 @@ struct AbcPass : public Pass {
log(" if no -script parameter is given, the following scripts are used:\n");
log("\n");
log(" for -liberty without -constr:\n");
- log(" %s\n", ABC_COMMAND_LIB);
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_LIB).c_str());
+ log("\n");
+ log(" for -liberty with -constr:\n");
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str());
+ log("\n");
+ log(" for -lut:\n");
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str());
+ log("\n");
+ log(" otherwise:\n");
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_DFL).c_str());
+ log("\n");
+ log(" -fast\n");
+ log(" use different default scripts that are slightly faster (at the cost\n");
+ log(" of output quality):\n");
+ log("\n");
+ log(" for -liberty without -constr:\n");
+ log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LIB).c_str());
log("\n");
log(" for -liberty with -constr:\n");
- log(" %s\n", ABC_COMMAND_CTR);
+ log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_CTR).c_str());
log("\n");
log(" for -lut:\n");
- log(" %s\n", ABC_COMMAND_LUT);
+ log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LUT).c_str());
log("\n");
log(" otherwise:\n");
- log(" %s\n", ABC_COMMAND_DFL);
+ log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_DFL).c_str());
log("\n");
log(" -liberty <file>\n");
log(" generate netlists for the specified cell library (using the liberty\n");
@@ -838,6 +1072,18 @@ struct AbcPass : public Pass {
log(" -constr <file>\n");
log(" pass this file with timing constraints to ABC. use with -liberty.\n");
log("\n");
+ log(" a constr file contains two lines:\n");
+ log(" set_driving_cell <cell_name>\n");
+ log(" set_load <floating_point_number>\n");
+ log("\n");
+ log(" the set_driving_cell statement defines which cell type is assumed to\n");
+ log(" drive the primary inputs and the set_load statement sets the load in\n");
+ log(" femtofarads for each primary output.\n");
+ log("\n");
+ log(" -D <picoseconds>\n");
+ log(" set delay target. the string {D} in the default scripts above is\n");
+ log(" replaced by this option when used, and an empty string otherwise.\n");
+ log("\n");
log(" -lut <width>\n");
log(" generate netlist using luts of (max) the specified width.\n");
log("\n");
@@ -851,6 +1097,10 @@ struct AbcPass : public Pass {
log(" with -dff, then it falls back to the automatic dection of clock domain\n");
log(" if the specified clock is not found in a module.)\n");
log("\n");
+ log(" -keepff\n");
+ log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
+ log(" them, for example for equivialence checking.)\n");
+ log("\n");
log(" -nocleanup\n");
log(" when this option is used, the temporary files created by this pass\n");
log(" are not removed. this is useful for debugging.\n");
@@ -869,13 +1119,17 @@ struct AbcPass : public Pass {
log_header("Executing ABC pass (technology mapping using ABC).\n");
log_push();
- std::string exe_file = rewrite_yosys_exe("yosys-abc");
- std::string script_file, liberty_file, constr_file, clk_str;
- bool dff_mode = false, cleanup = true;
+ std::string exe_file = proc_self_dirname() + "yosys-abc";
+ std::string script_file, liberty_file, constr_file, clk_str, delay_target;
+ bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
int lut_mode = 0;
size_t argidx;
- char *pwd = get_current_dir_name();
+ char pwd [PATH_MAX];
+ if (!getcwd(pwd, sizeof(pwd))) {
+ log_cmd_error("getcwd failed: %s\n", strerror(errno));
+ log_abort();
+ }
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-exe" && argidx+1 < args.size()) {
@@ -900,10 +1154,18 @@ struct AbcPass : public Pass {
constr_file = std::string(pwd) + "/" + constr_file;
continue;
}
+ if (arg == "-D" && argidx+1 < args.size()) {
+ delay_target = "-D " + args[++argidx];
+ continue;
+ }
if (arg == "-lut" && argidx+1 < args.size()) {
lut_mode = atoi(args[++argidx].c_str());
continue;
}
+ if (arg == "-fast") {
+ fast_mode = true;
+ continue;
+ }
if (arg == "-dff") {
dff_mode = true;
continue;
@@ -912,13 +1174,16 @@ struct AbcPass : public Pass {
clk_str = args[++argidx];
continue;
}
+ if (arg == "-keepff") {
+ keepff = true;
+ continue;
+ }
if (arg == "-nocleanup") {
cleanup = false;
continue;
}
break;
}
- free(pwd);
extra_args(args, argidx, design);
if (lut_mode != 0 && !liberty_file.empty())
@@ -926,12 +1191,12 @@ struct AbcPass : public Pass {
if (!constr_file.empty() && liberty_file.empty())
log_cmd_error("Got -constr but no -liberty!\n");
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second)) {
if (mod_it.second->processes.size() > 0)
log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
else
- abc_module(design, mod_it.second, script_file, exe_file, liberty_file, constr_file, cleanup, lut_mode, dff_mode, clk_str);
+ abc_module(design, mod_it.second, script_file, exe_file, liberty_file, constr_file, cleanup, lut_mode, dff_mode, clk_str, keepff, delay_target, fast_mode);
}
assign_map.clear();
diff --git a/passes/abc/blifparse.cc b/passes/abc/blifparse.cc
index 2d46d1a8..1fbb5720 100644
--- a/passes/abc/blifparse.cc
+++ b/passes/abc/blifparse.cc
@@ -40,7 +40,7 @@ static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count,
}
if (buffer_len == 0 || buffer[buffer_len-1] == '\\') {
- if (buffer[buffer_len-1] == '\\')
+ if (buffer_len > 0 && buffer[buffer_len-1] == '\\')
buffer[--buffer_len] = 0;
line_count++;
if (fgets(buffer+buffer_len, buffer_size-buffer_len, f) == NULL)
@@ -58,9 +58,8 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
RTLIL::Const *lutptr = NULL;
RTLIL::State lut_default_state = RTLIL::State::Sx;
- int port_count = 0;
module->name = "\\netlist";
- design->modules[module->name] = module;
+ design->add(module);
size_t buffer_size = 4096;
char *buffer = (char*)malloc(buffer_size);
@@ -91,6 +90,7 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
continue;
if (!strcmp(cmd, ".end")) {
+ module->fixup_ports();
free(buffer);
return design;
}
@@ -98,14 +98,11 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
if (!strcmp(cmd, ".inputs") || !strcmp(cmd, ".outputs")) {
char *p;
while ((p = strtok(NULL, " \t\r\n")) != NULL) {
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = stringf("\\%s", p);
- wire->port_id = ++port_count;
+ RTLIL::Wire *wire = module->addWire(stringf("\\%s", p));
if (!strcmp(cmd, ".inputs"))
wire->port_input = true;
else
wire->port_output = true;
- module->add(wire);
}
continue;
}
@@ -115,49 +112,34 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
char *d = strtok(NULL, " \t\r\n");
char *q = strtok(NULL, " \t\r\n");
- if (module->wires.count(RTLIL::escape_id(d)) == 0) {
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = RTLIL::escape_id(d);
- module->add(wire);
- }
+ if (module->wires_.count(RTLIL::escape_id(d)) == 0)
+ module->addWire(RTLIL::escape_id(d));
- if (module->wires.count(RTLIL::escape_id(q)) == 0) {
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = RTLIL::escape_id(q);
- module->add(wire);
- }
+ if (module->wires_.count(RTLIL::escape_id(q)) == 0)
+ module->addWire(RTLIL::escape_id(q));
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = dff_name;
- cell->connections["\\D"] = module->wires.at(RTLIL::escape_id(d));
- cell->connections["\\Q"] = module->wires.at(RTLIL::escape_id(q));
- module->add(cell);
+ RTLIL::Cell *cell = module->addCell(NEW_ID, dff_name);
+ cell->setPort("\\D", module->wires_.at(RTLIL::escape_id(d)));
+ cell->setPort("\\Q", module->wires_.at(RTLIL::escape_id(q)));
continue;
}
if (!strcmp(cmd, ".gate"))
{
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- module->add(cell);
-
char *p = strtok(NULL, " \t\r\n");
if (p == NULL)
goto error;
- cell->type = RTLIL::escape_id(p);
+
+ RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(p));
while ((p = strtok(NULL, " \t\r\n")) != NULL) {
char *q = strchr(p, '=');
if (q == NULL || !q[0] || !q[1])
goto error;
*(q++) = 0;
- if (module->wires.count(RTLIL::escape_id(q)) == 0) {
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = RTLIL::escape_id(q);
- module->add(wire);
- }
- cell->connections[RTLIL::escape_id(p)] = module->wires.at(RTLIL::escape_id(q));
+ if (module->wires_.count(RTLIL::escape_id(q)) == 0)
+ module->addWire(RTLIL::escape_id(q));
+ cell->setPort(RTLIL::escape_id(p), module->wires_.at(RTLIL::escape_id(q)));
}
continue;
}
@@ -168,19 +150,17 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
RTLIL::SigSpec input_sig, output_sig;
while ((p = strtok(NULL, " \t\r\n")) != NULL) {
RTLIL::Wire *wire;
- if (module->wires.count(stringf("\\%s", p)) > 0) {
- wire = module->wires.at(stringf("\\%s", p));
+ if (module->wires_.count(stringf("\\%s", p)) > 0) {
+ wire = module->wires_.at(stringf("\\%s", p));
} else {
- wire = new RTLIL::Wire;
- wire->name = stringf("\\%s", p);
- module->add(wire);
+ wire = module->addWire(stringf("\\%s", p));
}
input_sig.append(wire);
}
- output_sig = input_sig.extract(input_sig.width-1, 1);
- input_sig = input_sig.extract(0, input_sig.width-1);
+ output_sig = input_sig.extract(input_sig.size()-1, 1);
+ input_sig = input_sig.extract(0, input_sig.size()-1);
- if (input_sig.width == 0) {
+ if (input_sig.size() == 0) {
RTLIL::State state = RTLIL::State::Sa;
while (1) {
if (!read_next_line(buffer, buffer_size, line_count, f))
@@ -208,23 +188,17 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
finished_parsing_constval:
if (state == RTLIL::State::Sa)
state = RTLIL::State::S1;
- module->connections.push_back(RTLIL::SigSig(output_sig, state));
+ module->connect(RTLIL::SigSig(output_sig, state));
goto continue_without_read;
}
- input_sig.optimize();
- output_sig.optimize();
-
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$lut";
- cell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.width);
- cell->parameters["\\LUT"] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.width);
- cell->connections["\\I"] = input_sig;
- cell->connections["\\O"] = output_sig;
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$lut");
+ cell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size());
+ cell->parameters["\\LUT"] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.size());
+ cell->setPort("\\A", input_sig);
+ cell->setPort("\\Y", output_sig);
lutptr = &cell->parameters.at("\\LUT");
lut_default_state = RTLIL::State::Sx;
- module->add(cell);
continue;
}
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index f01a1c4b..eba61d1d 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -15,4 +15,10 @@ OBJS += passes/cmds/copy.o
OBJS += passes/cmds/splice.o
OBJS += passes/cmds/scc.o
OBJS += passes/cmds/log.o
+OBJS += passes/cmds/tee.o
+OBJS += passes/cmds/write_file.o
+OBJS += passes/cmds/connwrappers.o
+OBJS += passes/cmds/cover.o
+OBJS += passes/cmds/trace.o
+OBJS += passes/cmds/plugin.o
diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc
index acee4c46..e3fde855 100644
--- a/passes/cmds/add.cc
+++ b/passes/cmds/add.cc
@@ -28,8 +28,8 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
if (module->count_id(name) != 0)
{
- if (module->wires.count(name) > 0)
- wire = module->wires.at(name);
+ if (module->wires_.count(name) > 0)
+ wire = module->wires_.at(name);
if (wire != NULL && wire->width != width)
wire = NULL;
@@ -47,15 +47,12 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
}
else
{
- wire = new RTLIL::Wire;
- wire->name = name;
- wire->width = width;
+ wire = module->addWire(name, width);
wire->port_input = flag_input;
wire->port_output = flag_output;
- module->add(wire);
if (flag_input || flag_output) {
- wire->port_id = module->wires.size();
+ wire->port_id = module->wires_.size();
module->fixup_ports();
}
@@ -65,20 +62,20 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
if (!flag_global)
return;
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
- if (design->modules.count(it.second->type) == 0)
+ if (design->modules_.count(it.second->type) == 0)
continue;
- RTLIL::Module *mod = design->modules.at(it.second->type);
+ RTLIL::Module *mod = design->modules_.at(it.second->type);
if (!design->selected_whole_module(mod->name))
continue;
if (mod->get_bool_attribute("\\blackbox"))
continue;
- if (it.second->connections.count(name) > 0)
+ if (it.second->hasPort(name))
continue;
- it.second->connections[name] = wire;
+ it.second->setPort(name, wire);
log("Added connection %s to cell %s.%s (%s).\n", name.c_str(), module->name.c_str(), it.first.c_str(), it.second->type.c_str());
}
}
@@ -139,7 +136,7 @@ struct AddPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod : design->modules)
+ for (auto &mod : design->modules_)
{
RTLIL::Module *module = mod.second;
if (!design->selected_whole_module(module->name))
diff --git a/passes/cmds/connect.cc b/passes/cmds/connect.cc
index 7da2b951..30c80f73 100644
--- a/passes/cmds/connect.cc
+++ b/passes/cmds/connect.cc
@@ -27,14 +27,14 @@ static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap &
{
CellTypes ct(design);
- RTLIL::Wire *dummy_wire = module->new_wire(sig.width, NEW_ID);
+ RTLIL::Wire *dummy_wire = module->addWire(NEW_ID, sig.size());
- for (auto &it : module->cells)
- for (auto &port : it.second->connections)
+ for (auto &it : module->cells_)
+ for (auto &port : it.second->connections_)
if (ct.cell_output(it.second->type, port.first))
sigmap(port.second).replace(sig, dummy_wire, &port.second);
- for (auto &conn : module->connections)
+ for (auto &conn : module->connections_)
sigmap(conn.first).replace(sig, dummy_wire, &conn.first);
}
@@ -75,7 +75,7 @@ struct ConnectPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
RTLIL::Module *module = NULL;
- for (auto &it : design->modules) {
+ for (auto &it : design->modules_) {
if (!design->selected(it.second))
continue;
if (module != NULL)
@@ -123,7 +123,7 @@ struct ConnectPass : public Pass {
SigMap sigmap;
if (!flag_nomap)
- for (auto &it : module->connections) {
+ for (auto &it : module->connections()) {
std::vector<RTLIL::SigBit> lhs = it.first.to_sigbit_vector();
std::vector<RTLIL::SigBit> rhs = it.first.to_sigbit_vector();
for (size_t i = 0; i < lhs.size(); i++)
@@ -148,7 +148,7 @@ struct ConnectPass : public Pass {
if (!flag_nounset)
unset_drivers(design, module, sigmap, sig_lhs);
- module->connections.push_back(RTLIL::SigSig(sig_lhs, sig_rhs));
+ module->connect(RTLIL::SigSig(sig_lhs, sig_rhs));
}
else
if (!unset_expr.empty())
@@ -169,14 +169,14 @@ struct ConnectPass : public Pass {
if (flag_nounset)
log_cmd_error("Cant use -port together with -nounset.\n");
- if (module->cells.count(RTLIL::escape_id(port_cell)) == 0)
+ if (module->cells_.count(RTLIL::escape_id(port_cell)) == 0)
log_cmd_error("Can't find cell %s.\n", port_cell.c_str());
RTLIL::SigSpec sig;
if (!RTLIL::SigSpec::parse_sel(sig, design, module, port_expr))
log_cmd_error("Failed to parse port expression `%s'.\n", port_expr.c_str());
- module->cells.at(RTLIL::escape_id(port_cell))->connections[RTLIL::escape_id(port_port)] = sigmap(sig);
+ module->cells_.at(RTLIL::escape_id(port_cell))->setPort(RTLIL::escape_id(port_port), sigmap(sig));
}
else
log_cmd_error("Expected -set, -unset, or -port.\n");
diff --git a/passes/cmds/connwrappers.cc b/passes/cmds/connwrappers.cc
new file mode 100644
index 00000000..aac11716
--- /dev/null
+++ b/passes/cmds/connwrappers.cc
@@ -0,0 +1,205 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+struct ConnwrappersWorker
+{
+ struct portdecl_t {
+ // key: celltype, portname;
+ std::string widthparam, signparam;
+ bool is_signed;
+ };
+
+ std::set<RTLIL::IdString> decl_celltypes;
+ std::map<std::pair<RTLIL::IdString, RTLIL::IdString>, portdecl_t> decls;
+
+ void add_port(std::string celltype, std::string portname, std::string widthparam, std::string signparam)
+ {
+ std::pair<std::string, std::string> key(RTLIL::escape_id(celltype), RTLIL::escape_id(portname));
+ decl_celltypes.insert(key.first);
+
+ if (decls.count(key))
+ log_cmd_error("Duplicate port decl: %s %s\n", celltype.c_str(), portname.c_str());
+
+ portdecl_t decl;
+ decl.widthparam = RTLIL::escape_id(widthparam);
+ decl.signparam = RTLIL::escape_id(signparam);
+ decl.is_signed = false;
+ decls[key] = decl;
+ }
+
+ void add_port(std::string celltype, std::string portname, std::string widthparam, bool is_signed)
+ {
+ std::pair<std::string, std::string> key(RTLIL::escape_id(celltype), RTLIL::escape_id(portname));
+ decl_celltypes.insert(key.first);
+
+ if (decls.count(key))
+ log_cmd_error("Duplicate port decl: %s %s\n", celltype.c_str(), portname.c_str());
+
+ portdecl_t decl;
+ decl.widthparam = RTLIL::escape_id(widthparam);
+ decl.is_signed = is_signed;
+ decls[key] = decl;
+ }
+
+ void work(RTLIL::Design *design, RTLIL::Module *module)
+ {
+ std::map<RTLIL::SigBit, std::pair<bool, RTLIL::SigSpec>> extend_map;
+ SigMap sigmap(module);
+
+ for (auto &it : module->cells_)
+ {
+ RTLIL::Cell *cell = it.second;
+
+ if (!decl_celltypes.count(cell->type))
+ continue;
+
+ for (auto &conn : cell->connections())
+ {
+ std::pair<RTLIL::IdString, RTLIL::IdString> key(cell->type, conn.first);
+
+ if (!decls.count(key))
+ continue;
+
+ portdecl_t &decl = decls.at(key);
+
+ if (!cell->parameters.count(decl.widthparam))
+ continue;
+
+ if (!decl.signparam.empty() && !cell->parameters.count(decl.signparam))
+ continue;
+
+ int inner_width = cell->parameters.at(decl.widthparam).as_int();
+ int outer_width = conn.second.size();
+ bool is_signed = decl.signparam.empty() ? decl.is_signed : cell->parameters.at(decl.signparam).as_bool();
+
+ if (inner_width >= outer_width)
+ continue;
+
+ RTLIL::SigSpec sig = sigmap(conn.second);
+ extend_map[sig.extract(inner_width - 1, 1)] = std::pair<bool, RTLIL::SigSpec>(is_signed,
+ sig.extract(inner_width, outer_width - inner_width));
+ }
+ }
+
+ for (auto &it : module->cells_)
+ {
+ RTLIL::Cell *cell = it.second;
+
+ if (!design->selected(module, cell))
+ continue;
+
+ for (auto &conn : cell->connections_)
+ {
+ std::vector<RTLIL::SigBit> sigbits = sigmap(conn.second).to_sigbit_vector();
+ RTLIL::SigSpec old_sig;
+
+ for (size_t i = 0; i < sigbits.size(); i++)
+ {
+ if (!extend_map.count(sigbits[i]))
+ continue;
+
+ bool is_signed = extend_map.at(sigbits[i]).first;
+ RTLIL::SigSpec extend_sig = extend_map.at(sigbits[i]).second;
+
+ int extend_width = 0;
+ RTLIL::SigBit extend_bit = is_signed ? sigbits[i] : RTLIL::SigBit(RTLIL::State::S0);
+ while (extend_width < extend_sig.size() && i + extend_width + 1 < sigbits.size() &&
+ sigbits[i + extend_width + 1] == extend_bit) extend_width++;
+
+ if (extend_width == 0)
+ continue;
+
+ if (old_sig.size() == 0)
+ old_sig = conn.second;
+
+ conn.second.replace(i+1, extend_sig.extract(0, extend_width));
+ i += extend_width;
+ }
+
+ if (old_sig.size())
+ log("Connected extended bits of %s.%s:%s: %s -> %s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name),
+ RTLIL::id2cstr(conn.first), log_signal(old_sig), log_signal(conn.second));
+ }
+ }
+ }
+};
+
+struct ConnwrappersPass : public Pass {
+ ConnwrappersPass() : Pass("connwrappers", "replace undef values with defined constants") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" connwrappers [options] [selection]\n");
+ log("\n");
+ log("Wrappers are used in coarse-grain synthesis to wrap cells with smaller ports\n");
+ log("in wrapper cells with a (larger) constant port size. I.e. the upper bits\n");
+ log("of the wrapper outut are signed/unsigned bit extended. This command uses this\n");
+ log("knowlege to rewire the inputs of the driven cells to match the output of\n");
+ log("the driving cell.\n");
+ log("\n");
+ log(" -signed <cell_type> <port_name> <width_param>\n");
+ log(" -unsigned <cell_type> <port_name> <width_param>\n");
+ log(" consider the specified signed/unsigned wrapper output\n");
+ log("\n");
+ log(" -port <cell_type> <port_name> <width_param> <sign_param>\n");
+ log(" use the specified parameter to decide if signed or unsigned\n");
+ log("\n");
+ log("The options -signed, -unsigned, and -port can be specified multiple times.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ ConnwrappersWorker worker;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-signed" && argidx+3 < args.size()) {
+ worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], true);
+ argidx += 3;
+ continue;
+ }
+ if (args[argidx] == "-unsigned" && argidx+3 < args.size()) {
+ worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], false);
+ argidx += 3;
+ continue;
+ }
+ if (args[argidx] == "-port" && argidx+4 < args.size()) {
+ worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], args[argidx+4]);
+ argidx += 4;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ log_header("Executing CONNWRAPPERS pass (connect extended ports of wrapper cells).\n");
+
+ for (auto &mod_it : design->modules_)
+ if (design->selected(mod_it.second))
+ worker.work(design, mod_it.second);
+ }
+} ConnwrappersPass;
+
diff --git a/passes/cmds/copy.cc b/passes/cmds/copy.cc
index 4b1a8db8..be775820 100644
--- a/passes/cmds/copy.cc
+++ b/passes/cmds/copy.cc
@@ -41,14 +41,15 @@ struct CopyPass : public Pass {
std::string src_name = RTLIL::escape_id(args[1]);
std::string trg_name = RTLIL::escape_id(args[2]);
- if (design->modules.count(src_name) == 0)
+ if (design->modules_.count(src_name) == 0)
log_cmd_error("Can't find source module %s.\n", src_name.c_str());
- if (design->modules.count(trg_name) != 0)
+ if (design->modules_.count(trg_name) != 0)
log_cmd_error("Target module name %s already exists.\n", trg_name.c_str());
- design->modules[trg_name] = design->modules.at(src_name)->clone();
- design->modules[trg_name]->name = trg_name;
+ RTLIL::Module *new_mod = design->module(src_name)->clone();
+ new_mod->name = trg_name;
+ design->add(new_mod);
}
} CopyPass;
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
new file mode 100644
index 00000000..ac72ba53
--- /dev/null
+++ b/passes/cmds/cover.cc
@@ -0,0 +1,144 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fnmatch.h>
+
+#include "kernel/register.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+struct CoverPass : public Pass {
+ CoverPass() : Pass("cover", "print code coverage counters") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" cover [options] [pattern]\n");
+ log("\n");
+ log("Print the code coverage counters collected using the cover() macro in the Yosys\n");
+ log("C++ code. This is useful to figure out what parts of Yosys are utilized by a\n");
+ log("test bench.\n");
+ log("\n");
+ log(" -q\n");
+ log(" Do not print output to the normal destination (console and/or log file)\n");
+ log("\n");
+ log(" -o file\n");
+ log(" Write output to this file, truncate if exists.\n");
+ log("\n");
+ log(" -a file\n");
+ log(" Write output to this file, append if exists.\n");
+ log("\n");
+ log(" -d dir\n");
+ log(" Write output to a newly created file in the specified directory.\n");
+ log("\n");
+ log("When one or more pattern (shell wildcards) are specified, then only counters\n");
+ log("matching at least one pattern are printed.\n");
+ log("\n");
+ log("\n");
+ log("It is also possible to instruct Yosys to print the coverage counters on program\n");
+ log("exit to a file using environment variables:\n");
+ log("\n");
+ log(" YOSYS_COVER_DIR=\"{dir-name}\" yosys {args}\n");
+ log("\n");
+ log(" This will create a file (with an auto-generated name) in this\n");
+ log(" directory and write the coverage counters to it.\n");
+ log("\n");
+ log(" YOSYS_COVER_FILE=\"{file-name}\" yosys {args}\n");
+ log("\n");
+ log(" This will append the coverage counters to the specified file.\n");
+ log("\n");
+ log("\n");
+ log("Hint: Use the following AWK command to consolidate Yosys coverage files:\n");
+ log("\n");
+ log(" gawk '{ p[$3] = $1; c[$3] += $2; } END { for (i in p)\n");
+ log(" printf \"%%-60s %%10d %%s\\n\", p[i], c[i], i; }' {files} | sort -k3\n");
+ log("\n");
+ log("\n");
+ log("Coverage counters are only available in debug builds of Yosys for Linux.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ std::vector<FILE*> out_files;
+ std::vector<std::string> patterns;
+ bool do_log = true;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-q") {
+ do_log = false;
+ continue;
+ }
+ if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) {
+ const char *open_mode = args[argidx] == "-a" ? "a+" : "w";
+ std::string filename = args[++argidx];
+ if (args[argidx-1] == "-d") {
+ char filename_buffer[4096];
+ snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid());
+ filename = mkstemps(filename_buffer, 4);
+ }
+ FILE *f = fopen(filename.c_str(), open_mode);
+ if (f == NULL) {
+ for (auto f : out_files)
+ fclose(f);
+ log_cmd_error("Can't create file %s.\n", args[argidx].c_str());
+ }
+ out_files.push_back(f);
+ continue;
+ }
+ break;
+ }
+ while (argidx < args.size() && args[argidx].substr(0, 1) != "-")
+ patterns.push_back(args[argidx++]);
+ extra_args(args, argidx, design);
+
+ if (do_log) {
+ log_header("Printing code coverage counters.\n");
+ log("\n");
+ }
+
+#ifdef COVER_ACTIVE
+ for (auto &it : get_coverage_data()) {
+ if (!patterns.empty()) {
+ for (auto &p : patterns)
+ if (!fnmatch(p.c_str(), it.first.c_str(), 0))
+ goto pattern_match;
+ continue;
+ }
+ pattern_match:
+ for (auto f : out_files)
+ fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str());
+ if (do_log)
+ log("%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str());
+ }
+#else
+ for (auto f : out_files)
+ fclose(f);
+
+ log_cmd_error("Coverage counters are only available in debug builds of Yosys for Linux.\n");
+#endif
+
+ for (auto f : out_files)
+ fclose(f);
+ }
+} CoverPass;
+
diff --git a/passes/cmds/delete.cc b/passes/cmds/delete.cc
index 1c02752c..2a91bc9e 100644
--- a/passes/cmds/delete.cc
+++ b/passes/cmds/delete.cc
@@ -21,21 +21,6 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
-struct DeleteWireWorker
-{
- RTLIL::Module *module;
- std::set<std::string> *delete_wires_p;
-
- void operator()(RTLIL::SigSpec &sig) {
- sig.optimize();
- for (auto &c : sig.chunks)
- if (c.wire != NULL && delete_wires_p->count(c.wire->name)) {
- c.wire = module->new_wire(c.width, NEW_ID);
- c.offset = 0;
- }
- }
-};
-
struct DeletePass : public Pass {
DeletePass() : Pass("delete", "delete objects in the design") { }
virtual void help()
@@ -79,9 +64,9 @@ struct DeletePass : public Pass {
}
extra_args(args, argidx, design);
- std::vector<std::string> delete_mods;
+ std::vector<RTLIL::IdString> delete_mods;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (design->selected_whole_module(mod_it.first) && !flag_input && !flag_output) {
delete_mods.push_back(mod_it.first);
@@ -94,7 +79,7 @@ struct DeletePass : public Pass {
RTLIL::Module *module = mod_it.second;
if (flag_input || flag_output) {
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (design->selected(module, it.second)) {
if (flag_input)
it.second->port_input = false;
@@ -105,62 +90,52 @@ struct DeletePass : public Pass {
continue;
}
- std::set<std::string> delete_wires;
- std::set<std::string> delete_cells;
- std::set<std::string> delete_procs;
- std::set<std::string> delete_mems;
+ std::set<RTLIL::Wire*> delete_wires;
+ std::set<RTLIL::Cell*> delete_cells;
+ std::set<RTLIL::IdString> delete_procs;
+ std::set<RTLIL::IdString> delete_mems;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (design->selected(module, it.second))
- delete_wires.insert(it.first);
+ delete_wires.insert(it.second);
for (auto &it : module->memories)
if (design->selected(module, it.second))
delete_mems.insert(it.first);
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (design->selected(module, it.second))
- delete_cells.insert(it.first);
+ delete_cells.insert(it.second);
if ((it.second->type == "$memrd" || it.second->type == "$memwr") &&
delete_mems.count(it.second->parameters.at("\\MEMID").decode_string()) != 0)
- delete_cells.insert(it.first);
+ delete_cells.insert(it.second);
}
for (auto &it : module->processes)
if (design->selected(module, it.second))
delete_procs.insert(it.first);
- DeleteWireWorker delete_wire_worker;
- delete_wire_worker.module = module;
- delete_wire_worker.delete_wires_p = &delete_wires;
- module->rewrite_sigspecs(delete_wire_worker);
-
- for (auto &it : delete_wires) {
- delete module->wires.at(it);
- module->wires.erase(it);
- }
-
for (auto &it : delete_mems) {
delete module->memories.at(it);
module->memories.erase(it);
}
- for (auto &it : delete_cells) {
- delete module->cells.at(it);
- module->cells.erase(it);
- }
+ for (auto &it : delete_cells)
+ module->remove(it);
for (auto &it : delete_procs) {
delete module->processes.at(it);
module->processes.erase(it);
}
+ module->remove(delete_wires);
+
module->fixup_ports();
}
for (auto &it : delete_mods) {
- delete design->modules.at(it);
- design->modules.erase(it);
+ delete design->modules_.at(it);
+ design->modules_.erase(it);
}
}
} DeletePass;
diff --git a/passes/cmds/design.cc b/passes/cmds/design.cc
index 80a6c073..9f800c31 100644
--- a/passes/cmds/design.cc
+++ b/passes/cmds/design.cc
@@ -22,13 +22,20 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+YOSYS_NAMESPACE_BEGIN
+
+std::map<std::string, RTLIL::Design*> saved_designs;
+std::vector<RTLIL::Design*> pushed_designs;
+
struct DesignPass : public Pass {
DesignPass() : Pass("design", "save, restore and reset current design") { }
- std::map<std::string, RTLIL::Design*> saved_designs;
virtual ~DesignPass() {
for (auto &it : saved_designs)
delete it.second;
saved_designs.clear();
+ for (auto &it : pushed_designs)
+ delete it;
+ pushed_designs.clear();
}
virtual void help()
{
@@ -49,6 +56,16 @@ struct DesignPass : public Pass {
log("Save the current design under the given name and then clear the current design.\n");
log("\n");
log("\n");
+ log(" design -push\n");
+ log("\n");
+ log("Push the current design to the stack and then clear the current design.\n");
+ log("\n");
+ log("\n");
+ log(" design -pop\n");
+ log("\n");
+ log("Reset the current design and pop the last design from the stack.\n");
+ log("\n");
+ log("\n");
log(" design -load <name>\n");
log("\n");
log("Reset the current design and load the design previously saved under the given\n");
@@ -70,6 +87,8 @@ struct DesignPass : public Pass {
{
bool got_mode = false;
bool reset_mode = false;
+ bool push_mode = false;
+ bool pop_mode = false;
RTLIL::Design *copy_from_design = NULL, *copy_to_design = NULL;
std::string save_name, load_name, as_name;
std::vector<RTLIL::Module*> copy_src_modules;
@@ -83,6 +102,16 @@ struct DesignPass : public Pass {
reset_mode = true;
continue;
}
+ if (!got_mode && args[argidx] == "-push") {
+ got_mode = true;
+ push_mode = true;
+ continue;
+ }
+ if (!got_mode && args[argidx] == "-pop") {
+ got_mode = true;
+ pop_mode = true;
+ continue;
+ }
if (!got_mode && args[argidx] == "-save" && argidx+1 < args.size()) {
got_mode = true;
save_name = args[++argidx];
@@ -138,7 +167,7 @@ struct DesignPass : public Pass {
argidx = args.size();
}
- for (auto &it : copy_from_design->modules) {
+ for (auto &it : copy_from_design->modules_) {
if (sel.selected_whole_module(it.first)) {
copy_src_modules.push_back(it.second);
continue;
@@ -151,7 +180,10 @@ struct DesignPass : public Pass {
extra_args(args, argidx, design, false);
if (!got_mode)
- cmd_error(args, argidx, "Missing mode argument (-reset, -save, -load, -copy-from, or -copy-to).");
+ cmd_error(args, argidx, "Missing mode argument.");
+
+ if (pop_mode && pushed_designs.empty())
+ log_cmd_error("No pushed designs.\n");
if (copy_to_design != NULL)
{
@@ -160,21 +192,22 @@ struct DesignPass : public Pass {
for (auto mod : copy_src_modules)
{
- std::string trg_name = as_name.empty() ? mod->name : RTLIL::escape_id(as_name);
+ std::string trg_name = as_name.empty() ? mod->name.str() : RTLIL::escape_id(as_name);
- if (copy_to_design->modules.count(trg_name))
- delete copy_to_design->modules.at(trg_name);
- copy_to_design->modules[trg_name] = mod->clone();
- copy_to_design->modules[trg_name]->name = trg_name;
+ if (copy_to_design->modules_.count(trg_name))
+ delete copy_to_design->modules_.at(trg_name);
+ copy_to_design->modules_[trg_name] = mod->clone();
+ copy_to_design->modules_[trg_name]->name = trg_name;
+ copy_to_design->modules_[trg_name]->design = copy_to_design;
}
}
- if (!save_name.empty())
+ if (!save_name.empty() || push_mode)
{
RTLIL::Design *design_copy = new RTLIL::Design;
- for (auto &it : design->modules)
- design_copy->modules[it.first] = it.second->clone();
+ for (auto &it : design->modules_)
+ design_copy->add(it.second->clone());
design_copy->selection_stack = design->selection_stack;
design_copy->selection_vars = design->selection_vars;
@@ -182,14 +215,18 @@ struct DesignPass : public Pass {
if (saved_designs.count(save_name))
delete saved_designs.at(save_name);
- saved_designs[save_name] = design_copy;
+
+ if (push_mode)
+ pushed_designs.push_back(design_copy);
+ else
+ saved_designs[save_name] = design_copy;
}
- if (reset_mode || !load_name.empty())
+ if (reset_mode || !load_name.empty() || push_mode || pop_mode)
{
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
delete it.second;
- design->modules.clear();
+ design->modules_.clear();
design->selection_stack.clear();
design->selection_vars.clear();
@@ -198,12 +235,15 @@ struct DesignPass : public Pass {
design->selection_stack.push_back(RTLIL::Selection());
}
- if (!load_name.empty())
+ if (!load_name.empty() || pop_mode)
{
- RTLIL::Design *saved_design = saved_designs.at(load_name);
+ RTLIL::Design *saved_design = pop_mode ? pushed_designs.back() : saved_designs.at(load_name);
+
+ if (pop_mode)
+ pushed_designs.pop_back();
- for (auto &it : saved_design->modules)
- design->modules[it.first] = it.second->clone();
+ for (auto &it : saved_design->modules_)
+ design->add(it.second->clone());
design->selection_stack = saved_design->selection_stack;
design->selection_vars = saved_design->selection_vars;
@@ -211,4 +251,6 @@ struct DesignPass : public Pass {
}
}
} DesignPass;
-
+
+YOSYS_NAMESPACE_END
+
diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc
new file mode 100644
index 00000000..4e8234d1
--- /dev/null
+++ b/passes/cmds/plugin.cc
@@ -0,0 +1,124 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+
+#ifdef YOSYS_ENABLE_PLUGINS
+# include <dlfcn.h>
+#endif
+
+YOSYS_NAMESPACE_BEGIN
+
+std::map<std::string, void*> loaded_plugins;
+std::map<std::string, std::string> loaded_plugin_aliases;
+
+void load_plugin(std::string filename, std::vector<std::string> aliases)
+{
+#ifdef YOSYS_ENABLE_PLUGINS
+ if (filename.find('/') == std::string::npos)
+ filename = "./" + filename;
+
+ if (!loaded_plugins.count(filename)) {
+ void *hdl = dlopen(filename.c_str(), RTLD_LAZY|RTLD_LOCAL);
+ if (hdl == NULL)
+ log_cmd_error("Can't load module `%s': %s\n", filename.c_str(), dlerror());
+ loaded_plugins[filename] = hdl;
+ Pass::init_register();
+ }
+
+ for (auto &alias : aliases)
+ loaded_plugin_aliases[alias] = filename;
+#else
+ log_error("This version of yosys is built without plugin support.\n");
+#endif
+}
+
+struct PluginPass : public Pass {
+ PluginPass() : Pass("plugin", "load and list loaded plugins") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" plugin [options]\n");
+ log("\n");
+ log("Load and list loaded plugins.\n");
+ log("\n");
+ log(" -i <plugin_filename>\n");
+ log(" Load (install) the specified plugin.\n");
+ log("\n");
+ log(" -a <alias_name>\n");
+ log(" Register the specified alias name for the loaded plugin\n");
+ log("\n");
+ log(" -l\n");
+ log(" List loaded plugins\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ std::string plugin_filename;
+ std::vector<std::string> plugin_aliases;
+ bool list_mode = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if ((args[argidx] == "-i") && argidx+1 < args.size() && plugin_filename.empty()) {
+ plugin_filename = args[++argidx];
+ continue;
+ }
+ if ((args[argidx] == "-a") && argidx+1 < args.size()) {
+ plugin_aliases.push_back(args[++argidx]);
+ continue;
+ }
+ if (args[argidx] == "-l") {
+ list_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design, false);
+
+ if (!plugin_filename.empty())
+ load_plugin(plugin_filename, plugin_aliases);
+
+ if (list_mode)
+ {
+ log("\n");
+ if (loaded_plugins.empty())
+ log("No plugins loaded.\n");
+ else
+ log("Loaded plugins:\n");
+
+ for (auto &it : loaded_plugins)
+ log(" %s\n", it.first.c_str());
+
+ if (!loaded_plugin_aliases.empty()) {
+ log("\n");
+ int max_alias_len = 1;
+ for (auto &it : loaded_plugin_aliases)
+ max_alias_len = std::max(max_alias_len, SIZE(it.first));
+ for (auto &it : loaded_plugin_aliases)
+ log("Alias: %-*s %s\n", max_alias_len, it.first.c_str(), it.second.c_str());
+ }
+ }
+ }
+} PluginPass;
+
+YOSYS_NAMESPACE_END
+
diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc
index 519dce45..91de364f 100644
--- a/passes/cmds/rename.cc
+++ b/passes/cmds/rename.cc
@@ -29,23 +29,17 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
if (module->count_id(to_name))
log_cmd_error("There is already an object `%s' in module `%s'.\n", to_name.c_str(), module->name.c_str());
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.first == from_name) {
- RTLIL::Wire *wire = it.second;
- log("Renaming wire %s to %s in module %s.\n", wire->name.c_str(), to_name.c_str(), module->name.c_str());
- module->wires.erase(wire->name);
- wire->name = to_name;
- module->add(wire);
+ log("Renaming wire %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
+ module->rename(it.second, to_name);
return;
}
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
if (it.first == from_name) {
- RTLIL::Cell *cell = it.second;
- log("Renaming cell %s to %s in module %s.\n", cell->name.c_str(), to_name.c_str(), module->name.c_str());
- module->cells.erase(cell->name);
- cell->name = to_name;
- module->add(cell);
+ log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
+ module->rename(it.second, to_name);
return;
}
@@ -64,10 +58,12 @@ struct RenamePass : public Pass {
log("by this command.\n");
log("\n");
log("\n");
- log(" rename -enumerate [selection]\n");
+ log(" rename -enumerate [-pattern <pattern>] [selection]\n");
log("\n");
log("Assign short auto-generated names to all selected wires and cells with private\n");
- log("names.\n");
+ log("names. The -pattern option can be used to set the pattern for the new names.\n");
+ log("The character %% in the pattern is replaced with a integer number. The default\n");
+ log("pattern is '_%%_'.\n");
log("\n");
log(" rename -hide [selection]\n");
log("\n");
@@ -77,6 +73,7 @@ struct RenamePass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
+ std::string pattern_prefix = "_", pattern_suffix = "_";
bool flag_enumerate = false;
bool flag_hide = false;
bool got_mode = false;
@@ -95,6 +92,12 @@ struct RenamePass : public Pass {
got_mode = true;
continue;
}
+ if (arg == "-pattern" && argidx+1 < args.size() && args[argidx+1].find('%') != std::string::npos) {
+ int pos = args[++argidx].find('%');
+ pattern_prefix = args[argidx].substr(0, pos);
+ pattern_suffix = args[argidx].substr(pos+1);
+ continue;
+ }
break;
}
@@ -102,7 +105,7 @@ struct RenamePass : public Pass {
{
extra_args(args, argidx, design);
- for (auto &mod : design->modules)
+ for (auto &mod : design->modules_)
{
int counter = 0;
@@ -111,22 +114,22 @@ struct RenamePass : public Pass {
continue;
std::map<RTLIL::IdString, RTLIL::Wire*> new_wires;
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
if (it.first[0] == '$' && design->selected(module, it.second))
- do it.second->name = stringf("\\_%d_", counter++);
+ do it.second->name = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
while (module->count_id(it.second->name) > 0);
new_wires[it.second->name] = it.second;
}
- module->wires.swap(new_wires);
+ module->wires_.swap(new_wires);
std::map<RTLIL::IdString, RTLIL::Cell*> new_cells;
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (it.first[0] == '$' && design->selected(module, it.second))
- do it.second->name = stringf("\\_%d_", counter++);
+ do it.second->name = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
while (module->count_id(it.second->name) > 0);
new_cells[it.second->name] = it.second;
}
- module->cells.swap(new_cells);
+ module->cells_.swap(new_cells);
}
}
else
@@ -134,29 +137,29 @@ struct RenamePass : public Pass {
{
extra_args(args, argidx, design);
- for (auto &mod : design->modules)
+ for (auto &mod : design->modules_)
{
RTLIL::Module *module = mod.second;
if (!design->selected(module))
continue;
std::map<RTLIL::IdString, RTLIL::Wire*> new_wires;
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
if (design->selected(module, it.second))
if (it.first[0] == '\\' && it.second->port_id == 0)
it.second->name = NEW_ID;
new_wires[it.second->name] = it.second;
}
- module->wires.swap(new_wires);
+ module->wires_.swap(new_wires);
std::map<RTLIL::IdString, RTLIL::Cell*> new_cells;
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (design->selected(module, it.second))
if (it.first[0] == '\\')
it.second->name = NEW_ID;
new_cells[it.second->name] = it.second;
}
- module->cells.swap(new_cells);
+ module->cells_.swap(new_cells);
}
}
else
@@ -169,19 +172,19 @@ struct RenamePass : public Pass {
if (!design->selected_active_module.empty())
{
- if (design->modules.count(design->selected_active_module) > 0)
- rename_in_module(design->modules.at(design->selected_active_module), from_name, to_name);
+ if (design->modules_.count(design->selected_active_module) > 0)
+ rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name);
}
else
{
- for (auto &mod : design->modules) {
+ for (auto &mod : design->modules_) {
if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) {
to_name = RTLIL::escape_id(to_name);
log("Renaming module %s to %s.\n", mod.first.c_str(), to_name.c_str());
RTLIL::Module *module = mod.second;
- design->modules.erase(module->name);
+ design->modules_.erase(module->name);
module->name = to_name;
- design->modules[module->name] = module;
+ design->modules_[module->name] = module;
goto rename_ok;
}
}
diff --git a/passes/cmds/scatter.cc b/passes/cmds/scatter.cc
index e5f78830..e09c0012 100644
--- a/passes/cmds/scatter.cc
+++ b/passes/cmds/scatter.cc
@@ -43,25 +43,22 @@ struct ScatterPass : public Pass {
CellTypes ct(design);
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (!design->selected(mod_it.second))
continue;
- for (auto &c : mod_it.second->cells)
- for (auto &p : c.second->connections)
+ for (auto &c : mod_it.second->cells_)
+ for (auto &p : c.second->connections_)
{
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = NEW_ID;
- wire->width = p.second.width;
- mod_it.second->add(wire);
+ RTLIL::Wire *wire = mod_it.second->addWire(NEW_ID, p.second.size());
if (ct.cell_output(c.second->type, p.first)) {
RTLIL::SigSig sigsig(p.second, wire);
- mod_it.second->connections.push_back(sigsig);
+ mod_it.second->connect(sigsig);
} else {
RTLIL::SigSig sigsig(wire, p.second);
- mod_it.second->connections.push_back(sigsig);
+ mod_it.second->connect(sigsig);
}
p.second = wire;
diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc
index f8c351a4..5224f5bc 100644
--- a/passes/cmds/scc.cc
+++ b/passes/cmds/scc.cc
@@ -51,7 +51,7 @@ struct SccWorker
void run(RTLIL::Cell *cell, int depth, int maxDepth)
{
- assert(workQueue.count(cell) > 0);
+ log_assert(workQueue.count(cell) > 0);
workQueue.erase(cell);
cellLabels[cell] = std::pair<int, int>(labelCounter, labelCounter);
@@ -114,11 +114,11 @@ struct SccWorker
SigPool selectedSignals;
SigSet<RTLIL::Cell*> sigToNextCells;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (design->selected(module, it.second))
selectedSignals.add(sigmap(RTLIL::SigSpec(it.second)));
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
RTLIL::Cell *cell = it.second;
@@ -132,7 +132,7 @@ struct SccWorker
RTLIL::SigSpec inputSignals, outputSignals;
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
{
bool isInput = true, isOutput = true;
@@ -166,7 +166,7 @@ struct SccWorker
while (workQueue.size() > 0) {
RTLIL::Cell *cell = *workQueue.begin();
- assert(cellStack.size() == 0);
+ log_assert(cellStack.size() == 0);
cellDepth.clear();
run(cell, 0, maxDepth);
}
@@ -191,7 +191,7 @@ struct SccWorker
nextsig.sort_and_unify();
sig = prevsig.extract(nextsig);
- for (auto &chunk : sig.chunks)
+ for (auto &chunk : sig.chunks())
if (chunk.wire != NULL)
sel.selected_members[module->name].insert(chunk.wire->name);
}
@@ -216,7 +216,7 @@ struct SccPass : public Pass {
log("\n");
log(" -all_cell_types\n");
log(" Usually this command only considers internal non-memory cells. With\n");
- log(" this option set, all cells are considered. For unkown cells all ports\n");
+ log(" this option set, all cells are considered. For unknown cells all ports\n");
log(" are assumed to be bidirectional 'inout' ports.\n");
log("\n");
log(" -set_attr <name> <value>\n");
@@ -280,7 +280,7 @@ struct SccPass : public Pass {
RTLIL::Selection newSelection(false);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
{
SccWorker worker(design, mod_it.second, allCellTypes, maxDepth);
@@ -290,7 +290,7 @@ struct SccPass : public Pass {
}
if (selectMode) {
- assert(origSelectPos >= 0);
+ log_assert(origSelectPos >= 0);
design->selection_stack[origSelectPos] = newSelection;
design->selection_stack[origSelectPos].optimize(design);
}
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index a1a64f14..4c540ca6 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -23,6 +23,7 @@
#include "kernel/log.h"
#include <string.h>
#include <fnmatch.h>
+#include <errno.h>
using RTLIL::id2cstr;
@@ -63,6 +64,8 @@ static bool match_attr_val(const RTLIL::Const &value, std::string pattern, char
if (match_op == '=')
return value == pattern_value;
+ if (match_op == '!')
+ return value != pattern_value;
if (match_op == '<')
return value.as_int() < pattern_value.as_int();
if (match_op == '>')
@@ -82,6 +85,8 @@ static bool match_attr_val(const RTLIL::Const &value, std::string pattern, char
if (match_op == '=')
return value_str == pattern;
+ if (match_op == '!')
+ return value_str != pattern;
if (match_op == '<')
return value_str < pattern;
if (match_op == '>')
@@ -115,9 +120,11 @@ static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes
static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes, std::string match_expr)
{
- size_t pos = match_expr.find_first_of("<=>");
+ size_t pos = match_expr.find_first_of("<!=>");
if (pos != std::string::npos) {
+ if (match_expr.substr(pos, 2) == "!=")
+ return match_attr(attributes, match_expr.substr(0, pos), match_expr.substr(pos+2), '!');
if (match_expr.substr(pos, 2) == "<=")
return match_attr(attributes, match_expr.substr(0, pos), match_expr.substr(pos+2), '[');
if (match_expr.substr(pos, 2) == ">=")
@@ -144,7 +151,7 @@ static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs)
RTLIL::Selection new_sel(false);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (lhs.selected_whole_module(mod_it.first))
continue;
@@ -154,13 +161,13 @@ static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs)
}
RTLIL::Module *mod = mod_it.second;
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (!lhs.selected_member(mod_it.first, it.first))
new_sel.selected_members[mod->name].insert(it.first);
for (auto &it : mod->memories)
if (!lhs.selected_member(mod_it.first, it.first))
new_sel.selected_members[mod->name].insert(it.first);
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
if (!lhs.selected_member(mod_it.first, it.first))
new_sel.selected_members[mod->name].insert(it.first);
for (auto &it : mod->processes)
@@ -174,13 +181,13 @@ static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs)
static void select_op_submod(RTLIL::Design *design, RTLIL::Selection &lhs)
{
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (lhs.selected_whole_module(mod_it.first))
{
- for (auto &cell_it : mod_it.second->cells)
+ for (auto &cell_it : mod_it.second->cells_)
{
- if (design->modules.count(cell_it.second->type) == 0)
+ if (design->modules_.count(cell_it.second->type) == 0)
continue;
lhs.selected_modules.insert(cell_it.second->type);
}
@@ -198,7 +205,7 @@ static void select_op_fullmod(RTLIL::Design *design, RTLIL::Selection &lhs)
static void select_op_alias(RTLIL::Design *design, RTLIL::Selection &lhs)
{
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (lhs.selected_whole_module(mod_it.first))
continue;
@@ -208,11 +215,11 @@ static void select_op_alias(RTLIL::Design *design, RTLIL::Selection &lhs)
SigMap sigmap(mod_it.second);
SigPool selected_bits;
- for (auto &it : mod_it.second->wires)
+ for (auto &it : mod_it.second->wires_)
if (lhs.selected_member(mod_it.first, it.first))
selected_bits.add(sigmap(it.second));
- for (auto &it : mod_it.second->wires)
+ for (auto &it : mod_it.second->wires_)
if (!lhs.selected_member(mod_it.first, it.first) && selected_bits.check_any(sigmap(it.second)))
lhs.selected_members[mod_it.first].insert(it.first);
}
@@ -253,7 +260,7 @@ static void select_op_diff(RTLIL::Design *design, RTLIL::Selection &lhs, const R
if (!rhs.full_selection && rhs.selected_modules.size() == 0 && rhs.selected_members.size() == 0)
return;
lhs.full_selection = false;
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
lhs.selected_modules.insert(it.first);
}
@@ -264,18 +271,18 @@ static void select_op_diff(RTLIL::Design *design, RTLIL::Selection &lhs, const R
for (auto &it : rhs.selected_members)
{
- if (design->modules.count(it.first) == 0)
+ if (design->modules_.count(it.first) == 0)
continue;
- RTLIL::Module *mod = design->modules[it.first];
+ RTLIL::Module *mod = design->modules_[it.first];
if (lhs.selected_modules.count(mod->name) > 0)
{
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
lhs.selected_members[mod->name].insert(it.first);
for (auto &it : mod->memories)
lhs.selected_members[mod->name].insert(it.first);
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
lhs.selected_members[mod->name].insert(it.first);
for (auto &it : mod->processes)
lhs.selected_members[mod->name].insert(it.first);
@@ -297,7 +304,7 @@ static void select_op_intersect(RTLIL::Design *design, RTLIL::Selection &lhs, co
if (lhs.full_selection) {
lhs.full_selection = false;
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
lhs.selected_modules.insert(it.first);
}
@@ -361,7 +368,7 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
{
int sel_objects = 0;
bool is_input, is_output;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (lhs.selected_whole_module(mod_it.first) || !lhs.selected_module(mod_it.first))
continue;
@@ -369,11 +376,11 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
RTLIL::Module *mod = mod_it.second;
std::set<RTLIL::Wire*> selected_wires;
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (lhs.selected_member(mod_it.first, it.first) && limits.count(it.first) == 0)
selected_wires.insert(it.second);
- for (auto &conn : mod->connections)
+ for (auto &conn : mod->connections())
{
std::vector<RTLIL::SigBit> conn_lhs = conn.first.to_sigbit_vector();
std::vector<RTLIL::SigBit> conn_rhs = conn.second.to_sigbit_vector();
@@ -388,8 +395,8 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
}
}
- for (auto &cell : mod->cells)
- for (auto &conn : cell.second->connections)
+ for (auto &cell : mod->cells_)
+ for (auto &conn : cell.second->connections())
{
char last_mode = '-';
for (auto &rule : rules) {
@@ -408,7 +415,7 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
include_match:
is_input = mode == 'x' || ct.cell_input(cell.second->type, conn.first);
is_output = mode == 'x' || ct.cell_output(cell.second->type, conn.first);
- for (auto &chunk : conn.second.chunks)
+ for (auto &chunk : conn.second.chunks())
if (chunk.wire != NULL) {
if (max_objects != 0 && selected_wires.count(chunk.wire) > 0 && lhs.selected_members[mod->name].count(cell.first) == 0)
if (mode == 'x' || (mode == 'i' && is_output) || (mode == 'o' && is_input))
@@ -483,7 +490,7 @@ static void select_op_expand(RTLIL::Design *design, std::string arg, char mode)
for (auto i2 : i1.second)
limits.insert(i2);
} else
- log_cmd_error("Selection %s is not defined!\n", RTLIL::id2cstr(str));
+ log_cmd_error("Selection %s is not defined!\n", RTLIL::unescape_id(str).c_str());
} else
limits.insert(RTLIL::escape_id(str));
}
@@ -540,7 +547,7 @@ static void select_filter_active_mod(RTLIL::Design *design, RTLIL::Selection &se
return;
}
- std::vector<std::string> del_list;
+ std::vector<RTLIL::IdString> del_list;
for (auto mod_name : sel.selected_modules)
if (mod_name != design->selected_active_module)
del_list.push_back(mod_name);
@@ -588,6 +595,13 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
select_op_diff(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
work_stack.pop_back();
} else
+ if (arg == "%D") {
+ if (work_stack.size() < 2)
+ log_cmd_error("Must have at least two elements on the stack for operator %%d.\n");
+ select_op_diff(design, work_stack[work_stack.size()-1], work_stack[work_stack.size()-2]);
+ work_stack[work_stack.size()-2] = work_stack[work_stack.size()-1];
+ work_stack.pop_back();
+ } else
if (arg == "%i") {
if (work_stack.size() < 2)
log_cmd_error("Must have at least two elements on the stack for operator %%i.\n");
@@ -599,14 +613,19 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
log_cmd_error("Must have at least one element on the stack for operator %%s.\n");
select_op_submod(design, work_stack[work_stack.size()-1]);
} else
+ if (arg == "%c") {
+ if (work_stack.size() < 1)
+ log_cmd_error("Must have at least one element on the stack for operator %%c.\n");
+ work_stack.push_back(work_stack.back());
+ } else
if (arg == "%m") {
if (work_stack.size() < 1)
- log_cmd_error("Must have at least one element on the stack for operator %%s.\n");
+ log_cmd_error("Must have at least one element on the stack for operator %%m.\n");
select_op_fullmod(design, work_stack[work_stack.size()-1]);
} else
if (arg == "%a") {
if (work_stack.size() < 1)
- log_cmd_error("Must have at least one element on the stack for operator %%s.\n");
+ log_cmd_error("Must have at least one element on the stack for operator %%a.\n");
select_op_alias(design, work_stack[work_stack.size()-1]);
} else
if (arg == "%x" || (arg.size() > 2 && arg.substr(0, 2) == "%x" && (arg[2] == ':' || arg[2] == '*' || arg[2] == '.' || ('0' <= arg[2] && arg[2] <= '9')))) {
@@ -635,7 +654,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
if (design->selection_vars.count(set_name) > 0)
work_stack.push_back(design->selection_vars[set_name]);
else
- log_cmd_error("Selection @%s is not defined!\n", RTLIL::id2cstr(set_name));
+ log_cmd_error("Selection @%s is not defined!\n", RTLIL::unescape_id(set_name).c_str());
select_filter_active_mod(design, work_stack.back());
return;
}
@@ -665,7 +684,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
}
sel.full_selection = false;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (arg_mod.substr(0, 2) == "A:") {
if (!match_attr(mod_it.second->attributes, arg_mod.substr(2)))
@@ -681,22 +700,22 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
RTLIL::Module *mod = mod_it.second;
if (arg_memb.substr(0, 2) == "w:") {
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "i:") {
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (it.second->port_input && match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "o:") {
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (it.second->port_output && match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "x:") {
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if ((it.second->port_input || it.second->port_output) && match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
@@ -704,7 +723,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
size_t delim = arg_memb.substr(2).find(':');
if (delim == std::string::npos) {
int width = atoi(arg_memb.substr(2).c_str());
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (it.second->width == width)
sel.selected_members[mod->name].insert(it.first);
} else {
@@ -712,7 +731,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
std::string max_str = arg_memb.substr(2+delim+1);
int min_width = min_str.empty() ? 0 : atoi(min_str.c_str());
int max_width = max_str.empty() ? -1 : atoi(max_str.c_str());
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (min_width <= it.second->width && (it.second->width <= max_width || max_width == -1))
sel.selected_members[mod->name].insert(it.first);
}
@@ -723,12 +742,12 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "c:") {
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
if (match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "t:") {
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
if (match_ids(it.second->type, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
@@ -738,13 +757,13 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "a:") {
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (match_attr(it.second->attributes, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
for (auto &it : mod->memories)
if (match_attr(it.second->attributes, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
if (match_attr(it.second->attributes, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
for (auto &it : mod->processes)
@@ -752,19 +771,19 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "r:") {
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
if (match_attr(it.second->parameters, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else {
if (arg_memb.substr(0, 2) == "n:")
arg_memb = arg_memb.substr(2);
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (match_ids(it.first, arg_memb))
sel.selected_members[mod->name].insert(it.first);
for (auto &it : mod->memories)
if (match_ids(it.first, arg_memb))
sel.selected_members[mod->name].insert(it.first);
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
if (match_ids(it.first, arg_memb))
sel.selected_members[mod->name].insert(it.first);
for (auto &it : mod->processes)
@@ -838,6 +857,10 @@ struct SelectPass : public Pass {
log(" selection is non-empty. i.e. produce an error if no object matching\n");
log(" the selection is found.\n");
log("\n");
+ log(" -assert-count N\n");
+ log(" do not modify the current selection. instead assert that the given\n");
+ log(" selection contains exactly N objects.\n");
+ log("\n");
log(" -list\n");
log(" list all objects in the current selection\n");
log("\n");
@@ -951,12 +974,18 @@ struct SelectPass : public Pass {
log(" %%d\n");
log(" pop the top set from the stack and subtract it from the new top\n");
log("\n");
+ log(" %%D\n");
+ log(" like %%d but swap the roles of two top sets on the stack\n");
+ log("\n");
+ log(" %%c\n");
+ log(" create a copy of the top set rom the stack and push it\n");
+ log("\n");
log(" %%x[<num1>|*][.<num2>][:<rule>[:<rule>..]]\n");
log(" expand top set <num1> num times according to the specified rules.\n");
log(" (i.e. select all cells connected to selected wires and select all\n");
log(" wires connected to selected cells) The rules specify which cell\n");
log(" ports to use for this. the syntax for a rule is a '-' for exclusion\n");
- log(" and a '+' for inclusion, followed by an optional comma seperated\n");
+ log(" and a '+' for inclusion, followed by an optional comma separated\n");
log(" list of cell types followed by an optional comma separated list of\n");
log(" cell ports in square brackets. a rule can also be just a cell or wire\n");
log(" name that limits the expansion (is included but does not go beyond).\n");
@@ -996,6 +1025,7 @@ struct SelectPass : public Pass {
bool got_module = false;
bool assert_none = false;
bool assert_any = false;
+ int assert_count = -1;
std::string write_file;
std::string set_name;
std::string sel_str;
@@ -1022,6 +1052,10 @@ struct SelectPass : public Pass {
assert_any = true;
continue;
}
+ if (arg == "-assert-count" && argidx+1 < args.size()) {
+ assert_count = atoi(args[++argidx].c_str());
+ continue;
+ }
if (arg == "-clear") {
clear_mode = true;
continue;
@@ -1044,9 +1078,9 @@ struct SelectPass : public Pass {
}
if (arg == "-module" && argidx+1 < args.size()) {
RTLIL::IdString mod_name = RTLIL::escape_id(args[++argidx]);
- if (design->modules.count(mod_name) == 0)
+ if (design->modules_.count(mod_name) == 0)
log_cmd_error("No such module: %s\n", id2cstr(mod_name));
- design->selected_active_module = mod_name;
+ design->selected_active_module = mod_name.str();
got_module = true;
continue;
}
@@ -1055,7 +1089,7 @@ struct SelectPass : public Pass {
continue;
}
if (arg.size() > 0 && arg[0] == '-')
- log_cmd_error("Unkown option %s.\n", arg.c_str());
+ log_cmd_error("Unknown option %s.\n", arg.c_str());
select_stmt(design, arg);
sel_str += " " + arg;
}
@@ -1066,14 +1100,14 @@ struct SelectPass : public Pass {
if (none_mode && args.size() != 2)
log_cmd_error("Option -none can not be combined with any other options.\n");
- if (add_mode + del_mode + assert_none + assert_any > 1)
- log_cmd_error("Options -add, -del, -assert-none or -assert-any can not be combined.\n");
+ if (add_mode + del_mode + assert_none + assert_any + (assert_count >= 0) > 1)
+ log_cmd_error("Options -add, -del, -assert-none, -assert-any or -assert-count can not be combined.\n");
- if ((list_mode || !write_file.empty() || count_mode) && (add_mode || del_mode || assert_none || assert_any))
- log_cmd_error("Options -list, -write and -count can not be combined with -add, -del, -assert-none or -assert-any.\n");
+ if ((list_mode || !write_file.empty() || count_mode) && (add_mode || del_mode || assert_none || assert_any || assert_count >= 0))
+ log_cmd_error("Options -list, -write and -count can not be combined with -add, -del, -assert-none, -assert-any or -assert-count.\n");
- if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || del_mode || assert_none || assert_any))
- log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -assert-none or -assert-any.\n");
+ if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || del_mode || assert_none || assert_any || assert_count >= 0))
+ log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -assert-none, -assert-any or -assert-count.\n");
if (work_stack.size() == 0 && got_module) {
RTLIL::Selection sel;
@@ -1086,7 +1120,7 @@ struct SelectPass : public Pass {
work_stack.pop_back();
}
- assert(design->selection_stack.size() > 0);
+ log_assert(design->selection_stack.size() > 0);
if (clear_mode) {
design->selection_stack.back() = RTLIL::Selection(true);
@@ -1113,18 +1147,18 @@ struct SelectPass : public Pass {
if (work_stack.size() > 0)
sel = &work_stack.back();
sel->optimize(design);
- for (auto mod_it : design->modules)
+ for (auto mod_it : design->modules_)
{
if (sel->selected_whole_module(mod_it.first) && list_mode)
log("%s\n", id2cstr(mod_it.first));
if (sel->selected_module(mod_it.first)) {
- for (auto &it : mod_it.second->wires)
+ for (auto &it : mod_it.second->wires_)
if (sel->selected_member(mod_it.first, it.first))
LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
for (auto &it : mod_it.second->memories)
if (sel->selected_member(mod_it.first, it.first))
LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
- for (auto &it : mod_it.second->cells)
+ for (auto &it : mod_it.second->cells_)
if (sel->selected_member(mod_it.first, it.first))
LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
for (auto &it : mod_it.second->processes)
@@ -1176,6 +1210,34 @@ struct SelectPass : public Pass {
return;
}
+ if (assert_count >= 0)
+ {
+ int total_count = 0;
+ if (work_stack.size() == 0)
+ log_cmd_error("No selection to check.\n");
+ RTLIL::Selection *sel = &work_stack.back();
+ sel->optimize(design);
+ for (auto mod_it : design->modules_)
+ if (sel->selected_module(mod_it.first)) {
+ for (auto &it : mod_it.second->wires_)
+ if (sel->selected_member(mod_it.first, it.first))
+ total_count++;
+ for (auto &it : mod_it.second->memories)
+ if (sel->selected_member(mod_it.first, it.first))
+ total_count++;
+ for (auto &it : mod_it.second->cells_)
+ if (sel->selected_member(mod_it.first, it.first))
+ total_count++;
+ for (auto &it : mod_it.second->processes)
+ if (sel->selected_member(mod_it.first, it.first))
+ total_count++;
+ }
+ if (assert_count != total_count)
+ log_error("Assertation failed: selection contains %d elements instead of the asserted %d:%s\n",
+ total_count, assert_count, sel_str.c_str());
+ return;
+ }
+
if (!set_name.empty())
{
if (work_stack.size() == 0)
@@ -1237,15 +1299,15 @@ struct CdPass : public Pass {
std::string modname = RTLIL::escape_id(args[1]);
- if (design->modules.count(modname) == 0 && !design->selected_active_module.empty()) {
+ if (design->modules_.count(modname) == 0 && !design->selected_active_module.empty()) {
RTLIL::Module *module = NULL;
- if (design->modules.count(design->selected_active_module) > 0)
- module = design->modules.at(design->selected_active_module);
- if (module != NULL && module->cells.count(modname) > 0)
- modname = module->cells.at(modname)->type;
+ if (design->modules_.count(design->selected_active_module) > 0)
+ module = design->modules_.at(design->selected_active_module);
+ if (module != NULL && module->cells_.count(modname) > 0)
+ modname = module->cells_.at(modname)->type.str();
}
- if (design->modules.count(modname) > 0) {
+ if (design->modules_.count(modname) > 0) {
design->selected_active_module = modname;
design->selection_stack.back() = RTLIL::Selection();
select_filter_active_mod(design, design->selection_stack.back());
@@ -1253,14 +1315,14 @@ struct CdPass : public Pass {
return;
}
- log_cmd_error("No such module `%s' found!\n", RTLIL::id2cstr(modname));
+ log_cmd_error("No such module `%s' found!\n", RTLIL::unescape_id(modname).c_str());
}
} CdPass;
template<typename T>
static int log_matches(const char *title, std::string pattern, T list)
{
- std::vector<std::string> matches;
+ std::vector<RTLIL::IdString> matches;
for (auto &it : list)
if (pattern.empty() || match_ids(it.first, pattern))
@@ -1306,15 +1368,15 @@ struct LsPass : public Pass {
if (design->selected_active_module.empty())
{
- counter += log_matches("modules", pattern, design->modules);
+ counter += log_matches("modules", pattern, design->modules_);
}
else
- if (design->modules.count(design->selected_active_module) > 0)
+ if (design->modules_.count(design->selected_active_module) > 0)
{
- RTLIL::Module *module = design->modules.at(design->selected_active_module);
- counter += log_matches("wires", pattern, module->wires);
+ RTLIL::Module *module = design->modules_.at(design->selected_active_module);
+ counter += log_matches("wires", pattern, module->wires_);
counter += log_matches("memories", pattern, module->memories);
- counter += log_matches("cells", pattern, module->cells);
+ counter += log_matches("cells", pattern, module->cells_);
counter += log_matches("processes", pattern, module->processes);
}
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index 8d98df71..029c0ec7 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -98,7 +98,7 @@ struct SetattrPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod : design->modules)
+ for (auto &mod : design->modules_)
{
RTLIL::Module *module = mod.second;
@@ -111,7 +111,7 @@ struct SetattrPass : public Pass {
if (!design->selected(module))
continue;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (design->selected(module, it.second))
do_setunset(it.second->attributes, setunset_list);
@@ -119,7 +119,7 @@ struct SetattrPass : public Pass {
if (design->selected(module, it.second))
do_setunset(it.second->attributes, setunset_list);
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
if (design->selected(module, it.second))
do_setunset(it.second->attributes, setunset_list);
@@ -164,14 +164,14 @@ struct SetparamPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod : design->modules)
+ for (auto &mod : design->modules_)
{
RTLIL::Module *module = mod.second;
if (!design->selected(module))
continue;
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
if (design->selected(module, it.second))
do_setunset(it.second->parameters, setunset_list);
}
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index 9d59834c..c72e64b8 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -23,35 +23,33 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
-static int next_bit_mode;
-static uint32_t next_bit_state;
-
-static RTLIL::State next_bit()
+struct SetundefWorker
{
- if (next_bit_mode == 0)
- return RTLIL::State::S0;
+ int next_bit_mode;
+ uint32_t next_bit_state;
- if (next_bit_mode == 1)
- return RTLIL::State::S1;
+ RTLIL::State next_bit()
+ {
+ if (next_bit_mode == 0)
+ return RTLIL::State::S0;
- // xorshift32
- next_bit_state ^= next_bit_state << 13;
- next_bit_state ^= next_bit_state >> 17;
- next_bit_state ^= next_bit_state << 5;
- log_assert(next_bit_state != 0);
+ if (next_bit_mode == 1)
+ return RTLIL::State::S1;
- return ((next_bit_state >> (next_bit_state & 15)) & 16) ? RTLIL::State::S0 : RTLIL::State::S1;
-}
+ // xorshift32
+ next_bit_state ^= next_bit_state << 13;
+ next_bit_state ^= next_bit_state >> 17;
+ next_bit_state ^= next_bit_state << 5;
+ log_assert(next_bit_state != 0);
+
+ return ((next_bit_state >> (next_bit_state & 15)) & 16) ? RTLIL::State::S0 : RTLIL::State::S1;
+ }
-struct SetundefWorker
-{
void operator()(RTLIL::SigSpec &sig)
{
- sig.expand();
- for (auto &c : sig.chunks)
- if (c.wire == NULL && c.data.bits.at(0) > RTLIL::State::S1)
- c.data.bits.at(0) = next_bit();
- sig.optimize();
+ for (auto &bit : sig)
+ if (bit.wire == NULL && bit.data > RTLIL::State::S1)
+ bit = next_bit();
}
};
@@ -83,6 +81,7 @@ struct SetundefPass : public Pass {
{
bool got_value = false;
bool undriven_mode = false;
+ SetundefWorker worker;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -93,20 +92,20 @@ struct SetundefPass : public Pass {
}
if (args[argidx] == "-zero") {
got_value = true;
- next_bit_mode = 0;
+ worker.next_bit_mode = 0;
continue;
}
if (args[argidx] == "-one") {
got_value = true;
- next_bit_mode = 1;
+ worker.next_bit_mode = 1;
continue;
}
if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) {
got_value = true;
- next_bit_mode = 2;
- next_bit_state = atoi(args[++argidx].c_str()) + 1;
+ worker.next_bit_mode = 2;
+ worker.next_bit_state = atoi(args[++argidx].c_str()) + 1;
for (int i = 0; i < 10; i++)
- next_bit();
+ worker.next_bit();
continue;
}
break;
@@ -116,7 +115,7 @@ struct SetundefPass : public Pass {
if (!got_value)
log_cmd_error("One of the options -zero, -one, or -random <seed> must be specified.\n");
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
RTLIL::Module *module = mod_it.second;
if (!design->selected(module))
@@ -130,27 +129,26 @@ struct SetundefPass : public Pass {
SigMap sigmap(module);
SigPool undriven_signals;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (!it.second->port_input)
undriven_signals.add(sigmap(it.second));
CellTypes ct(design);
- for (auto &it : module->cells)
- for (auto &conn : it.second->connections)
+ for (auto &it : module->cells_)
+ for (auto &conn : it.second->connections())
if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first))
undriven_signals.del(sigmap(conn.second));
RTLIL::SigSpec sig = undriven_signals.export_all();
- for (auto &c : sig.chunks) {
+ for (auto &c : sig.chunks()) {
RTLIL::SigSpec bits;
for (int i = 0; i < c.width; i++)
- bits.append(next_bit());
- bits.optimize();
- module->connections.push_back(RTLIL::SigSig(c, bits));
+ bits.append(worker.next_bit());
+ module->connect(RTLIL::SigSig(c, bits));
}
}
- module->rewrite_sigspecs(SetundefWorker());
+ module->rewrite_sigspecs(worker);
}
}
} SetundefPass;
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index fdccb4bc..2218eded 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -22,7 +22,10 @@
#include "kernel/log.h"
#include <string.h>
#include <dirent.h>
-#include <readline/readline.h>
+
+#ifdef YOSYS_ENABLE_READLINE
+# include <readline/readline.h>
+#endif
using RTLIL::id2cstr;
@@ -45,6 +48,7 @@ struct ShowWorker
RTLIL::Module *module;
uint32_t currentColor;
bool genWidthLabels;
+ bool genSignedLabels;
bool stretchIO;
bool enumerateIds;
bool abbreviateIds;
@@ -54,7 +58,7 @@ struct ShowWorker
const std::vector<std::pair<std::string, RTLIL::Selection>> &color_selections;
const std::vector<std::pair<std::string, RTLIL::Selection>> &label_selections;
- uint32_t xorshift32(uint32_t x) {
+ static uint32_t xorshift32(uint32_t x) {
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
@@ -78,7 +82,7 @@ struct ShowWorker
std::string nextColor(RTLIL::SigSpec sig, std::string defaultColor)
{
sig.sort_and_unify();
- for (auto &c : sig.chunks) {
+ for (auto &c : sig.chunks()) {
if (c.wire != NULL)
for (auto &s : color_selections)
if (s.second.selected_members.count(module->name) > 0 && s.second.selected_members.at(module->name).count(c.wire->name) > 0)
@@ -87,17 +91,17 @@ struct ShowWorker
return defaultColor;
}
- std::string nextColor(RTLIL::SigSig &conn, std::string defaultColor)
+ std::string nextColor(const RTLIL::SigSig &conn, std::string defaultColor)
{
return nextColor(conn.first, nextColor(conn.second, defaultColor));
}
- std::string nextColor(RTLIL::SigSpec &sig)
+ std::string nextColor(const RTLIL::SigSpec &sig)
{
return nextColor(sig, nextColor());
}
- std::string nextColor(RTLIL::SigSig &conn)
+ std::string nextColor(const RTLIL::SigSig &conn)
{
return nextColor(conn, nextColor());
}
@@ -124,7 +128,7 @@ struct ShowWorker
const char *findLabel(std::string member_name)
{
for (auto &s : label_selections)
- if (s.second.selected_member(module->name, RTLIL::escape_id(member_name)))
+ if (s.second.selected_member(module->name, member_name))
return escape(s.first);
return escape(member_name, true);
}
@@ -171,15 +175,13 @@ struct ShowWorker
std::string gen_signode_simple(RTLIL::SigSpec sig, bool range_check = true)
{
- sig.optimize();
-
- if (sig.chunks.size() == 0) {
+ if (SIZE(sig) == 0) {
fprintf(f, "v%d [ label=\"\" ];\n", single_idx_count);
return stringf("v%d", single_idx_count++);
}
- if (sig.chunks.size() == 1) {
- RTLIL::SigChunk &c = sig.chunks[0];
+ if (sig.is_chunk()) {
+ const RTLIL::SigChunk &c = sig.as_chunk();
if (c.wire != NULL && design->selected_member(module->name, c.wire->name)) {
if (!range_check || c.wire->width == c.width)
return stringf("n%d", id2num(c.wire->name));
@@ -199,13 +201,12 @@ struct ShowWorker
if (net.empty())
{
std::string label_string;
- sig.optimize();
- int pos = sig.width-1;
+ int pos = sig.size()-1;
int idx = single_idx_count++;
- for (int i = int(sig.chunks.size())-1; i >= 0; i--) {
- RTLIL::SigChunk &c = sig.chunks[i];
+ for (int i = int(sig.chunks().size())-1; i >= 0; i--) {
+ const RTLIL::SigChunk &c = sig.chunks().at(i);
net = gen_signode_simple(c, false);
- assert(!net.empty());
+ log_assert(!net.empty());
if (driver) {
label_string += stringf("<s%d> %d:%d - %d:%d |", i, pos, pos-c.width+1, c.offset+c.width-1, c.offset);
net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i));
@@ -225,9 +226,9 @@ struct ShowWorker
if (!port.empty()) {
currentColor = xorshift32(currentColor);
if (driver)
- code += stringf("%s:e -> x%d:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", port.c_str(), idx, nextColor(sig).c_str(), widthLabel(sig.width).c_str());
+ code += stringf("%s:e -> x%d:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", port.c_str(), idx, nextColor(sig).c_str(), widthLabel(sig.size()).c_str());
else
- code += stringf("x%d:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", idx, port.c_str(), nextColor(sig).c_str(), widthLabel(sig.width).c_str());
+ code += stringf("x%d:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", idx, port.c_str(), nextColor(sig).c_str(), widthLabel(sig.size()).c_str());
}
if (node != NULL)
*node = stringf("x%d", idx);
@@ -239,7 +240,7 @@ struct ShowWorker
net_conn_map[net].in.insert(port);
else
net_conn_map[net].out.insert(port);
- net_conn_map[net].bits = sig.width;
+ net_conn_map[net].bits = sig.size();
net_conn_map[net].color = nextColor(sig, net_conn_map[net].color);
}
if (node != NULL)
@@ -299,16 +300,16 @@ struct ShowWorker
dot_id2num_store.clear();
net_conn_map.clear();
- fprintf(f, "digraph \"%s\" {\n", escape(module->name));
+ fprintf(f, "digraph \"%s\" {\n", escape(module->name.str()));
if (!notitle)
- fprintf(f, "label=\"%s\";\n", escape(module->name));
+ fprintf(f, "label=\"%s\";\n", escape(module->name.str()));
fprintf(f, "rankdir=\"LR\";\n");
fprintf(f, "remincross=true;\n");
std::set<std::string> all_sources, all_sinks;
std::map<std::string, std::string> wires_on_demand;
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
if (!design->selected_member(module->name, it.first))
continue;
const char *shape = "diamond";
@@ -316,14 +317,14 @@ struct ShowWorker
shape = "octagon";
if (it.first[0] == '\\') {
fprintf(f, "n%d [ shape=%s, label=\"%s\", %s, fontcolor=\"black\" ];\n",
- id2num(it.first), shape, findLabel(it.first),
+ id2num(it.first), shape, findLabel(it.first.str()),
nextColor(RTLIL::SigSpec(it.second), "color=\"black\"").c_str());
if (it.second->port_input)
all_sources.insert(stringf("n%d", id2num(it.first)));
else if (it.second->port_output)
all_sinks.insert(stringf("n%d", id2num(it.first)));
} else {
- wires_on_demand[stringf("n%d", id2num(it.first))] = it.first;
+ wires_on_demand[stringf("n%d", id2num(it.first))] = it.first.str();
}
}
@@ -340,38 +341,43 @@ struct ShowWorker
fprintf(f, "}\n");
}
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
if (!design->selected_member(module->name, it.first))
continue;
std::vector<RTLIL::IdString> in_ports, out_ports;
- for (auto &conn : it.second->connections) {
+ for (auto &conn : it.second->connections()) {
if (!ct.cell_output(it.second->type, conn.first))
in_ports.push_back(conn.first);
else
out_ports.push_back(conn.first);
}
+ std::sort(in_ports.begin(), in_ports.end(), RTLIL::sort_by_id_str());
+ std::sort(out_ports.begin(), out_ports.end(), RTLIL::sort_by_id_str());
+
std::string label_string = "{{";
for (auto &p : in_ports)
- label_string += stringf("<p%d> %s|", id2num(p), escape(p));
+ label_string += stringf("<p%d> %s%s|", id2num(p), escape(p.str()),
+ genSignedLabels && it.second->hasParam(p.str() + "_SIGNED") &&
+ it.second->getParam(p.str() + "_SIGNED").as_bool() ? "*" : "");
if (label_string[label_string.size()-1] == '|')
label_string = label_string.substr(0, label_string.size()-1);
- label_string += stringf("}|%s\\n%s|{", findLabel(it.first), escape(it.second->type));
+ label_string += stringf("}|%s\\n%s|{", findLabel(it.first.str()), escape(it.second->type.str()));
for (auto &p : out_ports)
- label_string += stringf("<p%d> %s|", id2num(p), escape(p));
+ label_string += stringf("<p%d> %s|", id2num(p), escape(p.str()));
if (label_string[label_string.size()-1] == '|')
label_string = label_string.substr(0, label_string.size()-1);
label_string += "}}";
std::string code;
- for (auto &conn : it.second->connections) {
+ for (auto &conn : it.second->connections()) {
code += gen_portbox(stringf("c%d:p%d", id2num(it.first), id2num(conn.first)),
conn.second, ct.cell_output(it.second->type, conn.first));
}
@@ -383,7 +389,7 @@ struct ShowWorker
else
#endif
fprintf(f, "c%d [ shape=record, label=\"%s\"%s ];\n%s",
- id2num(it.first), label_string.c_str(), findColor(it.first), code.c_str());
+ id2num(it.first), label_string.c_str(), findColor(it.first.str()), code.c_str());
}
for (auto &it : module->processes)
@@ -405,7 +411,7 @@ struct ShowWorker
code += gen_portbox("", sig, false, &node);
fprintf(f, "%s", code.c_str());
net_conn_map[node].out.insert(stringf("p%d", pidx));
- net_conn_map[node].bits = sig.width;
+ net_conn_map[node].bits = sig.size();
net_conn_map[node].color = nextColor(sig, net_conn_map[node].color);
}
@@ -414,25 +420,25 @@ struct ShowWorker
code += gen_portbox("", sig, true, &node);
fprintf(f, "%s", code.c_str());
net_conn_map[node].in.insert(stringf("p%d", pidx));
- net_conn_map[node].bits = sig.width;
+ net_conn_map[node].bits = sig.size();
net_conn_map[node].color = nextColor(sig, net_conn_map[node].color);
}
std::string proc_src = RTLIL::unescape_id(proc->name);
if (proc->attributes.count("\\src") > 0)
proc_src = proc->attributes.at("\\src").decode_string();
- fprintf(f, "p%d [shape=box, style=rounded, label=\"PROC %s\\n%s\"];\n", pidx, findLabel(proc->name), proc_src.c_str());
+ fprintf(f, "p%d [shape=box, style=rounded, label=\"PROC %s\\n%s\"];\n", pidx, findLabel(proc->name.str()), proc_src.c_str());
}
- for (auto &conn : module->connections)
+ for (auto &conn : module->connections())
{
bool found_lhs_wire = false;
- for (auto &c : conn.first.chunks) {
+ for (auto &c : conn.first.chunks()) {
if (c.wire == NULL || design->selected_member(module->name, c.wire->name))
found_lhs_wire = true;
}
bool found_rhs_wire = false;
- for (auto &c : conn.second.chunks) {
+ for (auto &c : conn.second.chunks()) {
if (c.wire == NULL || design->selected_member(module->name, c.wire->name))
found_rhs_wire = true;
}
@@ -446,11 +452,11 @@ struct ShowWorker
if (left_node[0] == 'x' && right_node[0] == 'x') {
currentColor = xorshift32(currentColor);
- fprintf(f, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", left_node.c_str(), right_node.c_str(), nextColor(conn).c_str(), widthLabel(conn.first.width).c_str());
+ fprintf(f, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", left_node.c_str(), right_node.c_str(), nextColor(conn).c_str(), widthLabel(conn.first.size()).c_str());
} else {
- net_conn_map[right_node].bits = conn.first.width;
+ net_conn_map[right_node].bits = conn.first.size();
net_conn_map[right_node].color = nextColor(conn, net_conn_map[right_node].color);
- net_conn_map[left_node].bits = conn.first.width;
+ net_conn_map[left_node].bits = conn.first.size();
net_conn_map[left_node].color = nextColor(conn, net_conn_map[left_node].color);
if (left_node[0] == 'x') {
net_conn_map[right_node].in.insert(left_node);
@@ -487,15 +493,15 @@ struct ShowWorker
fprintf(f, "%s:e -> %s:w [%s, %s];\n", it.first.c_str(), it2.c_str(), nextColor(it.second.color).c_str(), widthLabel(it.second.bits).c_str());
}
- fprintf(f, "};\n");
+ fprintf(f, "}\n");
}
- ShowWorker(FILE *f, RTLIL::Design *design, std::vector<RTLIL::Design*> &libs, uint32_t colorSeed,
- bool genWidthLabels, bool stretchIO, bool enumerateIds, bool abbreviateIds, bool notitle,
+ ShowWorker(FILE *f, RTLIL::Design *design, std::vector<RTLIL::Design*> &libs, uint32_t colorSeed, bool genWidthLabels,
+ bool genSignedLabels, bool stretchIO, bool enumerateIds, bool abbreviateIds, bool notitle,
const std::vector<std::pair<std::string, RTLIL::Selection>> &color_selections,
const std::vector<std::pair<std::string, RTLIL::Selection>> &label_selections) :
f(f), design(design), currentColor(colorSeed), genWidthLabels(genWidthLabels),
- stretchIO(stretchIO), enumerateIds(enumerateIds), abbreviateIds(abbreviateIds),
+ genSignedLabels(genSignedLabels), stretchIO(stretchIO), enumerateIds(enumerateIds), abbreviateIds(abbreviateIds),
notitle(notitle), color_selections(color_selections), label_selections(label_selections)
{
ct.setup_internals();
@@ -509,7 +515,7 @@ struct ShowWorker
design->optimize();
page_counter = 0;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
module = mod_it.second;
if (!design->selected_module(module->name))
@@ -519,7 +525,7 @@ struct ShowWorker
log("Skipping blackbox module %s.\n", id2cstr(module->name));
continue;
} else
- if (module->cells.empty() && module->connections.empty() && module->processes.empty()) {
+ if (module->cells_.empty() && module->connections().empty() && module->processes.empty()) {
log("Skipping empty module %s.\n", id2cstr(module->name));
continue;
} else
@@ -575,6 +581,10 @@ struct ShowPass : public Pass {
log(" -width\n");
log(" annotate busses with a label indicating the width of the bus.\n");
log("\n");
+ log(" -signed\n");
+ log(" mark ports (A, B) that are declarted as signed (using the [AB]_SIGNED\n");
+ log(" cell parameter) with an asterisk next to the port name.\n");
+ log("\n");
log(" -stretch\n");
log(" stretch the graph so all inputs are on the left side and all outputs\n");
log(" (including inout ports) are on the right side.\n");
@@ -591,8 +601,8 @@ struct ShowPass : public Pass {
log(" -notitle\n");
log(" do not add the module name as graph title to the dot file\n");
log("\n");
- log("When no <format> is specified, SVG is used. When no <format> and <viewer> is\n");
- log("specified, 'yosys-svgviewer' is used to display the schematic.\n");
+ log("When no <format> is specified, 'dot' is used. When no <format> and <viewer> is\n");
+ log("specified, 'xdot' is used to display the schematic.\n");
log("\n");
log("The generated output files are '~/.yosys_show.dot' and '~/.yosys_show.<format>',\n");
log("unless another prefix is specified using -prefix <prefix>.\n");
@@ -613,6 +623,7 @@ struct ShowPass : public Pass {
std::vector<RTLIL::Design*> libs;
uint32_t colorSeed = 0;
bool flag_width = false;
+ bool flag_signed = false;
bool flag_stretch = false;
bool flag_pause = false;
bool flag_enum = false;
@@ -655,6 +666,8 @@ struct ShowPass : public Pass {
}
if (arg == "-colors" && argidx+1 < args.size()) {
colorSeed = atoi(args[++argidx].c_str());
+ for (int i = 0; i < 100; i++)
+ colorSeed = ShowWorker::xorshift32(colorSeed);
continue;
}
if (arg == "-format" && argidx+1 < args.size()) {
@@ -665,6 +678,10 @@ struct ShowPass : public Pass {
flag_width= true;
continue;
}
+ if (arg == "-signed") {
+ flag_signed= true;
+ continue;
+ }
if (arg == "-stretch") {
flag_stretch= true;
continue;
@@ -693,10 +710,10 @@ struct ShowPass : public Pass {
if (format != "ps") {
int modcount = 0;
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (mod_it.second->get_bool_attribute("\\blackbox"))
continue;
- if (mod_it.second->cells.empty() && mod_it.second->connections.empty())
+ if (mod_it.second->cells_.empty() && mod_it.second->connections().empty())
continue;
if (design->selected_module(mod_it.first))
modcount++;
@@ -706,13 +723,13 @@ struct ShowPass : public Pass {
}
for (auto filename : libfiles) {
- FILE *f = fopen(filename.c_str(), "rt");
- if (f == NULL)
+ std::ifstream f;
+ f.open(filename.c_str());
+ if (f.fail())
log_error("Can't open lib file `%s'.\n", filename.c_str());
RTLIL::Design *lib = new RTLIL::Design;
- Frontend::frontend_call(lib, f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
+ Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
libs.push_back(lib);
- fclose(f);
}
if (libs.size() > 0)
@@ -728,7 +745,7 @@ struct ShowPass : public Pass {
delete lib;
log_cmd_error("Can't open dot file `%s' for writing.\n", dot_file.c_str());
}
- ShowWorker worker(f, design, libs, colorSeed, flag_width, flag_stretch, flag_enum, flag_abbeviate, flag_notitle, color_selections, label_selections);
+ ShowWorker worker(f, design, libs, colorSeed, flag_width, flag_signed, flag_stretch, flag_enum, flag_abbeviate, flag_notitle, color_selections, label_selections);
fclose(f);
for (auto lib : libs)
@@ -737,8 +754,8 @@ struct ShowPass : public Pass {
if (worker.page_counter == 0)
log_cmd_error("Nothing there to show.\n");
- if (format != "dot") {
- std::string cmd = stringf("dot -T%s -o '%s' '%s'", format.empty() ? "svg" : format.c_str(), out_file.c_str(), dot_file.c_str());
+ if (format != "dot" && !format.empty()) {
+ std::string cmd = stringf("dot -T%s -o '%s' '%s'", format.c_str(), out_file.c_str(), dot_file.c_str());
log("Exec: %s\n", cmd.c_str());
if (system(cmd.c_str()) != 0)
log_cmd_error("Shell command failed!\n");
@@ -751,13 +768,14 @@ struct ShowPass : public Pass {
log_cmd_error("Shell command failed!\n");
} else
if (format.empty()) {
- std::string cmd = stringf("fuser -s '%s' || '%s' '%s' &", out_file.c_str(), rewrite_yosys_exe("yosys-svgviewer").c_str(), out_file.c_str());
+ std::string cmd = stringf("fuser -s '%s' || xdot '%s' < '%s' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str());
log("Exec: %s\n", cmd.c_str());
if (system(cmd.c_str()) != 0)
log_cmd_error("Shell command failed!\n");
}
if (flag_pause) {
+ #ifdef YOSYS_ENABLE_READLINE
char *input = NULL;
while ((input = readline("Press ENTER to continue (or type 'shell' to open a shell)> ")) != NULL) {
if (input[strspn(input, " \t\r\n")] == 0)
@@ -768,6 +786,9 @@ struct ShowPass : public Pass {
break;
}
}
+ #else
+ log_cmd_error("This version of yosys is built without readline support => 'show -pause' is not available.\n");
+ #endif
}
log_pop();
diff --git a/passes/cmds/splice.cc b/passes/cmds/splice.cc
index 6d920dbc..d03aaf3b 100644
--- a/passes/cmds/splice.cc
+++ b/passes/cmds/splice.cc
@@ -33,8 +33,8 @@ struct SpliceWorker
bool sel_by_wire;
bool sel_any_bit;
bool no_outputs;
- std::set<std::string> ports;
- std::set<std::string> no_ports;
+ std::set<RTLIL::IdString> ports;
+ std::set<RTLIL::IdString> no_ports;
CellTypes ct;
SigMap sigmap;
@@ -52,7 +52,7 @@ struct SpliceWorker
RTLIL::SigSpec get_sliced_signal(RTLIL::SigSpec sig)
{
- if (sig.width == 0 || sig.is_fully_const())
+ if (sig.size() == 0 || sig.is_fully_const())
return sig;
if (sliced_signals_cache.count(sig))
@@ -69,20 +69,16 @@ struct SpliceWorker
RTLIL::SigSpec new_sig = sig;
- if (sig_a.width != sig.width) {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$slice";
+ if (sig_a.size() != sig.size()) {
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$slice");
cell->parameters["\\OFFSET"] = offset;
- cell->parameters["\\A_WIDTH"] = sig_a.width;
- cell->parameters["\\Y_WIDTH"] = sig.width;
- cell->connections["\\A"] = sig_a;
- cell->connections["\\Y"] = module->new_wire(sig.width, NEW_ID);
- new_sig = cell->connections["\\Y"];
- module->add(cell);
+ cell->parameters["\\A_WIDTH"] = sig_a.size();
+ cell->parameters["\\Y_WIDTH"] = sig.size();
+ cell->setPort("\\A", sig_a);
+ cell->setPort("\\Y", module->addWire(NEW_ID, sig.size()));
+ new_sig = cell->getPort("\\Y");
}
- new_sig.optimize();
sliced_signals_cache[sig] = new_sig;
return new_sig;
@@ -90,7 +86,7 @@ struct SpliceWorker
RTLIL::SigSpec get_spliced_signal(RTLIL::SigSpec sig)
{
- if (sig.width == 0 || sig.is_fully_const())
+ if (sig.size() == 0 || sig.is_fully_const())
return sig;
if (spliced_signals_cache.count(sig))
@@ -131,19 +127,15 @@ struct SpliceWorker
RTLIL::SigSpec new_sig = get_sliced_signal(chunks.front());
for (size_t i = 1; i < chunks.size(); i++) {
RTLIL::SigSpec sig2 = get_sliced_signal(chunks[i]);
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$concat";
- cell->parameters["\\A_WIDTH"] = new_sig.width;
- cell->parameters["\\B_WIDTH"] = sig2.width;
- cell->connections["\\A"] = new_sig;
- cell->connections["\\B"] = sig2;
- cell->connections["\\Y"] = module->new_wire(new_sig.width + sig2.width, NEW_ID);
- new_sig = cell->connections["\\Y"];
- module->add(cell);
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$concat");
+ cell->parameters["\\A_WIDTH"] = new_sig.size();
+ cell->parameters["\\B_WIDTH"] = sig2.size();
+ cell->setPort("\\A", new_sig);
+ cell->setPort("\\B", sig2);
+ cell->setPort("\\Y", module->addWire(NEW_ID, new_sig.size() + sig2.size()));
+ new_sig = cell->getPort("\\Y");
}
- new_sig.optimize();
spliced_signals_cache[sig] = new_sig;
log(" Created spliced signal: %s -> %s\n", log_signal(sig), log_signal(new_sig));
@@ -157,7 +149,7 @@ struct SpliceWorker
driven_bits.push_back(RTLIL::State::Sm);
driven_bits.push_back(RTLIL::State::Sm);
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->port_input) {
RTLIL::SigSpec sig = sigmap(it.second);
driven_chunks.insert(sig);
@@ -166,8 +158,8 @@ struct SpliceWorker
driven_bits.push_back(RTLIL::State::Sm);
}
- for (auto &it : module->cells)
- for (auto &conn : it.second->connections)
+ for (auto &it : module->cells_)
+ for (auto &conn : it.second->connections())
if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first)) {
RTLIL::SigSpec sig = sigmap(conn.second);
driven_chunks.insert(sig);
@@ -183,14 +175,14 @@ struct SpliceWorker
SigPool selected_bits;
if (!sel_by_cell)
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (design->selected(module, it.second))
selected_bits.add(sigmap(it.second));
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (!sel_by_wire && !design->selected(module, it.second))
continue;
- for (auto &conn : it.second->connections)
+ for (auto &conn : it.second->connections_)
if (ct.cell_input(it.second->type, conn.first)) {
if (ports.size() > 0 && !ports.count(conn.first))
continue;
@@ -211,7 +203,7 @@ struct SpliceWorker
std::vector<std::pair<RTLIL::Wire*, RTLIL::SigSpec>> rework_wires;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (!no_outputs && it.second->port_output) {
if (!design->selected(module, it.second))
continue;
@@ -232,15 +224,15 @@ struct SpliceWorker
for (auto &it : rework_wires)
{
- module->wires.erase(it.first->name);
- RTLIL::Wire *new_port = new RTLIL::Wire(*it.first);
- it.first->name = NEW_ID;
+ RTLIL::IdString orig_name = it.first->name;
+ module->rename(it.first, NEW_ID);
+
+ RTLIL::Wire *new_port = module->addWire(orig_name, it.first);
it.first->port_id = 0;
it.first->port_input = false;
it.first->port_output = false;
- module->add(it.first);
- module->add(new_port);
- module->connections.push_back(RTLIL::SigSig(new_port, it.second));
+
+ module->connect(RTLIL::SigSig(new_port, it.second));
}
}
};
@@ -259,12 +251,12 @@ struct SplicePass : public Pass {
log("\n");
log(" -sel_by_cell\n");
log(" only select the cell ports to rewire by the cell. if the selection\n");
- log(" contains a cell, than all cell inputs are rewired, if neccessary.\n");
+ log(" contains a cell, than all cell inputs are rewired, if necessary.\n");
log("\n");
log(" -sel_by_wire\n");
log(" only select the cell ports to rewire by the wire. if the selection\n");
log(" contains a wire, than all cell ports driven by this wire are wired,\n");
- log(" if neccessary.\n");
+ log(" if necessary.\n");
log("\n");
log(" -sel_any_bit\n");
log(" it is sufficient if the driver of any bit of a cell port is selected.\n");
@@ -291,7 +283,7 @@ struct SplicePass : public Pass {
bool sel_by_wire = false;
bool sel_any_bit = false;
bool no_outputs = false;
- std::set<std::string> ports, no_ports;
+ std::set<RTLIL::IdString> ports, no_ports;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -335,7 +327,7 @@ struct SplicePass : public Pass {
log_header("Executing SPLICE pass (creating cells for signal splicing).\n");
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (!design->selected(mod_it.second))
continue;
diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc
index da9ef43f..344b03fc 100644
--- a/passes/cmds/splitnets.cc
+++ b/passes/cmds/splitnets.cc
@@ -28,33 +28,28 @@ struct SplitnetsWorker
void append_wire(RTLIL::Module *module, RTLIL::Wire *wire, int offset, int width, std::string format)
{
- RTLIL::Wire *new_wire = new RTLIL::Wire;
-
- new_wire->port_id = wire->port_id;
- new_wire->port_input = wire->port_input;
- new_wire->port_output = wire->port_output;
- new_wire->name = wire->name;
- new_wire->width = width;
+ std::string new_wire_name = wire->name.str();
if (format.size() > 0)
- new_wire->name += format.substr(0, 1);
+ new_wire_name += format.substr(0, 1);
if (width > 1) {
- new_wire->name += stringf("%d", offset+width-1);
+ new_wire_name += stringf("%d", offset+width-1);
if (format.size() > 2)
- new_wire->name += format.substr(2, 1);
+ new_wire_name += format.substr(2, 1);
else
- new_wire->name += ":";
+ new_wire_name += ":";
}
- new_wire->name += stringf("%d", offset);
+ new_wire_name += stringf("%d", offset);
if (format.size() > 1)
- new_wire->name += format.substr(1, 1);
+ new_wire_name += format.substr(1, 1);
- while (module->count_id(new_wire->name) > 0)
- new_wire->name = new_wire->name + "_";
- module->add(new_wire);
+ RTLIL::Wire *new_wire = module->addWire(module->uniquify(new_wire_name), width);
+ new_wire->port_id = wire->port_id;
+ new_wire->port_input = wire->port_input;
+ new_wire->port_output = wire->port_output;
std::vector<RTLIL::SigBit> sigvec = RTLIL::SigSpec(new_wire).to_sigbit_vector();
splitmap[wire].insert(splitmap[wire].end(), sigvec.begin(), sigvec.end());
@@ -62,11 +57,9 @@ struct SplitnetsWorker
void operator()(RTLIL::SigSpec &sig)
{
- sig.expand();
- for (auto &c : sig.chunks)
- if (splitmap.count(c.wire) > 0)
- c = splitmap.at(c.wire).at(c.offset);
- sig.optimize();
+ for (auto &bit : sig)
+ if (splitmap.count(bit.wire) > 0)
+ bit = splitmap.at(bit.wire).at(bit.offset);
}
};
@@ -83,7 +76,7 @@ struct SplitnetsPass : public Pass {
log(" -format char1[char2[char3]]\n");
log(" the first char is inserted between the net name and the bit index, the\n");
log(" second char is appended to the netname. e.g. -format () creates net\n");
- log(" names like 'mysignal(42)'. the 3rd character is the range seperation\n");
+ log(" names like 'mysignal(42)'. the 3rd character is the range separation\n");
log(" character when creating multi-bit wires. the default is '[]:'.\n");
log("\n");
log(" -ports\n");
@@ -121,7 +114,7 @@ struct SplitnetsPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
RTLIL::Module *module = mod_it.second;
if (!design->selected(module))
@@ -135,16 +128,16 @@ struct SplitnetsPass : public Pass {
std::map<RTLIL::Wire*, std::set<int>> split_wires_at;
- for (auto &c : module->cells)
- for (auto &p : c.second->connections)
+ for (auto &c : module->cells_)
+ for (auto &p : c.second->connections())
{
if (!ct.cell_known(c.second->type))
continue;
if (!ct.cell_output(c.second->type, p.first))
continue;
- RTLIL::SigSpec sig = p.second.optimized();
- for (auto &chunk : sig.chunks) {
+ RTLIL::SigSpec sig = p.second;
+ for (auto &chunk : sig.chunks()) {
if (chunk.wire == NULL)
continue;
if (chunk.wire->port_id == 0 || flag_ports) {
@@ -167,9 +160,9 @@ struct SplitnetsPass : public Pass {
}
else
{
- for (auto &w : module->wires) {
+ for (auto &w : module->wires_) {
RTLIL::Wire *wire = w.second;
- if (wire->width > 1 && (wire->port_id == 0 || flag_ports))
+ if (wire->width > 1 && (wire->port_id == 0 || flag_ports) && design->selected(module, w.second))
worker.splitmap[wire] = std::vector<RTLIL::SigBit>();
}
@@ -180,10 +173,10 @@ struct SplitnetsPass : public Pass {
module->rewrite_sigspecs(worker);
- for (auto &it : worker.splitmap) {
- module->wires.erase(it.first->name);
- delete it.first;
- }
+ std::set<RTLIL::Wire*> delete_wires;
+ for (auto &it : worker.splitmap)
+ delete_wires.insert(it.first);
+ module->remove(delete_wires);
module->fixup_ports();
}
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 83477007..19cdaa62 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -63,13 +63,13 @@ namespace
#undef X
}
- statdata_t(RTLIL::Design *design, RTLIL::Module *mod)
+ statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode)
{
#define X(_name) _name = 0;
STAT_INT_MEMBERS
#undef X
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
{
if (!design->selected(mod, it.second))
continue;
@@ -90,11 +90,35 @@ namespace
num_memory_bits += it.second->width * it.second->size;
}
- for (auto &it : mod->cells) {
+ for (auto &it : mod->cells_)
+ {
if (!design->selected(mod, it.second))
continue;
+
+ RTLIL::IdString cell_type = it.second->type;
+
+ if (width_mode)
+ {
+ if (cell_type.in("$not", "$pos", "$neg",
+ "$logic_not", "$logic_and", "$logic_or",
+ "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
+ "$lut", "$and", "$or", "$xor", "$xnor",
+ "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
+ "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
+ "$add", "$sub", "$mul", "$div", "$mod", "$pow")) {
+ int width_a = it.second->hasPort("\\A") ? SIZE(it.second->getPort("\\A")) : 0;
+ int width_b = it.second->hasPort("\\B") ? SIZE(it.second->getPort("\\B")) : 0;
+ int width_y = it.second->hasPort("\\Y") ? SIZE(it.second->getPort("\\Y")) : 0;
+ cell_type = stringf("%s_%d", cell_type.c_str(), std::max<int>({width_a, width_b, width_y}));
+ }
+ else if (cell_type.in("$mux", "$pmux"))
+ cell_type = stringf("%s_%d", cell_type.c_str(), SIZE(it.second->getPort("\\Y")));
+ else if (cell_type.in("$sr", "$dff", "$dffsr", "$adff", "$dlatch", "$dlatchsr"))
+ cell_type = stringf("%s_%d", cell_type.c_str(), SIZE(it.second->getPort("\\Q")));
+ }
+
num_cells++;
- num_cells_by_type[it.second->type]++;
+ num_cells_by_type[cell_type]++;
}
for (auto &it : mod->processes) {
@@ -154,28 +178,37 @@ struct StatPass : public Pass {
log(" selected and a module has the 'top' attribute set, this module is used\n");
log(" default value for this option.\n");
log("\n");
+ log(" -width\n");
+ log(" annotate internal cell types with their word width.\n");
+ log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Printing statistics.\n");
+ bool width_mode = false;
RTLIL::Module *top_mod = NULL;
std::map<RTLIL::IdString, statdata_t> mod_stat;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
+ if (args[argidx] == "-width") {
+ width_mode = true;
+ continue;
+ }
if (args[argidx] == "-top" && argidx+1 < args.size()) {
- if (design->modules.count(RTLIL::escape_id(args[argidx+1])) == 0)
+ if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0)
log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str());
- top_mod = design->modules.at(RTLIL::escape_id(args[++argidx]));
+ top_mod = design->modules_.at(RTLIL::escape_id(args[++argidx]));
continue;
}
break;
}
extra_args(args, argidx, design);
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
{
if (!design->selected_module(it.first))
continue;
@@ -184,7 +217,7 @@ struct StatPass : public Pass {
if (it.second->get_bool_attribute("\\top"))
top_mod = it.second;
- statdata_t data(design, it.second);
+ statdata_t data(design, it.second, width_mode);
mod_stat[it.first] = data;
log("\n");
diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc
new file mode 100644
index 00000000..6f80ef72
--- /dev/null
+++ b/passes/cmds/tee.cc
@@ -0,0 +1,88 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2014 Johann Glaser <Johann.Glaser@gmx.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+struct TeePass : public Pass {
+ TeePass() : Pass("tee", "redirect command output to file") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" tee [-q] [-o logfile|-a logfile] cmd\n");
+ log("\n");
+ log("Execute the specified command, optionally writing the commands output to the\n");
+ log("specified logfile(s).\n");
+ log("\n");
+ log(" -q\n");
+ log(" Do not print output to the normal destination (console and/or log file)\n");
+ log("\n");
+ log(" -o logfile\n");
+ log(" Write output to this file, truncate if exists.\n");
+ log("\n");
+ log(" -a logfile\n");
+ log(" Write output to this file, append if exists.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ std::vector<FILE*> backup_log_files, files_to_close;
+ backup_log_files = log_files;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-q" && files_to_close.empty()) {
+ log_files.clear();
+ continue;
+ }
+ if ((args[argidx] == "-o" || args[argidx] == "-a") && argidx+1 < args.size()) {
+ const char *open_mode = args[argidx] == "-o" ? "w" : "a+";
+ FILE *f = fopen(args[++argidx].c_str(), open_mode);
+ if (f == NULL) {
+ for (auto cf : files_to_close)
+ fclose(cf);
+ log_cmd_error("Can't create file %s.\n", args[argidx].c_str());
+ }
+ log_files.push_back(f);
+ files_to_close.push_back(f);
+ continue;
+ }
+ break;
+ }
+
+ try {
+ std::vector<std::string> new_args(args.begin() + argidx, args.end());
+ Pass::call(design, new_args);
+ } catch (log_cmd_error_expection) {
+ for (auto cf : files_to_close)
+ fclose(cf);
+ log_files = backup_log_files;
+ throw log_cmd_error_expection();
+ }
+
+ for (auto cf : files_to_close)
+ fclose(cf);
+ log_files = backup_log_files;
+ }
+} TeePass;
+
diff --git a/passes/cmds/trace.cc b/passes/cmds/trace.cc
new file mode 100644
index 00000000..09293a86
--- /dev/null
+++ b/passes/cmds/trace.cc
@@ -0,0 +1,97 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2014 Johann Glaser <Johann.Glaser@gmx.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+
+PRIVATE_NAMESPACE_BEGIN
+
+struct TraceMonitor : public RTLIL::Monitor
+{
+ virtual void notify_module_add(RTLIL::Module *module) OVERRIDE
+ {
+ log("#TRACE# Module add: %s\n", log_id(module));
+ }
+
+ virtual void notify_module_del(RTLIL::Module *module) OVERRIDE
+ {
+ log("#TRACE# Module delete: %s\n", log_id(module));
+ }
+
+ virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) OVERRIDE
+ {
+ log("#TRACE# Cell connect: %s.%s.%s = %s (was: %s)\n", log_id(cell->module), log_id(cell), log_id(port), log_signal(sig), log_signal(old_sig));
+ }
+
+ virtual void notify_connect(RTLIL::Module *module, const RTLIL::SigSig &sigsig) OVERRIDE
+ {
+ log("#TRACE# Connection in module %s: %s = %s\n", log_id(module), log_signal(sigsig.first), log_signal(sigsig.second));
+ }
+
+ virtual void notify_connect(RTLIL::Module *module, const std::vector<RTLIL::SigSig> &sigsig_vec) OVERRIDE
+ {
+ log("#TRACE# New connections in module %s:\n", log_id(module));
+ for (auto &sigsig : sigsig_vec)
+ log("## %s = %s\n", log_signal(sigsig.first), log_signal(sigsig.second));
+ }
+
+ virtual void notify_blackout(RTLIL::Module *module) OVERRIDE
+ {
+ log("#TRACE# Blackout in module %s:\n", log_id(module));
+ }
+};
+
+struct TracePass : public Pass {
+ TracePass() : Pass("trace", "redirect command output to file") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" trace cmd\n");
+ log("\n");
+ log("Execute the specified command, logging all changes the command performs on\n");
+ log("the design in real time.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // .. parse options ..
+ break;
+ }
+
+ TraceMonitor monitor;
+ design->monitors.insert(&monitor);
+
+ try {
+ std::vector<std::string> new_args(args.begin() + argidx, args.end());
+ Pass::call(design, new_args);
+ } catch (log_cmd_error_expection) {
+ design->monitors.erase(&monitor);
+ throw log_cmd_error_expection();
+ }
+
+ design->monitors.erase(&monitor);
+ }
+} TracePass;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/passes/cmds/write_file.cc b/passes/cmds/write_file.cc
new file mode 100644
index 00000000..813e215b
--- /dev/null
+++ b/passes/cmds/write_file.cc
@@ -0,0 +1,76 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2014 Johann Glaser <Johann.Glaser@gmx.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+
+struct WriteFileFrontend : public Frontend {
+ WriteFileFrontend() : Frontend("=write_file", "write a text to a file") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" write_file [options] output_file [input_file]\n");
+ log("\n");
+ log("Write the text fron the input file to the output file.\n");
+ log("\n");
+ log(" -a\n");
+ log(" Append to output file (instead of overwriting)\n");
+ log("\n");
+ log("\n");
+ log("Inside a script the input file can also can a here-document:\n");
+ log("\n");
+ log(" write_file hello.txt <<EOT\n");
+ log(" Hello World!\n");
+ log(" EOT\n");
+ log("\n");
+ }
+ virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design*)
+ {
+ bool append_mode = false;
+ std::string output_filename;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-a") {
+ append_mode = true;
+ continue;
+ }
+ break;
+ }
+
+ if (argidx < args.size() && args[argidx].rfind("-", 0) != 0)
+ output_filename = args[argidx++];
+ else
+ log_cmd_error("Missing putput filename.\n");
+
+ extra_args(f, filename, args, argidx);
+
+ FILE *of = fopen(output_filename.c_str(), append_mode ? "a" : "w");
+ char buffer[64 * 1024];
+ size_t bytes;
+
+ while (0 < (bytes = f->readsome(buffer, sizeof(buffer))))
+ fwrite(buffer, bytes, 1, of);
+
+ fclose(of);
+ }
+} WriteFileFrontend;
+
diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc
index 13e90910..2fae7609 100644
--- a/passes/fsm/fsm.cc
+++ b/passes/fsm/fsm.cc
@@ -127,12 +127,12 @@ struct FsmPass : public Pass {
Pass::call(design, "fsm_recode" + fm_set_fsm_file_opt + encoding_opt);
Pass::call(design, "fsm_info");
- if (!flag_nomap)
- Pass::call(design, "fsm_map");
-
if (flag_export)
Pass::call(design, "fsm_export");
+ if (!flag_nomap)
+ Pass::call(design, "fsm_map");
+
log_pop();
}
} FsmPass;
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc
index a8ec1912..2c846a4c 100644
--- a/passes/fsm/fsm_detect.cc
+++ b/passes/fsm/fsm_detect.cc
@@ -26,7 +26,7 @@
static RTLIL::Module *module;
static SigMap assign_map;
-typedef std::pair<RTLIL::Cell*,std::string> sig2driver_entry_t;
+typedef std::pair<RTLIL::Cell*, RTLIL::IdString> sig2driver_entry_t;
static SigSet<sig2driver_entry_t> sig2driver, sig2user;
static std::set<RTLIL::Cell*> muxtree_cells;
static SigPool sig_at_port;
@@ -50,14 +50,14 @@ static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, Sig
std::set<sig2driver_entry_t> cellport_list;
sig2driver.find(sig, cellport_list);
for (auto &cellport : cellport_list) {
- if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux" && cellport.first->type != "$safe_pmux") || cellport.second != "\\Y")
+ if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux") || cellport.second != "\\Y")
return false;
- RTLIL::SigSpec sig_a = assign_map(cellport.first->connections["\\A"]);
- RTLIL::SigSpec sig_b = assign_map(cellport.first->connections["\\B"]);
+ RTLIL::SigSpec sig_a = assign_map(cellport.first->getPort("\\A"));
+ RTLIL::SigSpec sig_b = assign_map(cellport.first->getPort("\\B"));
if (!check_state_mux_tree(old_sig, sig_a, recursion_monitor))
return false;
- for (int i = 0; i < sig_b.width; i += sig_a.width)
- if (!check_state_mux_tree(old_sig, sig_b.extract(i, sig_a.width), recursion_monitor))
+ for (int i = 0; i < sig_b.size(); i += sig_a.size())
+ if (!check_state_mux_tree(old_sig, sig_b.extract(i, sig_a.size()), recursion_monitor))
return false;
muxtree_cells.insert(cellport.first);
}
@@ -80,14 +80,14 @@ static bool check_state_users(RTLIL::SigSpec sig)
continue;
if (cellport.second != "\\A" && cellport.second != "\\B")
return false;
- if (cell->connections.count("\\A") == 0 || cell->connections.count("\\B") == 0 || cell->connections.count("\\Y") == 0)
+ if (!cell->hasPort("\\A") || !cell->hasPort("\\B") || !cell->hasPort("\\Y"))
return false;
- for (auto &port_it : cell->connections)
+ for (auto &port_it : cell->connections())
if (port_it.first != "\\A" && port_it.first != "\\B" && port_it.first != "\\Y")
return false;
- if (assign_map(cell->connections["\\A"]) == sig && cell->connections["\\B"].is_fully_const())
+ if (assign_map(cell->getPort("\\A")) == sig && cell->getPort("\\B").is_fully_const())
continue;
- if (assign_map(cell->connections["\\B"]) == sig && cell->connections["\\A"].is_fully_const())
+ if (assign_map(cell->getPort("\\B")) == sig && cell->getPort("\\A").is_fully_const())
continue;
return false;
}
@@ -109,8 +109,8 @@ static void detect_fsm(RTLIL::Wire *wire)
continue;
muxtree_cells.clear();
SigPool recursion_monitor;
- RTLIL::SigSpec sig_q = assign_map(cellport.first->connections["\\Q"]);
- RTLIL::SigSpec sig_d = assign_map(cellport.first->connections["\\D"]);
+ RTLIL::SigSpec sig_q = assign_map(cellport.first->getPort("\\Q"));
+ RTLIL::SigSpec sig_d = assign_map(cellport.first->getPort("\\D"));
if (sig_q == RTLIL::SigSpec(wire) && check_state_mux_tree(sig_q, sig_d, recursion_monitor) && check_state_users(sig_q)) {
log("Found FSM state register %s in module %s.\n", wire->name.c_str(), module->name.c_str());
wire->attributes["\\fsm_encoding"] = RTLIL::Const("auto");
@@ -148,7 +148,7 @@ struct FsmDetectPass : public Pass {
ct.setup_stdcells();
ct.setup_stdcells_mem();
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (!design->selected(mod_it.second))
continue;
@@ -159,8 +159,8 @@ struct FsmDetectPass : public Pass {
sig2driver.clear();
sig2user.clear();
sig_at_port.clear();
- for (auto &cell_it : module->cells)
- for (auto &conn_it : cell_it.second->connections) {
+ for (auto &cell_it : module->cells_)
+ for (auto &conn_it : cell_it.second->connections()) {
if (ct.cell_output(cell_it.second->type, conn_it.first) || !ct.cell_known(cell_it.second->type)) {
RTLIL::SigSpec sig = conn_it.second;
assign_map.apply(sig);
@@ -173,11 +173,11 @@ struct FsmDetectPass : public Pass {
}
}
- for (auto &wire_it : module->wires)
+ for (auto &wire_it : module->wires_)
if (wire_it.second->port_id != 0)
sig_at_port.add(assign_map(RTLIL::SigSpec(wire_it.second)));
- for (auto &wire_it : module->wires)
+ for (auto &wire_it : module->wires_)
if (design->selected(module, wire_it.second))
detect_fsm(wire_it.second);
}
diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc
index 5756b10c..d1364391 100644
--- a/passes/fsm/fsm_expand.cc
+++ b/passes/fsm/fsm_expand.cc
@@ -30,50 +30,50 @@ struct FsmExpand
RTLIL::Module *module;
RTLIL::Cell *fsm_cell;
SigMap assign_map;
- SigSet<RTLIL::Cell*, RTLIL::sort_by_name<RTLIL::Cell>> sig2driver, sig2user;
+ SigSet<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> sig2driver, sig2user;
CellTypes ct;
- std::set<RTLIL::Cell*, RTLIL::sort_by_name<RTLIL::Cell>> merged_set;
- std::set<RTLIL::Cell*, RTLIL::sort_by_name<RTLIL::Cell>> current_set;
- std::set<RTLIL::Cell*, RTLIL::sort_by_name<RTLIL::Cell>> no_candidate_set;
+ std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> merged_set;
+ std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> current_set;
+ std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> no_candidate_set;
bool already_optimized;
int limit_transitions;
bool is_cell_merge_candidate(RTLIL::Cell *cell)
{
- if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux")
- if (cell->connections.at("\\A").width < 2)
+ if (cell->type == "$mux" || cell->type == "$pmux")
+ if (cell->getPort("\\A").size() < 2)
return true;
RTLIL::SigSpec new_signals;
- if (cell->connections.count("\\A") > 0)
- new_signals.append(assign_map(cell->connections["\\A"]));
- if (cell->connections.count("\\B") > 0)
- new_signals.append(assign_map(cell->connections["\\B"]));
- if (cell->connections.count("\\S") > 0)
- new_signals.append(assign_map(cell->connections["\\S"]));
- if (cell->connections.count("\\Y") > 0)
- new_signals.append(assign_map(cell->connections["\\Y"]));
+ if (cell->hasPort("\\A"))
+ new_signals.append(assign_map(cell->getPort("\\A")));
+ if (cell->hasPort("\\B"))
+ new_signals.append(assign_map(cell->getPort("\\B")));
+ if (cell->hasPort("\\S"))
+ new_signals.append(assign_map(cell->getPort("\\S")));
+ if (cell->hasPort("\\Y"))
+ new_signals.append(assign_map(cell->getPort("\\Y")));
new_signals.sort_and_unify();
new_signals.remove_const();
- new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_IN"]));
- new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_OUT"]));
+ new_signals.remove(assign_map(fsm_cell->getPort("\\CTRL_IN")));
+ new_signals.remove(assign_map(fsm_cell->getPort("\\CTRL_OUT")));
- if (new_signals.width > 3)
+ if (new_signals.size() > 3)
return false;
- if (cell->connections.count("\\Y") > 0) {
- new_signals.append(assign_map(cell->connections["\\Y"]));
+ if (cell->hasPort("\\Y")) {
+ new_signals.append(assign_map(cell->getPort("\\Y")));
new_signals.sort_and_unify();
new_signals.remove_const();
- new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_IN"]));
- new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_OUT"]));
+ new_signals.remove(assign_map(fsm_cell->getPort("\\CTRL_IN")));
+ new_signals.remove(assign_map(fsm_cell->getPort("\\CTRL_OUT")));
}
- if (new_signals.width > 2)
+ if (new_signals.size() > 2)
return false;
return true;
@@ -83,10 +83,10 @@ struct FsmExpand
{
std::vector<RTLIL::Cell*> cell_list;
- for (auto c : sig2driver.find(assign_map(fsm_cell->connections["\\CTRL_IN"])))
+ for (auto c : sig2driver.find(assign_map(fsm_cell->getPort("\\CTRL_IN"))))
cell_list.push_back(c);
- for (auto c : sig2user.find(assign_map(fsm_cell->connections["\\CTRL_OUT"])))
+ for (auto c : sig2user.find(assign_map(fsm_cell->getPort("\\CTRL_OUT"))))
cell_list.push_back(c);
current_set.clear();
@@ -94,7 +94,7 @@ struct FsmExpand
{
if (merged_set.count(c) > 0 || current_set.count(c) > 0 || no_candidate_set.count(c) > 0)
continue;
- for (auto &p : c->connections) {
+ for (auto &p : c->connections()) {
if (p.first != "\\A" && p.first != "\\B" && p.first != "\\S" && p.first != "\\Y")
goto next_cell;
}
@@ -135,7 +135,7 @@ struct FsmExpand
RTLIL::SigSpec input_sig, output_sig;
- for (auto &p : cell->connections)
+ for (auto &p : cell->connections())
if (ct.cell_output(cell->type, p.first))
output_sig.append(assign_map(p.second));
else
@@ -145,38 +145,42 @@ struct FsmExpand
std::vector<RTLIL::Const> truth_tab;
- for (int i = 0; i < (1 << input_sig.width); i++) {
- RTLIL::Const in_val(i, input_sig.width);
+ for (int i = 0; i < (1 << input_sig.size()); i++) {
+ RTLIL::Const in_val(i, input_sig.size());
RTLIL::SigSpec A, B, S;
- if (cell->connections.count("\\A") > 0)
- A = assign_map(cell->connections["\\A"]);
- if (cell->connections.count("\\B") > 0)
- B = assign_map(cell->connections["\\B"]);
- if (cell->connections.count("\\S") > 0)
- S = assign_map(cell->connections["\\S"]);
+ if (cell->hasPort("\\A"))
+ A = assign_map(cell->getPort("\\A"));
+ if (cell->hasPort("\\B"))
+ B = assign_map(cell->getPort("\\B"));
+ if (cell->hasPort("\\S"))
+ S = assign_map(cell->getPort("\\S"));
A.replace(input_sig, RTLIL::SigSpec(in_val));
B.replace(input_sig, RTLIL::SigSpec(in_val));
S.replace(input_sig, RTLIL::SigSpec(in_val));
- assert(A.is_fully_const());
- assert(B.is_fully_const());
- assert(S.is_fully_const());
+ log_assert(A.is_fully_const());
+ log_assert(B.is_fully_const());
+ log_assert(S.is_fully_const());
truth_tab.push_back(ct.eval(cell, A.as_const(), B.as_const(), S.as_const()));
}
FsmData fsm_data;
fsm_data.copy_from_cell(fsm_cell);
- fsm_data.num_inputs += input_sig.width;
- fsm_cell->connections["\\CTRL_IN"].append(input_sig);
+ fsm_data.num_inputs += input_sig.size();
+ RTLIL::SigSpec new_ctrl_in = fsm_cell->getPort("\\CTRL_IN");
+ new_ctrl_in.append(input_sig);
+ fsm_cell->setPort("\\CTRL_IN", new_ctrl_in);
- fsm_data.num_outputs += output_sig.width;
- fsm_cell->connections["\\CTRL_OUT"].append(output_sig);
+ fsm_data.num_outputs += output_sig.size();
+ RTLIL::SigSpec new_ctrl_out = fsm_cell->getPort("\\CTRL_OUT");
+ new_ctrl_out.append(output_sig);
+ fsm_cell->setPort("\\CTRL_OUT", new_ctrl_out);
std::vector<FsmData::transition_t> new_transition_table;
for (auto &tr : fsm_data.transition_table) {
- for (int i = 0; i < (1 << input_sig.width); i++) {
+ for (int i = 0; i < (1 << input_sig.size()); i++) {
FsmData::transition_t new_tr = tr;
- RTLIL::Const in_val(i, input_sig.width);
+ RTLIL::Const in_val(i, input_sig.size());
RTLIL::Const out_val = truth_tab[i];
RTLIL::SigSpec ctrl_in = new_tr.ctrl_in;
RTLIL::SigSpec ctrl_out = new_tr.ctrl_out;
@@ -201,10 +205,10 @@ struct FsmExpand
assign_map.set(module);
ct.setup_internals();
- for (auto &cell_it : module->cells) {
+ for (auto &cell_it : module->cells_) {
RTLIL::Cell *c = cell_it.second;
if (ct.cell_known(c->type) && design->selected(mod, c))
- for (auto &p : c->connections) {
+ for (auto &p : c->connections()) {
if (ct.cell_output(c->type, p.first))
sig2driver.insert(assign_map(p.second), c);
else
@@ -226,10 +230,8 @@ struct FsmExpand
merge_cell_into_fsm(c);
}
- for (auto c : merged_set) {
- module->cells.erase(c->name);
- delete c;
- }
+ for (auto c : merged_set)
+ module->remove(c);
if (merged_set.size() > 0 && !already_optimized)
FsmData::optimize_fsm(fsm_cell, module);
@@ -256,11 +258,11 @@ struct FsmExpandPass : public Pass {
log_header("Executing FSM_EXPAND pass (merging auxiliary logic into FSMs).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (!design->selected(mod_it.second))
continue;
std::vector<RTLIL::Cell*> fsm_cells;
- for (auto &cell_it : mod_it.second->cells)
+ for (auto &cell_it : mod_it.second->cells_)
if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second))
fsm_cells.push_back(cell_it.second);
for (auto c : fsm_cells) {
diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc
index cc328ce3..b4a6b3f7 100644
--- a/passes/fsm/fsm_export.cc
+++ b/passes/fsm/fsm_export.cc
@@ -32,10 +32,7 @@
* Convert a signal into a KISS-compatible textual representation.
*/
std::string kiss_convert_signal(const RTLIL::SigSpec &sig) {
- if (!sig.is_fully_const()) {
- throw 0;
- }
-
+ log_assert(sig.is_fully_const());
return sig.as_const().as_string();
}
@@ -59,13 +56,12 @@ void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell, std::st
attr_it = cell->attributes.find("\\fsm_export");
if (!filename.empty()) {
- kiss_name.assign(filename);
+ kiss_name.assign(filename);
} else if (attr_it != cell->attributes.end() && attr_it->second.decode_string() != "") {
kiss_name.assign(attr_it->second.decode_string());
}
else {
- kiss_name.assign(module->name);
- kiss_name.append('-' + cell->name + ".kiss2");
+ kiss_name.assign(log_id(module) + std::string("-") + log_id(cell) + ".kiss2");
}
log("\n");
@@ -174,9 +170,9 @@ struct FsmExportPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
- for (auto &cell_it : mod_it.second->cells)
+ for (auto &cell_it : mod_it.second->cells_)
if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second)) {
attr_it = cell_it.second->attributes.find("\\fsm_export");
if (!flag_noauto || (attr_it != cell_it.second->attributes.end())) {
diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc
index 9cba904a..451f00fc 100644
--- a/passes/fsm/fsm_extract.cc
+++ b/passes/fsm/fsm_extract.cc
@@ -31,56 +31,72 @@
static RTLIL::Module *module;
static SigMap assign_map;
-typedef std::pair<std::string, std::string> sig2driver_entry_t;
+typedef std::pair<RTLIL::IdString, RTLIL::IdString> sig2driver_entry_t;
static SigSet<sig2driver_entry_t> sig2driver, sig2trigger;
+static std::map<RTLIL::SigBit, std::set<RTLIL::SigBit>> exclusive_ctrls;
static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL::SigSpec &ctrl, std::map<RTLIL::Const, int> &states, RTLIL::Const *reset_state = NULL)
{
- sig.extend(dff_out.width, false);
+ sig.extend(dff_out.size(), false);
if (sig == dff_out)
return true;
assign_map.apply(sig);
if (sig.is_fully_const()) {
- sig.optimize();
- assert(sig.chunks.size() == 1);
- if (states.count(sig.chunks[0].data) == 0) {
+ if (sig.is_fully_def() && states.count(sig.as_const()) == 0) {
log(" found state code: %s\n", log_signal(sig));
- states[sig.chunks[0].data] = -1;
+ states[sig.as_const()] = -1;
}
return true;
}
std::set<sig2driver_entry_t> cellport_list;
sig2driver.find(sig, cellport_list);
- for (auto &cellport : cellport_list) {
- RTLIL::Cell *cell = module->cells.at(cellport.first);
- if ((cell->type != "$mux" && cell->type != "$pmux" && cell->type != "$safe_pmux") || cellport.second != "\\Y") {
+ for (auto &cellport : cellport_list)
+ {
+ RTLIL::Cell *cell = module->cells_.at(cellport.first);
+ if ((cell->type != "$mux" && cell->type != "$pmux") || cellport.second != "\\Y") {
log(" unexpected cell type %s (%s) found in state selection tree.\n", cell->type.c_str(), cell->name.c_str());
return false;
}
- RTLIL::SigSpec sig_a = assign_map(cell->connections["\\A"]);
- RTLIL::SigSpec sig_b = assign_map(cell->connections["\\B"]);
- RTLIL::SigSpec sig_s = assign_map(cell->connections["\\S"]);
+
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec sig_s = assign_map(cell->getPort("\\S"));
+ RTLIL::SigSpec sig_y = assign_map(cell->getPort("\\Y"));
+
+ RTLIL::SigSpec sig_aa = sig;
+ sig_aa.replace(sig_y, sig_a);
+
+ RTLIL::SigSpec sig_bb;
+ for (int i = 0; i < SIZE(sig_b)/SIZE(sig_a); i++) {
+ RTLIL::SigSpec s = sig;
+ s.replace(sig_y, sig_b.extract(i*SIZE(sig_a), SIZE(sig_a)));
+ sig_bb.append(s);
+ }
+
if (reset_state && RTLIL::SigSpec(*reset_state).is_fully_undef())
do {
- if (sig_a.is_fully_def())
- *reset_state = sig_a.as_const();
- else if (sig_b.is_fully_def())
- *reset_state = sig_b.as_const();
+ if (sig_aa.is_fully_def())
+ *reset_state = sig_aa.as_const();
+ else if (sig_bb.is_fully_def())
+ *reset_state = sig_bb.as_const();
else
break;
log(" found reset state: %s (guessed from mux tree)\n", log_signal(*reset_state));
} while (0);
- if (ctrl.extract(sig_s).width == 0) {
+
+ if (ctrl.extract(sig_s).size() == 0) {
log(" found ctrl input: %s\n", log_signal(sig_s));
ctrl.append(sig_s);
}
- if (!find_states(sig_a, dff_out, ctrl, states))
+
+ if (!find_states(sig_aa, dff_out, ctrl, states))
return false;
- for (int i = 0; i < sig_b.width/sig_a.width; i++) {
- if (!find_states(sig_b.extract(i*sig_a.width, sig_a.width), dff_out, ctrl, states))
+
+ for (int i = 0; i < SIZE(sig_bb)/SIZE(sig_aa); i++) {
+ if (!find_states(sig_bb.extract(i*SIZE(sig_aa), SIZE(sig_aa)), dff_out, ctrl, states))
return false;
}
}
@@ -90,47 +106,69 @@ static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL
static RTLIL::Const sig2const(ConstEval &ce, RTLIL::SigSpec sig, RTLIL::State noconst_state, RTLIL::SigSpec dont_care = RTLIL::SigSpec())
{
- if (dont_care.width > 0) {
- sig.expand();
- for (auto &chunk : sig.chunks) {
- assert(chunk.width == 1);
- if (dont_care.extract(chunk).width > 0)
- chunk.wire = NULL, chunk.data = RTLIL::Const(noconst_state);
- }
- sig.optimize();
+ if (dont_care.size() > 0) {
+ for (int i = 0; i < SIZE(sig); i++)
+ if (dont_care.extract(sig[i]).size() > 0)
+ sig[i] = noconst_state;
}
ce.assign_map.apply(sig);
ce.values_map.apply(sig);
- sig.expand();
- for (auto &chunk : sig.chunks) {
- assert(chunk.width == 1);
- if (chunk.wire != NULL)
- chunk.wire = NULL, chunk.data = RTLIL::Const(noconst_state);
- }
- sig.optimize();
+ for (int i = 0; i < SIZE(sig); i++)
+ if (sig[i].wire != NULL)
+ sig[i] = noconst_state;
- if (sig.width == 0)
- return RTLIL::Const();
- assert(sig.chunks.size() == 1 && sig.chunks[0].wire == NULL);
- return sig.chunks[0].data;
+ return sig.as_const();
}
static void find_transitions(ConstEval &ce, ConstEval &ce_nostop, FsmData &fsm_data, std::map<RTLIL::Const, int> &states, int state_in, RTLIL::SigSpec ctrl_in, RTLIL::SigSpec ctrl_out, RTLIL::SigSpec dff_in, RTLIL::SigSpec dont_care)
{
+ bool undef_bit_in_next_state_mode = false;
RTLIL::SigSpec undef, constval;
- if (ce.eval(ctrl_out, undef) && ce.eval(dff_in, undef)) {
- assert(ctrl_out.is_fully_const() && dff_in.is_fully_const());
+ if (ce.eval(ctrl_out, undef) && ce.eval(dff_in, undef))
+ {
+ if (0) {
+undef_bit_in_next_state:
+ for (auto &bit : dff_in)
+ if (bit.wire != nullptr) bit = RTLIL::Sm;
+ for (auto &bit : ctrl_out)
+ if (bit.wire != nullptr) bit = RTLIL::Sm;
+ undef_bit_in_next_state_mode = true;
+ }
+
+ log_assert(ctrl_out.is_fully_const() && dff_in.is_fully_const());
+
FsmData::transition_t tr;
- tr.state_in = state_in;
- tr.state_out = states[ce.values_map(ce.assign_map(dff_in)).as_const()];
tr.ctrl_in = sig2const(ce, ctrl_in, RTLIL::State::Sa, dont_care);
tr.ctrl_out = sig2const(ce, ctrl_out, RTLIL::State::Sx);
+
+ std::map<RTLIL::SigBit, int> ctrl_in_bit_indices;
+ for (int i = 0; i < SIZE(ctrl_in); i++)
+ ctrl_in_bit_indices[ctrl_in[i]] = i;
+
+ for (auto &it : ctrl_in_bit_indices)
+ if (tr.ctrl_in.bits.at(it.second) == RTLIL::S1 && exclusive_ctrls.count(it.first) != 0)
+ for (auto &dc_bit : exclusive_ctrls.at(it.first))
+ if (ctrl_in_bit_indices.count(dc_bit))
+ tr.ctrl_in.bits.at(ctrl_in_bit_indices.at(dc_bit)) = RTLIL::State::Sa;
+
RTLIL::Const log_state_in = RTLIL::Const(RTLIL::State::Sx, fsm_data.state_bits);
if (state_in >= 0)
- log_state_in = fsm_data.state_table[tr.state_in];
+ log_state_in = fsm_data.state_table.at(state_in);
+
+ if (states.count(ce.values_map(ce.assign_map(dff_in)).as_const()) == 0) {
+ log(" transition: %10s %s -> INVALID_STATE(%s) %s <ignored invalid transistion!>%s\n",
+ log_signal(log_state_in), log_signal(tr.ctrl_in),
+ log_signal(ce.values_map(ce.assign_map(dff_in))), log_signal(tr.ctrl_out),
+ undef_bit_in_next_state_mode ? " SHORTENED" : "");
+ return;
+ }
+
+ tr.state_in = state_in;
+ tr.state_out = states.at(ce.values_map(ce.assign_map(dff_in)).as_const());
+
if (dff_in.is_fully_def()) {
fsm_data.transition_table.push_back(tr);
log(" transition: %10s %s -> %10s %s\n",
@@ -144,7 +182,11 @@ static void find_transitions(ConstEval &ce, ConstEval &ce_nostop, FsmData &fsm_d
return;
}
- log_assert(undef.width > 0);
+ for (auto &bit : dff_in)
+ if (bit == RTLIL::Sx)
+ goto undef_bit_in_next_state;
+
+ log_assert(undef.size() > 0);
log_assert(ce.stop_signals.check_all(undef));
undef = undef.extract(0, 1);
@@ -155,21 +197,39 @@ static void find_transitions(ConstEval &ce, ConstEval &ce_nostop, FsmData &fsm_d
ce.push();
dont_care.append(undef);
ce.set(undef, constval.as_const());
+ if (exclusive_ctrls.count(undef) && constval == RTLIL::S1)
+ for (auto &bit : exclusive_ctrls.at(undef)) {
+ RTLIL::SigSpec bitval = bit;
+ if (ce.eval(bitval) && bitval != RTLIL::S0)
+ goto found_contradiction_1;
+ else
+ ce.set(bit, RTLIL::S0);
+ }
find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care);
+ found_contradiction_1:
ce.pop();
}
else
{
ce.push(), ce_nostop.push();
- ce.set(undef, RTLIL::Const(0, 1));
- ce_nostop.set(undef, RTLIL::Const(0, 1));
+ ce.set(undef, RTLIL::S0);
+ ce_nostop.set(undef, RTLIL::S0);
find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care);
ce.pop(), ce_nostop.pop();
ce.push(), ce_nostop.push();
- ce.set(undef, RTLIL::Const(1, 1));
- ce_nostop.set(undef, RTLIL::Const(1, 1));
+ ce.set(undef, RTLIL::S1);
+ ce_nostop.set(undef, RTLIL::S1);
+ if (exclusive_ctrls.count(undef))
+ for (auto &bit : exclusive_ctrls.at(undef)) {
+ RTLIL::SigSpec bitval = bit;
+ if ((ce.eval(bitval) || ce_nostop.eval(bitval)) && bitval != RTLIL::S0)
+ goto found_contradiction_2;
+ else
+ ce.set(bit, RTLIL::S0), ce_nostop.set(bit, RTLIL::S0);
+ }
find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care);
+ found_contradiction_2:
ce.pop(), ce_nostop.pop();
}
}
@@ -184,24 +244,24 @@ static void extract_fsm(RTLIL::Wire *wire)
RTLIL::SigSpec dff_in(RTLIL::State::Sm, wire->width);
RTLIL::Const reset_state(RTLIL::State::Sx, wire->width);
- RTLIL::SigSpec clk = RTLIL::SigSpec(0, 1);
- RTLIL::SigSpec arst = RTLIL::SigSpec(0, 1);
+ RTLIL::SigSpec clk = RTLIL::S0;
+ RTLIL::SigSpec arst = RTLIL::S0;
bool clk_polarity = true;
bool arst_polarity = true;
std::set<sig2driver_entry_t> cellport_list;
sig2driver.find(dff_out, cellport_list);
for (auto &cellport : cellport_list) {
- RTLIL::Cell *cell = module->cells.at(cellport.first);
+ RTLIL::Cell *cell = module->cells_.at(cellport.first);
if ((cell->type != "$dff" && cell->type != "$adff") || cellport.second != "\\Q")
continue;
log(" found %s cell for state register: %s\n", cell->type.c_str(), cell->name.c_str());
- RTLIL::SigSpec sig_q = assign_map(cell->connections["\\Q"]);
- RTLIL::SigSpec sig_d = assign_map(cell->connections["\\D"]);
- clk = cell->connections["\\CLK"];
+ RTLIL::SigSpec sig_q = assign_map(cell->getPort("\\Q"));
+ RTLIL::SigSpec sig_d = assign_map(cell->getPort("\\D"));
+ clk = cell->getPort("\\CLK");
clk_polarity = cell->parameters["\\CLK_POLARITY"].as_bool();
if (cell->type == "$adff") {
- arst = cell->connections["\\ARST"];
+ arst = cell->getPort("\\ARST");
arst_polarity = cell->parameters["\\ARST_POLARITY"].as_bool();
reset_state = cell->parameters["\\ARST_VALUE"];
}
@@ -227,6 +287,10 @@ static void extract_fsm(RTLIL::Wire *wire)
log(" fsm extraction failed: state selection tree is not closed.\n");
return;
}
+ if (SIZE(states) <= 1) {
+ log(" fsm extraction failed: at least two states are required.\n");
+ return;
+ }
// find control outputs
// (add the state signals to the list of control outputs. if everything goes right, this signals
@@ -236,10 +300,10 @@ static void extract_fsm(RTLIL::Wire *wire)
cellport_list.clear();
sig2trigger.find(dff_out, cellport_list);
for (auto &cellport : cellport_list) {
- RTLIL::Cell *cell = module->cells.at(cellport.first);
- RTLIL::SigSpec sig_a = assign_map(cell->connections["\\A"]);
- RTLIL::SigSpec sig_b = assign_map(cell->connections["\\B"]);
- RTLIL::SigSpec sig_y = assign_map(cell->connections["\\Y"]);
+ RTLIL::Cell *cell = module->cells_.at(cellport.first);
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec sig_y = assign_map(cell->getPort("\\Y"));
if (cellport.second == "\\A" && !sig_b.is_fully_const())
continue;
if (cellport.second == "\\B" && !sig_a.is_fully_const())
@@ -258,8 +322,8 @@ static void extract_fsm(RTLIL::Wire *wire)
// Initialize fsm data struct
FsmData fsm_data;
- fsm_data.num_inputs = ctrl_in.width;
- fsm_data.num_outputs = ctrl_out.width;
+ fsm_data.num_inputs = ctrl_in.size();
+ fsm_data.num_outputs = ctrl_out.size();
fsm_data.state_bits = wire->width;
fsm_data.reset_state = -1;
for (auto &it : states) {
@@ -283,40 +347,34 @@ static void extract_fsm(RTLIL::Wire *wire)
// create fsm cell
- RTLIL::Cell *fsm_cell = new RTLIL::Cell;
- fsm_cell->name = stringf("$fsm$%s$%d", wire->name.c_str(), RTLIL::autoidx++);
- fsm_cell->type = "$fsm";
- fsm_cell->connections["\\CLK"] = clk;
- fsm_cell->connections["\\ARST"] = arst;
- fsm_cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity ? 1 : 0, 1);
- fsm_cell->parameters["\\ARST_POLARITY"] = RTLIL::Const(arst_polarity ? 1 : 0, 1);
- fsm_cell->connections["\\CTRL_IN"] = ctrl_in;
- fsm_cell->connections["\\CTRL_OUT"] = ctrl_out;
- fsm_cell->parameters["\\NAME"] = RTLIL::Const(wire->name);
+ RTLIL::Cell *fsm_cell = module->addCell(stringf("$fsm$%s$%d", wire->name.c_str(), autoidx++), "$fsm");
+ fsm_cell->setPort("\\CLK", clk);
+ fsm_cell->setPort("\\ARST", arst);
+ fsm_cell->parameters["\\CLK_POLARITY"] = clk_polarity ? RTLIL::S1 : RTLIL::S0;
+ fsm_cell->parameters["\\ARST_POLARITY"] = arst_polarity ? RTLIL::S1 : RTLIL::S0;
+ fsm_cell->setPort("\\CTRL_IN", ctrl_in);
+ fsm_cell->setPort("\\CTRL_OUT", ctrl_out);
+ fsm_cell->parameters["\\NAME"] = RTLIL::Const(wire->name.str());
fsm_cell->attributes = wire->attributes;
fsm_data.copy_to_cell(fsm_cell);
- module->cells[fsm_cell->name] = fsm_cell;
// rename original state wire
- module->wires.erase(wire->name);
+ module->wires_.erase(wire->name);
wire->attributes.erase("\\fsm_encoding");
wire->name = stringf("$fsm$oldstate%s", wire->name.c_str());
- module->wires[wire->name] = wire;
+ module->wires_[wire->name] = wire;
// unconnect control outputs from old drivers
cellport_list.clear();
sig2driver.find(ctrl_out, cellport_list);
for (auto &cellport : cellport_list) {
- RTLIL::Cell *cell = module->cells.at(cellport.first);
- RTLIL::SigSpec port_sig = assign_map(cell->connections[cellport.second]);
+ RTLIL::Cell *cell = module->cells_.at(cellport.first);
+ RTLIL::SigSpec port_sig = assign_map(cell->getPort(cellport.second));
RTLIL::SigSpec unconn_sig = port_sig.extract(ctrl_out);
- RTLIL::Wire *unconn_wire = new RTLIL::Wire;
- unconn_wire->name = stringf("$fsm_unconnect$%s$%d", log_signal(unconn_sig), RTLIL::autoidx++);
- unconn_wire->width = unconn_sig.width;
- module->wires[unconn_wire->name] = unconn_wire;
- port_sig.replace(unconn_sig, RTLIL::SigSpec(unconn_wire), &cell->connections[cellport.second]);
+ RTLIL::Wire *unconn_wire = module->addWire(stringf("$fsm_unconnect$%s$%d", log_signal(unconn_sig), autoidx++), unconn_sig.size());
+ port_sig.replace(unconn_sig, RTLIL::SigSpec(unconn_wire), &cell->connections_[cellport.second]);
}
}
@@ -349,7 +407,7 @@ struct FsmExtractPass : public Pass {
ct.setup_stdcells();
ct.setup_stdcells_mem();
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (!design->selected(mod_it.second))
continue;
@@ -359,23 +417,32 @@ struct FsmExtractPass : public Pass {
sig2driver.clear();
sig2trigger.clear();
- for (auto &cell_it : module->cells)
- for (auto &conn_it : cell_it.second->connections) {
- if (ct.cell_output(cell_it.second->type, conn_it.first) || !ct.cell_known(cell_it.second->type)) {
+ exclusive_ctrls.clear();
+ for (auto cell : module->cells()) {
+ for (auto &conn_it : cell->connections()) {
+ if (ct.cell_output(cell->type, conn_it.first) || !ct.cell_known(cell->type)) {
RTLIL::SigSpec sig = conn_it.second;
assign_map.apply(sig);
- sig2driver.insert(sig, sig2driver_entry_t(cell_it.first, conn_it.first));
+ sig2driver.insert(sig, sig2driver_entry_t(cell->name, conn_it.first));
}
- if (ct.cell_input(cell_it.second->type, conn_it.first) && cell_it.second->connections.count("\\Y") > 0 &&
- cell_it.second->connections["\\Y"].width == 1 && (conn_it.first == "\\A" || conn_it.first == "\\B")) {
+ if (ct.cell_input(cell->type, conn_it.first) && cell->hasPort("\\Y") &&
+ cell->getPort("\\Y").size() == 1 && (conn_it.first == "\\A" || conn_it.first == "\\B")) {
RTLIL::SigSpec sig = conn_it.second;
assign_map.apply(sig);
- sig2trigger.insert(sig, sig2driver_entry_t(cell_it.first, conn_it.first));
+ sig2trigger.insert(sig, sig2driver_entry_t(cell->name, conn_it.first));
}
}
+ if (cell->type == "$pmux") {
+ RTLIL::SigSpec sel_sig = assign_map(cell->getPort("\\S"));
+ for (auto &bit1 : sel_sig)
+ for (auto &bit2 : sel_sig)
+ if (bit1 != bit2)
+ exclusive_ctrls[bit1].insert(bit2);
+ }
+ }
std::vector<RTLIL::Wire*> wire_list;
- for (auto &wire_it : module->wires)
+ for (auto &wire_it : module->wires_)
if (wire_it.second->attributes.count("\\fsm_encoding") > 0 && wire_it.second->attributes["\\fsm_encoding"].decode_string() != "none")
if (design->selected(module, wire_it.second))
wire_list.push_back(wire_it.second);
diff --git a/passes/fsm/fsm_info.cc b/passes/fsm/fsm_info.cc
index f2d0c1a8..45d68a90 100644
--- a/passes/fsm/fsm_info.cc
+++ b/passes/fsm/fsm_info.cc
@@ -43,9 +43,9 @@ struct FsmInfoPass : public Pass {
log_header("Executing FSM_INFO pass (dumping all available information on FSM cells).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
- for (auto &cell_it : mod_it.second->cells)
+ for (auto &cell_it : mod_it.second->cells_)
if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second)) {
log("\n");
log("FSM `%s' from module `%s':\n", cell_it.second->name.c_str(), mod_it.first.c_str());
diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc
index c30cf1fe..ab6d5671 100644
--- a/passes/fsm/fsm_map.cc
+++ b/passes/fsm/fsm_map.cc
@@ -25,12 +25,26 @@
#include "fsmdata.h"
#include <string.h>
+static bool pattern_is_subset(const RTLIL::Const &super_pattern, const RTLIL::Const &sub_pattern)
+{
+ log_assert(SIZE(super_pattern.bits) == SIZE(sub_pattern.bits));
+ for (int i = 0; i < SIZE(super_pattern.bits); i++)
+ if (sub_pattern.bits[i] == RTLIL::State::S0 || sub_pattern.bits[i] == RTLIL::State::S1) {
+ if (super_pattern.bits[i] == RTLIL::State::S0 || super_pattern.bits[i] == RTLIL::State::S1) {
+ if (super_pattern.bits[i] != sub_pattern.bits[i])
+ return false;
+ } else
+ return false;
+ }
+ return true;
+}
+
static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const, std::set<int>> &pattern_cache, std::set<int> &fullstate_cache, int num_states, RTLIL::Wire *state_onehot, RTLIL::SigSpec &ctrl_in, RTLIL::SigSpec output)
{
RTLIL::SigSpec cases_vector;
for (int in_state : fullstate_cache)
- cases_vector.append(RTLIL::SigSpec(state_onehot, 1, in_state));
+ cases_vector.append(RTLIL::SigSpec(state_onehot, in_state));
for (auto &it : pattern_cache)
{
@@ -42,89 +56,74 @@ static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const
eq_sig_a.append(ctrl_in.extract(j, 1));
eq_sig_b.append(RTLIL::SigSpec(pattern.bits[j]));
}
- eq_sig_a.optimize();
- eq_sig_b.optimize();
for (int in_state : it.second)
if (fullstate_cache.count(in_state) == 0)
- or_sig.append(RTLIL::SigSpec(state_onehot, 1, in_state));
- or_sig.optimize();
+ or_sig.append(RTLIL::SigSpec(state_onehot, in_state));
- if (or_sig.width == 0)
+ if (or_sig.size() == 0)
continue;
RTLIL::SigSpec and_sig;
- if (eq_sig_a.width > 0)
+ if (eq_sig_a.size() > 0)
{
- RTLIL::Wire *eq_wire = new RTLIL::Wire;
- eq_wire->name = NEW_ID;
- module->add(eq_wire);
-
- RTLIL::Cell *eq_cell = new RTLIL::Cell;
- eq_cell->name = NEW_ID;
- eq_cell->type = "$eq";
- eq_cell->connections["\\A"] = eq_sig_a;
- eq_cell->connections["\\B"] = eq_sig_b;
- eq_cell->connections["\\Y"] = RTLIL::SigSpec(eq_wire);
+ RTLIL::Wire *eq_wire = module->addWire(NEW_ID);
+ and_sig.append(RTLIL::SigSpec(eq_wire));
+
+ RTLIL::Cell *eq_cell = module->addCell(NEW_ID, "$eq");
+ eq_cell->setPort("\\A", eq_sig_a);
+ eq_cell->setPort("\\B", eq_sig_b);
+ eq_cell->setPort("\\Y", RTLIL::SigSpec(eq_wire));
eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(false);
- eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(eq_sig_a.width);
- eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(eq_sig_b.width);
+ eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(eq_sig_a.size());
+ eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(eq_sig_b.size());
eq_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- module->add(eq_cell);
-
- and_sig.append(RTLIL::SigSpec(eq_wire));
}
- if (or_sig.width < num_states-int(fullstate_cache.size()))
+ std::set<int> complete_in_state_cache = it.second;
+
+ for (auto &it2 : pattern_cache)
+ if (pattern_is_subset(pattern, it2.first))
+ complete_in_state_cache.insert(it2.second.begin(), it2.second.end());
+
+ if (SIZE(complete_in_state_cache) < num_states)
{
- if (or_sig.width == 1)
+ if (or_sig.size() == 1)
{
and_sig.append(or_sig);
}
else
{
- RTLIL::Wire *or_wire = new RTLIL::Wire;
- or_wire->name = NEW_ID;
- module->add(or_wire);
-
- RTLIL::Cell *or_cell = new RTLIL::Cell;
- or_cell->name = NEW_ID;
- or_cell->type = "$reduce_or";
- or_cell->connections["\\A"] = or_sig;
- or_cell->connections["\\Y"] = RTLIL::SigSpec(or_wire);
+ RTLIL::Wire *or_wire = module->addWire(NEW_ID);
+ and_sig.append(RTLIL::SigSpec(or_wire));
+
+ RTLIL::Cell *or_cell = module->addCell(NEW_ID, "$reduce_or");
+ or_cell->setPort("\\A", or_sig);
+ or_cell->setPort("\\Y", RTLIL::SigSpec(or_wire));
or_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
- or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(or_sig.width);
+ or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(or_sig.size());
or_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- module->add(or_cell);
-
- and_sig.append(RTLIL::SigSpec(or_wire));
}
}
- switch (and_sig.width)
+ switch (and_sig.size())
{
case 2:
{
- RTLIL::Wire *and_wire = new RTLIL::Wire;
- and_wire->name = NEW_ID;
- module->add(and_wire);
-
- RTLIL::Cell *and_cell = new RTLIL::Cell;
- and_cell->name = NEW_ID;
- and_cell->type = "$and";
- and_cell->connections["\\A"] = and_sig.extract(0, 1);
- and_cell->connections["\\B"] = and_sig.extract(1, 1);
- and_cell->connections["\\Y"] = RTLIL::SigSpec(and_wire);
+ RTLIL::Wire *and_wire = module->addWire(NEW_ID);
+ cases_vector.append(RTLIL::SigSpec(and_wire));
+
+ RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$and");
+ and_cell->setPort("\\A", and_sig.extract(0, 1));
+ and_cell->setPort("\\B", and_sig.extract(1, 1));
+ and_cell->setPort("\\Y", RTLIL::SigSpec(and_wire));
and_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
and_cell->parameters["\\B_SIGNED"] = RTLIL::Const(false);
and_cell->parameters["\\A_WIDTH"] = RTLIL::Const(1);
and_cell->parameters["\\B_WIDTH"] = RTLIL::Const(1);
and_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- module->add(and_cell);
-
- cases_vector.append(RTLIL::SigSpec(and_wire));
break;
}
case 1:
@@ -138,20 +137,17 @@ static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const
}
}
- if (cases_vector.width > 1) {
- RTLIL::Cell *or_cell = new RTLIL::Cell;
- or_cell->name = NEW_ID;
- or_cell->type = "$reduce_or";
- or_cell->connections["\\A"] = cases_vector;
- or_cell->connections["\\Y"] = output;
+ if (cases_vector.size() > 1) {
+ RTLIL::Cell *or_cell = module->addCell(NEW_ID, "$reduce_or");
+ or_cell->setPort("\\A", cases_vector);
+ or_cell->setPort("\\Y", output);
or_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
- or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(cases_vector.width);
+ or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(cases_vector.size());
or_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- module->add(or_cell);
- } else if (cases_vector.width == 1) {
- module->connections.push_back(RTLIL::SigSig(output, cases_vector));
+ } else if (cases_vector.size() == 1) {
+ module->connect(RTLIL::SigSig(output, cases_vector));
} else {
- module->connections.push_back(RTLIL::SigSig(output, RTLIL::SigSpec(0, 1)));
+ module->connect(RTLIL::SigSig(output, RTLIL::SigSpec(0, 1)));
}
}
@@ -162,26 +158,16 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
FsmData fsm_data;
fsm_data.copy_from_cell(fsm_cell);
- RTLIL::SigSpec ctrl_in = fsm_cell->connections["\\CTRL_IN"];
- RTLIL::SigSpec ctrl_out = fsm_cell->connections["\\CTRL_OUT"];
+ RTLIL::SigSpec ctrl_in = fsm_cell->getPort("\\CTRL_IN");
+ RTLIL::SigSpec ctrl_out = fsm_cell->getPort("\\CTRL_OUT");
// create state register
- RTLIL::Wire *state_wire = new RTLIL::Wire;
- state_wire->name = fsm_cell->parameters["\\NAME"].decode_string();
- while (module->count_id(state_wire->name) > 0)
- state_wire->name += "_";
- state_wire->width = fsm_data.state_bits;
- module->add(state_wire);
-
- RTLIL::Wire *next_state_wire = new RTLIL::Wire;
- next_state_wire->name = NEW_ID;
- next_state_wire->width = fsm_data.state_bits;
- module->add(next_state_wire);
-
- RTLIL::Cell *state_dff = new RTLIL::Cell;
- state_dff->name = NEW_ID;
- if (fsm_cell->connections["\\ARST"].is_fully_const()) {
+ RTLIL::Wire *state_wire = module->addWire(module->uniquify(fsm_cell->parameters["\\NAME"].decode_string()), fsm_data.state_bits);
+ RTLIL::Wire *next_state_wire = module->addWire(NEW_ID, fsm_data.state_bits);
+
+ RTLIL::Cell *state_dff = module->addCell(NEW_ID, "");
+ if (fsm_cell->getPort("\\ARST").is_fully_const()) {
state_dff->type = "$dff";
} else {
state_dff->type = "$adff";
@@ -190,23 +176,19 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
for (auto &bit : state_dff->parameters["\\ARST_VALUE"].bits)
if (bit != RTLIL::State::S1)
bit = RTLIL::State::S0;
- state_dff->connections["\\ARST"] = fsm_cell->connections["\\ARST"];
+ state_dff->setPort("\\ARST", fsm_cell->getPort("\\ARST"));
}
state_dff->parameters["\\WIDTH"] = RTLIL::Const(fsm_data.state_bits);
state_dff->parameters["\\CLK_POLARITY"] = fsm_cell->parameters["\\CLK_POLARITY"];
- state_dff->connections["\\CLK"] = fsm_cell->connections["\\CLK"];
- state_dff->connections["\\D"] = RTLIL::SigSpec(next_state_wire);
- state_dff->connections["\\Q"] = RTLIL::SigSpec(state_wire);
- module->add(state_dff);
+ state_dff->setPort("\\CLK", fsm_cell->getPort("\\CLK"));
+ state_dff->setPort("\\D", RTLIL::SigSpec(next_state_wire));
+ state_dff->setPort("\\Q", RTLIL::SigSpec(state_wire));
// decode state register
bool encoding_is_onehot = true;
- RTLIL::Wire *state_onehot = new RTLIL::Wire;
- state_onehot->name = NEW_ID;
- state_onehot->width = fsm_data.state_table.size();
- module->add(state_onehot);
+ RTLIL::Wire *state_onehot = module->addWire(NEW_ID, fsm_data.state_table.size());
for (size_t i = 0; i < fsm_data.state_table.size(); i++)
{
@@ -215,111 +197,102 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
for (size_t j = 0; j < state.bits.size(); j++)
if (state.bits[j] == RTLIL::State::S0 || state.bits[j] == RTLIL::State::S1) {
- sig_a.append(RTLIL::SigSpec(state_wire, 1, j));
+ sig_a.append(RTLIL::SigSpec(state_wire, j));
sig_b.append(RTLIL::SigSpec(state.bits[j]));
}
- sig_a.optimize();
- sig_b.optimize();
if (sig_b == RTLIL::SigSpec(RTLIL::State::S1))
{
- module->connections.push_back(RTLIL::SigSig(RTLIL::SigSpec(state_onehot, 1, i), sig_a));
+ module->connect(RTLIL::SigSig(RTLIL::SigSpec(state_onehot, i), sig_a));
}
else
{
encoding_is_onehot = false;
- RTLIL::Cell *eq_cell = new RTLIL::Cell;
- eq_cell->name = NEW_ID;
- eq_cell->type = "$eq";
- eq_cell->connections["\\A"] = sig_a;
- eq_cell->connections["\\B"] = sig_b;
- eq_cell->connections["\\Y"] = RTLIL::SigSpec(state_onehot, 1, i);
+ RTLIL::Cell *eq_cell = module->addCell(NEW_ID, "$eq");
+ eq_cell->setPort("\\A", sig_a);
+ eq_cell->setPort("\\B", sig_b);
+ eq_cell->setPort("\\Y", RTLIL::SigSpec(state_onehot, i));
eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(false);
- eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig_a.width);
- eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(sig_b.width);
+ eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig_a.size());
+ eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(sig_b.size());
eq_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- module->add(eq_cell);
}
}
// generate next_state signal
- RTLIL::Wire *next_state_onehot = new RTLIL::Wire;
- next_state_onehot->name = NEW_ID;
- next_state_onehot->width = fsm_data.state_table.size();
- module->add(next_state_onehot);
-
- for (size_t i = 0; i < fsm_data.state_table.size(); i++)
+ if (SIZE(fsm_data.state_table) == 1)
{
- std::map<RTLIL::Const, std::set<int>> pattern_cache;
- std::set<int> fullstate_cache;
+ module->connect(next_state_wire, fsm_data.state_table.front());
+ }
+ else
+ {
+ RTLIL::Wire *next_state_onehot = module->addWire(NEW_ID, fsm_data.state_table.size());
- for (size_t j = 0; j < fsm_data.state_table.size(); j++)
- fullstate_cache.insert(j);
+ for (size_t i = 0; i < fsm_data.state_table.size(); i++)
+ {
+ std::map<RTLIL::Const, std::set<int>> pattern_cache;
+ std::set<int> fullstate_cache;
- for (auto &tr : fsm_data.transition_table) {
- if (tr.state_out == int(i))
- pattern_cache[tr.ctrl_in].insert(tr.state_in);
- else
- fullstate_cache.erase(tr.state_in);
- }
+ for (size_t j = 0; j < fsm_data.state_table.size(); j++)
+ fullstate_cache.insert(j);
- implement_pattern_cache(module, pattern_cache, fullstate_cache, fsm_data.state_table.size(), state_onehot, ctrl_in, RTLIL::SigSpec(next_state_onehot, 1, i));
- }
+ for (auto &tr : fsm_data.transition_table) {
+ if (tr.state_out == int(i))
+ pattern_cache[tr.ctrl_in].insert(tr.state_in);
+ else
+ fullstate_cache.erase(tr.state_in);
+ }
- if (encoding_is_onehot)
- {
- RTLIL::SigSpec next_state_sig(RTLIL::State::Sm, next_state_wire->width);
- for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
- RTLIL::Const state = fsm_data.state_table[i];
- int bit_idx = -1;
- for (size_t j = 0; j < state.bits.size(); j++)
- if (state.bits[j] == RTLIL::State::S1)
- bit_idx = j;
- if (bit_idx >= 0)
- next_state_sig.replace(bit_idx, RTLIL::SigSpec(next_state_onehot, 1, i));
+ implement_pattern_cache(module, pattern_cache, fullstate_cache, fsm_data.state_table.size(), state_onehot, ctrl_in, RTLIL::SigSpec(next_state_onehot, i));
}
- log_assert(!next_state_sig.has_marked_bits());
- module->connections.push_back(RTLIL::SigSig(next_state_wire, next_state_sig));
- }
- else
- {
- RTLIL::SigSpec sig_a, sig_b, sig_s;
- int reset_state = fsm_data.reset_state;
- if (reset_state < 0)
- reset_state = 0;
-
- for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
- RTLIL::Const state = fsm_data.state_table[i];
- if (int(i) == fsm_data.reset_state) {
- sig_a = RTLIL::SigSpec(state);
- } else {
- sig_b.append(RTLIL::SigSpec(state));
- sig_s.append(RTLIL::SigSpec(next_state_onehot, 1, i));
+
+ if (encoding_is_onehot)
+ {
+ RTLIL::SigSpec next_state_sig(RTLIL::State::Sm, next_state_wire->width);
+ for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
+ RTLIL::Const state = fsm_data.state_table[i];
+ int bit_idx = -1;
+ for (size_t j = 0; j < state.bits.size(); j++)
+ if (state.bits[j] == RTLIL::State::S1)
+ bit_idx = j;
+ if (bit_idx >= 0)
+ next_state_sig.replace(bit_idx, RTLIL::SigSpec(next_state_onehot, i));
}
+ log_assert(!next_state_sig.has_marked_bits());
+ module->connect(RTLIL::SigSig(next_state_wire, next_state_sig));
}
+ else
+ {
+ RTLIL::SigSpec sig_a, sig_b, sig_s;
+ int reset_state = fsm_data.reset_state;
+ if (reset_state < 0)
+ reset_state = 0;
+
+ for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
+ RTLIL::Const state = fsm_data.state_table[i];
+ if (int(i) == fsm_data.reset_state) {
+ sig_a = RTLIL::SigSpec(state);
+ } else {
+ sig_b.append(RTLIL::SigSpec(state));
+ sig_s.append(RTLIL::SigSpec(next_state_onehot, i));
+ }
+ }
- RTLIL::Cell *mux_cell = new RTLIL::Cell;
- mux_cell->name = NEW_ID;
- mux_cell->type = "$safe_pmux";
- mux_cell->connections["\\A"] = sig_a;
- mux_cell->connections["\\B"] = sig_b;
- mux_cell->connections["\\S"] = sig_s;
- mux_cell->connections["\\Y"] = RTLIL::SigSpec(next_state_wire);
- mux_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_a.width);
- mux_cell->parameters["\\S_WIDTH"] = RTLIL::Const(sig_s.width);
- module->add(mux_cell);
+ RTLIL::Cell *mux_cell = module->addCell(NEW_ID, "$pmux");
+ mux_cell->setPort("\\A", sig_a);
+ mux_cell->setPort("\\B", sig_b);
+ mux_cell->setPort("\\S", sig_s);
+ mux_cell->setPort("\\Y", RTLIL::SigSpec(next_state_wire));
+ mux_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_a.size());
+ mux_cell->parameters["\\S_WIDTH"] = RTLIL::Const(sig_s.size());
+ }
}
// Generate ctrl_out signal
- RTLIL::Wire *ctrl_out_wire = new RTLIL::Wire;
- ctrl_out_wire->name = NEW_ID;
- ctrl_out_wire->width = fsm_data.num_outputs;
- module->add(ctrl_out_wire);
-
for (int i = 0; i < fsm_data.num_outputs; i++)
{
std::map<RTLIL::Const, std::set<int>> pattern_cache;
@@ -340,8 +313,7 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
// Remove FSM cell
- module->cells.erase(fsm_cell->name);
- delete fsm_cell;
+ module->remove(fsm_cell);
}
struct FsmMapPass : public Pass {
@@ -360,11 +332,11 @@ struct FsmMapPass : public Pass {
log_header("Executing FSM_MAP pass (mapping FSMs to basic logic).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (!design->selected(mod_it.second))
continue;
std::vector<RTLIL::Cell*> fsm_cells;
- for (auto &cell_it : mod_it.second->cells)
+ for (auto &cell_it : mod_it.second->cells_)
if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second))
fsm_cells.push_back(cell_it.second);
for (auto cell : fsm_cells)
diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc
index 242a505e..a0e1885e 100644
--- a/passes/fsm/fsm_opt.cc
+++ b/passes/fsm/fsm_opt.cc
@@ -30,22 +30,62 @@ struct FsmOpt
FsmData fsm_data;
RTLIL::Cell *cell;
RTLIL::Module *module;
+
+ void opt_unreachable_states()
+ {
+ while (1)
+ {
+ std::set<int> unreachable_states;
+ std::vector<FsmData::transition_t> new_transition_table;
+ std::vector<RTLIL::Const> new_state_table;
+ std::map<int, int> old_to_new_state;
+
+ for (int i = 0; i < SIZE(fsm_data.state_table); i++)
+ if (i != fsm_data.reset_state)
+ unreachable_states.insert(i);
+
+ for (auto &trans : fsm_data.transition_table)
+ unreachable_states.erase(trans.state_out);
+
+ if (unreachable_states.empty())
+ break;
+
+ for (int i = 0; i < SIZE(fsm_data.state_table); i++) {
+ if (unreachable_states.count(i)) {
+ log(" Removing unreachable state %s.\n", log_signal(fsm_data.state_table[i]));
+ continue;
+ }
+ old_to_new_state[i] = SIZE(new_state_table);
+ new_state_table.push_back(fsm_data.state_table[i]);
+ }
+
+ for (auto trans : fsm_data.transition_table) {
+ if (unreachable_states.count(trans.state_in))
+ continue;
+ trans.state_in = old_to_new_state.at(trans.state_in);
+ trans.state_out = old_to_new_state.at(trans.state_out);
+ new_transition_table.push_back(trans);
+ }
+
+ new_transition_table.swap(fsm_data.transition_table);
+ new_state_table.swap(fsm_data.state_table);
+ fsm_data.reset_state = old_to_new_state.at(fsm_data.reset_state);
+ }
+ }
bool signal_is_unused(RTLIL::SigSpec sig)
{
- assert(sig.width == 1);
- sig.optimize();
-
- RTLIL::Wire *wire = sig.chunks[0].wire;
- int bit = sig.chunks[0].offset;
+ RTLIL::SigBit bit = sig.to_single_sigbit();
- if (!wire || wire->attributes.count("\\unused_bits") == 0)
+ if (bit.wire == NULL || bit.wire->attributes.count("\\unused_bits") == 0)
return false;
- char *str = strdup(wire->attributes["\\unused_bits"].decode_string().c_str());
+ char *str = strdup(bit.wire->attributes["\\unused_bits"].decode_string().c_str());
for (char *tok = strtok(str, " "); tok != NULL; tok = strtok(NULL, " ")) {
- if (tok[0] && bit == atoi(tok))
+ if (tok[0] && bit.offset == atoi(tok)) {
+ free(str);
return true;
+ }
}
free(str);
@@ -54,12 +94,12 @@ struct FsmOpt
void opt_const_and_unused_inputs()
{
- RTLIL::SigSpec ctrl_in = cell->connections["\\CTRL_IN"];
- std::vector<bool> ctrl_in_used(ctrl_in.width);
+ RTLIL::SigSpec ctrl_in = cell->getPort("\\CTRL_IN");
+ std::vector<bool> ctrl_in_used(ctrl_in.size());
std::vector<FsmData::transition_t> new_transition_table;
for (auto &tr : fsm_data.transition_table) {
- for (int i = 0; i < ctrl_in.width; i++) {
+ for (int i = 0; i < ctrl_in.size(); i++) {
RTLIL::SigSpec ctrl_bit = ctrl_in.extract(i, 1);
if (ctrl_bit.is_fully_const()) {
if (tr.ctrl_in.bits[i] <= RTLIL::State::S1 && RTLIL::SigSpec(tr.ctrl_in.bits[i]) != ctrl_bit)
@@ -75,13 +115,15 @@ struct FsmOpt
for (int i = int(ctrl_in_used.size())-1; i >= 0; i--) {
if (!ctrl_in_used[i]) {
- log(" Removing unused input signal %s.\n", log_signal(cell->connections["\\CTRL_IN"].extract(i, 1)));
+ log(" Removing unused input signal %s.\n", log_signal(cell->getPort("\\CTRL_IN").extract(i, 1)));
for (auto &tr : new_transition_table) {
RTLIL::SigSpec tmp(tr.ctrl_in);
tmp.remove(i, 1);
tr.ctrl_in = tmp.as_const();
}
- cell->connections["\\CTRL_IN"].remove(i, 1);
+ RTLIL::SigSpec new_ctrl_in = cell->getPort("\\CTRL_IN");
+ new_ctrl_in.remove(i, 1);
+ cell->setPort("\\CTRL_IN", new_ctrl_in);
fsm_data.num_inputs--;
}
}
@@ -93,10 +135,12 @@ struct FsmOpt
void opt_unused_outputs()
{
for (int i = 0; i < fsm_data.num_outputs; i++) {
- RTLIL::SigSpec sig = cell->connections["\\CTRL_OUT"].extract(i, 1);
+ RTLIL::SigSpec sig = cell->getPort("\\CTRL_OUT").extract(i, 1);
if (signal_is_unused(sig)) {
log(" Removing unused output signal %s.\n", log_signal(sig));
- cell->connections["\\CTRL_OUT"].remove(i, 1);
+ RTLIL::SigSpec new_ctrl_out = cell->getPort("\\CTRL_OUT");
+ new_ctrl_out.remove(i, 1);
+ cell->setPort("\\CTRL_OUT", new_ctrl_out);
for (auto &tr : fsm_data.transition_table) {
RTLIL::SigSpec tmp(tr.ctrl_out);
tmp.remove(i, 1);
@@ -110,10 +154,10 @@ struct FsmOpt
void opt_alias_inputs()
{
- RTLIL::SigSpec &ctrl_in = cell->connections["\\CTRL_IN"];
+ RTLIL::SigSpec &ctrl_in = cell->connections_["\\CTRL_IN"];
- for (int i = 0; i < ctrl_in.width; i++)
- for (int j = i+1; j < ctrl_in.width; j++)
+ for (int i = 0; i < ctrl_in.size(); i++)
+ for (int j = i+1; j < ctrl_in.size(); j++)
if (ctrl_in.extract(i, 1) == ctrl_in.extract(j, 1))
{
log(" Optimize handling of signal %s that is connected to inputs %d and %d.\n", log_signal(ctrl_in.extract(i, 1)), i, j);
@@ -147,11 +191,11 @@ struct FsmOpt
void opt_feedback_inputs()
{
- RTLIL::SigSpec &ctrl_in = cell->connections["\\CTRL_IN"];
- RTLIL::SigSpec &ctrl_out = cell->connections["\\CTRL_OUT"];
+ RTLIL::SigSpec &ctrl_in = cell->connections_["\\CTRL_IN"];
+ RTLIL::SigSpec &ctrl_out = cell->connections_["\\CTRL_OUT"];
- for (int j = 0; j < ctrl_out.width; j++)
- for (int i = 0; i < ctrl_in.width; i++)
+ for (int j = 0; j < ctrl_out.size(); j++)
+ for (int i = 0; i < ctrl_in.size(); i++)
if (ctrl_in.extract(i, 1) == ctrl_out.extract(j, 1))
{
log(" Optimize handling of signal %s that is connected to input %d and output %d.\n", log_signal(ctrl_in.extract(i, 1)), i, j);
@@ -251,6 +295,8 @@ struct FsmOpt
this->cell = cell;
this->module = module;
+ opt_unreachable_states();
+
opt_unused_outputs();
opt_alias_inputs();
@@ -286,9 +332,9 @@ struct FsmOptPass : public Pass {
log_header("Executing FSM_OPT pass (simple optimizations of FSMs).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (design->selected(mod_it.second))
- for (auto &cell_it : mod_it.second->cells)
+ for (auto &cell_it : mod_it.second->cells_)
if (cell_it.second->type == "$fsm" and design->selected(mod_it.second, cell_it.second))
FsmData::optimize_fsm(cell_it.second, mod_it.second);
}
diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc
index 5a4e091c..873ee7a1 100644
--- a/passes/fsm/fsm_recode.cc
+++ b/passes/fsm/fsm_recode.cc
@@ -23,8 +23,9 @@
#include "kernel/consteval.h"
#include "kernel/celltypes.h"
#include "fsmdata.h"
-#include "math.h"
+#include <math.h>
#include <string.h>
+#include <errno.h>
static void fm_set_fsm_print(RTLIL::Cell *cell, RTLIL::Module *module, FsmData &fsm_data, const char *prefix, FILE *f)
{
@@ -52,10 +53,10 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
std::string encoding = cell->attributes.count("\\fsm_encoding") ? cell->attributes.at("\\fsm_encoding").decode_string() : "auto";
log("Recoding FSM `%s' from module `%s' using `%s' encoding:\n", cell->name.c_str(), module->name.c_str(), encoding.c_str());
- if (encoding != "none" && encoding != "one-hot" && encoding != "binary") {
- if (encoding != "auto")
- log(" unkown encoding `%s': using auto (%s) instead.\n", encoding.c_str(), default_encoding.c_str());
- encoding = default_encoding;
+
+ if (encoding != "none" && encoding != "one-hot" && encoding != "binary" && encoding != "auto") {
+ log(" unknown encoding `%s': using auto instead.\n", encoding.c_str());
+ encoding = "auto";
}
if (encoding == "none") {
@@ -69,11 +70,24 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
if (fm_set_fsm_file != NULL)
fm_set_fsm_print(cell, module, fsm_data, "r", fm_set_fsm_file);
+ if (encoding == "auto") {
+ if (!default_encoding.empty())
+ encoding = default_encoding;
+ else
+ encoding = SIZE(fsm_data.state_table) < 32 ? "one-hot" : "binary";
+ log(" mapping auto encoding to `%s` for this FSM.\n", encoding.c_str());
+ }
+
if (encoding == "one-hot") {
fsm_data.state_bits = fsm_data.state_table.size();
} else
- if (encoding == "auto" || encoding == "binary") {
- fsm_data.state_bits = ceil(log2(fsm_data.state_table.size()));
+ if (encoding == "binary") {
+ int new_num_state_bits = ceil(log2(fsm_data.state_table.size()));
+ if (fsm_data.state_bits == new_num_state_bits) {
+ log(" existing encoding is already a packed binary encoding.\n");
+ return;
+ }
+ fsm_data.state_bits = new_num_state_bits;
} else
log_error("FSM encoding `%s' is not supported!\n", encoding.c_str());
@@ -87,7 +101,7 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
new_code = RTLIL::Const(RTLIL::State::Sa, fsm_data.state_bits);
new_code.bits[state_idx] = RTLIL::State::S1;
} else
- if (encoding == "auto" || encoding == "binary") {
+ if (encoding == "binary") {
new_code = RTLIL::Const(state_idx, fsm_data.state_bits);
} else
log_abort();
@@ -123,7 +137,7 @@ struct FsmRecodePass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
FILE *fm_set_fsm_file = NULL;
- std::string default_encoding = "one-hot";
+ std::string default_encoding;
log_header("Executing FSM_RECODE pass (re-assigning FSM state encoding).\n");
size_t argidx;
@@ -143,9 +157,9 @@ struct FsmRecodePass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
- for (auto &cell_it : mod_it.second->cells)
+ for (auto &cell_it : mod_it.second->cells_)
if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second))
fsm_recode(cell_it.second, mod_it.second, fm_set_fsm_file, default_encoding);
diff --git a/passes/fsm/fsmdata.h b/passes/fsm/fsmdata.h
index 225f34a9..7a44dd45 100644
--- a/passes/fsm/fsmdata.h
+++ b/passes/fsm/fsmdata.h
@@ -141,29 +141,27 @@ struct FsmData
log("\n");
log(" Input signals:\n");
- RTLIL::SigSpec sig_in = cell->connections["\\CTRL_IN"];
- sig_in.expand();
- for (size_t i = 0; i < sig_in.chunks.size(); i++)
- log(" %3zd: %s\n", i, log_signal(sig_in.chunks[i]));
+ RTLIL::SigSpec sig_in = cell->getPort("\\CTRL_IN");
+ for (int i = 0; i < SIZE(sig_in); i++)
+ log(" %3d: %s\n", i, log_signal(sig_in[i]));
log("\n");
log(" Output signals:\n");
- RTLIL::SigSpec sig_out = cell->connections["\\CTRL_OUT"];
- sig_out.expand();
- for (size_t i = 0; i < sig_out.chunks.size(); i++)
- log(" %3zd: %s\n", i, log_signal(sig_out.chunks[i]));
+ RTLIL::SigSpec sig_out = cell->getPort("\\CTRL_OUT");
+ for (int i = 0; i < SIZE(sig_out); i++)
+ log(" %3d: %s\n", i, log_signal(sig_out[i]));
log("\n");
log(" State encoding:\n");
- for (size_t i = 0; i < state_table.size(); i++)
- log(" %3zd: %10s%s\n", i, log_signal(state_table[i], false),
+ for (int i = 0; i < SIZE(state_table); i++)
+ log(" %3d: %10s%s\n", i, log_signal(state_table[i], false),
int(i) == reset_state ? " <RESET STATE>" : "");
log("\n");
log(" Transition Table (state_in, ctrl_in, state_out, ctrl_out):\n");
- for (size_t i = 0; i < transition_table.size(); i++) {
+ for (int i = 0; i < SIZE(transition_table); i++) {
transition_t &tr = transition_table[i];
- log(" %5zd: %5d %s -> %5d %s\n", i, tr.state_in, log_signal(tr.ctrl_in), tr.state_out, log_signal(tr.ctrl_out));
+ log(" %5d: %5d %s -> %5d %s\n", i, tr.state_in, log_signal(tr.ctrl_in), tr.state_out, log_signal(tr.ctrl_out));
}
log("\n");
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 50d0e6e4..14bf8d1b 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -28,20 +28,22 @@
namespace {
struct generate_port_decl_t {
bool input, output;
- std::string portname;
+ RTLIL::IdString portname;
int index;
};
}
static void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, const std::vector<generate_port_decl_t> &portdecls)
{
- std::set<std::string> found_celltypes;
+ std::set<RTLIL::IdString> found_celltypes;
- for (auto i1 : design->modules)
- for (auto i2 : i1.second->cells)
+ for (auto i1 : design->modules_)
+ for (auto i2 : i1.second->cells_)
{
RTLIL::Cell *cell = i2.second;
- if (cell->type[0] == '$' || design->modules.count(cell->type) > 0)
+ if (design->has(cell->type))
+ continue;
+ if (cell->type.substr(0, 1) == "$" && cell->type.substr(0, 3) != "$__")
continue;
for (auto &pattern : celltypes)
if (!fnmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str(), FNM_NOESCAPE))
@@ -50,18 +52,18 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
for (auto &celltype : found_celltypes)
{
- std::set<std::string> portnames;
- std::set<std::string> parameters;
- std::map<std::string, int> portwidths;
+ std::set<RTLIL::IdString> portnames;
+ std::set<RTLIL::IdString> parameters;
+ std::map<RTLIL::IdString, int> portwidths;
log("Generate module for cell type %s:\n", celltype.c_str());
- for (auto i1 : design->modules)
- for (auto i2 : i1.second->cells)
+ for (auto i1 : design->modules_)
+ for (auto i2 : i1.second->cells_)
if (i2.second->type == celltype) {
- for (auto &conn : i2.second->connections) {
+ for (auto &conn : i2.second->connections()) {
if (conn.first[0] != '$')
portnames.insert(conn.first);
- portwidths[conn.first] = std::max(portwidths[conn.first], conn.second.width);
+ portwidths[conn.first] = std::max(portwidths[conn.first], conn.second.size());
}
for (auto &para : i2.second->parameters)
parameters.insert(para.first);
@@ -92,13 +94,13 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
}
while (portnames.size() > 0) {
- std::string portname = *portnames.begin();
+ RTLIL::IdString portname = *portnames.begin();
for (auto &decl : portdecls)
if (decl.index == 0 && !fnmatch(decl.portname.c_str(), RTLIL::unescape_id(portname).c_str(), FNM_NOESCAPE)) {
generate_port_decl_t d = decl;
d.portname = portname;
d.index = *indices.begin();
- assert(!indices.empty());
+ log_assert(!indices.empty());
indices.erase(d.index);
ports[d.index-1] = d;
portwidths[d.portname] = std::max(portwidths[d.portname], 1);
@@ -110,23 +112,22 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
portnames.erase(portname);
}
- assert(indices.empty());
+ log_assert(indices.empty());
RTLIL::Module *mod = new RTLIL::Module;
mod->name = celltype;
mod->attributes["\\blackbox"] = RTLIL::Const(1);
- design->modules[mod->name] = mod;
+ design->add(mod);
for (auto &decl : ports) {
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = decl.portname;
- wire->width = portwidths.at(decl.portname);
+ RTLIL::Wire *wire = mod->addWire(decl.portname, portwidths.at(decl.portname));
wire->port_id = decl.index;
wire->port_input = decl.input;
wire->port_output = decl.output;
- mod->add(wire);
}
+ mod->fixup_ports();
+
for (auto &para : parameters)
log(" ignoring parameter %s.\n", RTLIL::id2cstr(para));
@@ -137,14 +138,33 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector<std::string> &libdirs)
{
bool did_something = false;
+ std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
std::string filename;
- for (auto &cell_it : module->cells)
+ for (auto &cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
- if (design->modules.count(cell->type) == 0)
+ if (cell->type.substr(0, 7) == "$array:") {
+ int pos_idx = cell->type.str().find_first_of(':');
+ int pos_num = cell->type.str().find_first_of(':', pos_idx + 1);
+ int pos_type = cell->type.str().find_first_of(':', pos_num + 1);
+ int idx = atoi(cell->type.str().substr(pos_idx + 1, pos_num).c_str());
+ int num = atoi(cell->type.str().substr(pos_num + 1, pos_type).c_str());
+ array_cells[cell] = std::pair<int, int>(idx, num);
+ cell->type = cell->type.str().substr(pos_type + 1);
+ }
+
+ if (design->modules_.count(cell->type) == 0)
{
+ if (design->modules_.count("$abstract" + cell->type.str()))
+ {
+ cell->type = design->modules_.at("$abstract" + cell->type.str())->derive(design, cell->parameters);
+ cell->parameters.clear();
+ did_something = true;
+ continue;
+ }
+
if (cell->type[0] == '$')
continue;
@@ -173,7 +193,7 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
continue;
loaded_module:
- if (design->modules.count(cell->type) == 0)
+ if (design->modules_.count(cell->type) == 0)
log_error("File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->type.c_str());
did_something = true;
}
@@ -181,15 +201,47 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
if (cell->parameters.size() == 0)
continue;
- if (design->modules.at(cell->type)->get_bool_attribute("\\blackbox"))
+ if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox"))
continue;
- RTLIL::Module *mod = design->modules[cell->type];
+ RTLIL::Module *mod = design->modules_[cell->type];
cell->type = mod->derive(design, cell->parameters);
cell->parameters.clear();
did_something = true;
}
+ for (auto &it : array_cells)
+ {
+ RTLIL::Cell *cell = it.first;
+ int idx = it.second.first, num = it.second.second;
+
+ if (design->modules_.count(cell->type) == 0)
+ log_error("Array cell `%s.%s' of unknown type `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
+
+ RTLIL::Module *mod = design->modules_[cell->type];
+
+ for (auto &conn : cell->connections_) {
+ int conn_size = conn.second.size();
+ RTLIL::IdString portname = conn.first;
+ if (portname.substr(0, 1) == "$") {
+ int port_id = atoi(portname.substr(1).c_str());
+ for (auto &wire_it : mod->wires_)
+ if (wire_it.second->port_id == port_id) {
+ portname = wire_it.first;
+ break;
+ }
+ }
+ if (mod->wires_.count(portname) == 0)
+ log_error("Array cell `%s.%s' connects to unknown port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
+ int port_size = mod->wires_.at(portname)->width;
+ if (conn_size == port_size)
+ continue;
+ if (conn_size != port_size*num)
+ log_error("Array cell `%s.%s' has invalid port vs. signal size for port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
+ conn.second = conn.second.extract(port_size*idx, port_size);
+ }
+ }
+
return did_something;
}
@@ -204,27 +256,29 @@ static void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &us
log("Used module: %*s%s\n", indent, "", mod->name.c_str());
used.insert(mod);
- for (auto &it : mod->cells) {
- if (design->modules.count(it.second->type) > 0)
- hierarchy_worker(design, used, design->modules[it.second->type], indent+4);
+ for (auto &it : mod->cells_) {
+ if (design->modules_.count(it.second->type) > 0)
+ hierarchy_worker(design, used, design->modules_[it.second->type], indent+4);
}
}
-static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
+static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib, bool first_pass)
{
std::set<RTLIL::Module*> used;
hierarchy_worker(design, used, top, 0);
std::vector<RTLIL::Module*> del_modules;
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
if (used.count(it.second) == 0)
del_modules.push_back(it.second);
for (auto mod : del_modules) {
+ if (first_pass && mod->name.substr(0, 9) == "$abstract")
+ continue;
if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
continue;
log("Removing unused module `%s'.\n", mod->name.c_str());
- design->modules.erase(mod->name);
+ design->modules_.erase(mod->name);
delete mod;
}
@@ -240,7 +294,7 @@ struct HierarchyPass : public Pass {
log(" hierarchy [-check] [-top <module>]\n");
log(" hierarchy -generate <cell-types> <port-decls>\n");
log("\n");
- log("In parametric designs, a module might exists in serveral variations with\n");
+ log("In parametric designs, a module might exists in several variations with\n");
log("different parameter values. This pass looks at all modules in the current\n");
log("design an re-runs the language frontends for the parametric modules as\n");
log("needed.\n");
@@ -255,7 +309,7 @@ struct HierarchyPass : public Pass {
log("\n");
log(" -libdir <directory>\n");
log(" search for files named <module_name>.v in the specified directory\n");
- log(" for unkown modules and automatically run read_verilog for each\n");
+ log(" for unknown modules and automatically run read_verilog for each\n");
log(" unknown module.\n");
log("\n");
log(" -keep_positionals\n");
@@ -362,10 +416,12 @@ struct HierarchyPass : public Pass {
if (args[argidx] == "-top") {
if (++argidx >= args.size())
log_cmd_error("Option -top requires an additional argument!\n");
- if (args[argidx][0] != '$' && args[argidx][0] != '\\')
- top_mod = design->modules.count("\\" + args[argidx]) > 0 ? design->modules["\\" + args[argidx]] : NULL;
- else
- top_mod = design->modules.count(args[argidx]) > 0 ? design->modules[args[argidx]] : NULL;
+ top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
+ if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
+ std::map<RTLIL::IdString, RTLIL::Const> empty_parameters;
+ design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
+ top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
+ }
if (top_mod == NULL)
log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
continue;
@@ -382,25 +438,25 @@ struct HierarchyPass : public Pass {
log_push();
if (top_mod == NULL)
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
top_mod = mod_it.second;
if (top_mod != NULL)
- hierarchy(design, top_mod, purge_lib);
+ hierarchy(design, top_mod, purge_lib, true);
bool did_something = true;
bool did_something_once = false;
while (did_something) {
did_something = false;
- std::vector<std::string> modnames;
- modnames.reserve(design->modules.size());
- for (auto &mod_it : design->modules)
+ std::vector<RTLIL::IdString> modnames;
+ modnames.reserve(design->modules_.size());
+ for (auto &mod_it : design->modules_)
modnames.push_back(mod_it.first);
for (auto &modname : modnames) {
- if (design->modules.count(modname) == 0)
+ if (design->modules_.count(modname) == 0)
continue;
- if (expand_module(design, design->modules[modname], flag_check, libdirs))
+ if (expand_module(design, design->modules_[modname], flag_check, libdirs))
did_something = true;
}
if (did_something)
@@ -409,11 +465,11 @@ struct HierarchyPass : public Pass {
if (top_mod != NULL && did_something_once) {
log_header("Re-running hierarchy analysis..\n");
- hierarchy(design, top_mod, purge_lib);
+ hierarchy(design, top_mod, purge_lib, false);
}
if (top_mod != NULL) {
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (mod_it.second == top_mod)
mod_it.second->attributes["\\top"] = RTLIL::Const(1);
else
@@ -426,21 +482,21 @@ struct HierarchyPass : public Pass {
std::map<std::pair<RTLIL::Module*,int>, RTLIL::IdString> pos_map;
std::vector<std::pair<RTLIL::Module*,RTLIL::Cell*>> pos_work;
- for (auto &mod_it : design->modules)
- for (auto &cell_it : mod_it.second->cells) {
+ for (auto &mod_it : design->modules_)
+ for (auto &cell_it : mod_it.second->cells_) {
RTLIL::Cell *cell = cell_it.second;
- if (design->modules.count(cell->type) == 0)
+ if (design->modules_.count(cell->type) == 0)
continue;
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
- pos_mods.insert(design->modules.at(cell->type));
+ pos_mods.insert(design->modules_.at(cell->type));
pos_work.push_back(std::pair<RTLIL::Module*,RTLIL::Cell*>(mod_it.second, cell));
break;
}
}
for (auto module : pos_mods)
- for (auto &wire_it : module->wires) {
+ for (auto &wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_id > 0)
pos_map[std::pair<RTLIL::Module*,int>(module, wire->port_id)] = wire->name;
@@ -452,10 +508,10 @@ struct HierarchyPass : public Pass {
log("Mapping positional arguments of cell %s.%s (%s).\n",
RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
std::map<RTLIL::IdString, RTLIL::SigSpec> new_connections;
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
int id = atoi(conn.first.c_str()+1);
- std::pair<RTLIL::Module*,int> key(design->modules.at(cell->type), id);
+ std::pair<RTLIL::Module*,int> key(design->modules_.at(cell->type), id);
if (pos_map.count(key) == 0) {
log(" Failed to map positional argument %d of cell %s.%s (%s).\n",
id, RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
@@ -464,7 +520,7 @@ struct HierarchyPass : public Pass {
new_connections[pos_map.at(key)] = conn.second;
} else
new_connections[conn.first] = conn.second;
- cell->connections = new_connections;
+ cell->connections_ = new_connections;
}
}
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
index 7d081125..1b03ab55 100644
--- a/passes/hierarchy/submod.cc
+++ b/passes/hierarchy/submod.cc
@@ -65,9 +65,9 @@ struct SubmodWorker
flag_found_something = true;
}
- void flag_signal(RTLIL::SigSpec &sig, bool create, bool set_int_driven, bool set_int_used, bool set_ext_driven, bool set_ext_used)
+ void flag_signal(const RTLIL::SigSpec &sig, bool create, bool set_int_driven, bool set_int_used, bool set_ext_driven, bool set_ext_used)
{
- for (auto &c : sig.chunks)
+ for (auto &c : sig.chunks())
if (c.wire != NULL)
flag_wire(c.wire, create, set_int_driven, set_int_used, set_ext_driven, set_ext_used);
}
@@ -79,24 +79,24 @@ struct SubmodWorker
wire_flags.clear();
for (RTLIL::Cell *cell : submod.cells) {
if (ct.cell_known(cell->type)) {
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
flag_signal(conn.second, true, ct.cell_output(cell->type, conn.first), ct.cell_input(cell->type, conn.first), false, false);
} else {
log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
flag_signal(conn.second, true, true, true, false, false);
}
}
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
if (submod.cells.count(cell) > 0)
continue;
if (ct.cell_known(cell->type)) {
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
flag_signal(conn.second, false, false, false, ct.cell_output(cell->type, conn.first), ct.cell_input(cell->type, conn.first));
} else {
flag_found_something = false;
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
flag_signal(conn.second, false, false, false, true, true);
if (flag_found_something)
log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
@@ -105,10 +105,10 @@ struct SubmodWorker
RTLIL::Module *new_mod = new RTLIL::Module;
new_mod->name = submod.full_name;
- design->modules[new_mod->name] = new_mod;
- int port_counter = 1, auto_name_counter = 1;
+ design->add(new_mod);
+ int auto_name_counter = 1;
- std::set<std::string> all_wire_names;
+ std::set<RTLIL::IdString> all_wire_names;
for (auto &it : wire_flags) {
all_wire_names.insert(it.first->name);
}
@@ -123,31 +123,34 @@ struct SubmodWorker
if (wire->port_output)
flags.is_ext_used = true;
- RTLIL::Wire *new_wire = new RTLIL::Wire;
- new_wire->name = wire->name;
- new_wire->width = wire->width;
- new_wire->start_offset = wire->start_offset;
- new_wire->attributes = wire->attributes;
+ bool new_wire_port_input = false;
+ bool new_wire_port_output = false;
if (flags.is_int_driven && flags.is_ext_used)
- new_wire->port_output = true;
+ new_wire_port_output = true;
if (flags.is_ext_driven && flags.is_int_used)
- new_wire->port_input = true;
+ new_wire_port_input = true;
if (flags.is_int_driven && flags.is_ext_driven)
- new_wire->port_input = true, new_wire->port_output = true;
-
- if (new_wire->port_input || new_wire->port_output) {
- new_wire->port_id = port_counter++;
- while (new_wire->name[0] == '$') {
- std::string new_wire_name = stringf("\\n%d", auto_name_counter++);
- if (all_wire_names.count(new_wire_name) == 0) {
- all_wire_names.insert(new_wire_name);
- new_wire->name = new_wire_name;
+ new_wire_port_input = true, new_wire_port_output = true;
+
+ std::string new_wire_name = wire->name.str();
+ if (new_wire_port_input || new_wire_port_output) {
+ while (new_wire_name[0] == '$') {
+ std::string next_wire_name = stringf("\\n%d", auto_name_counter++);
+ if (all_wire_names.count(next_wire_name) == 0) {
+ all_wire_names.insert(next_wire_name);
+ new_wire_name = next_wire_name;
}
}
}
+ RTLIL::Wire *new_wire = new_mod->addWire(new_wire_name, wire->width);
+ new_wire->port_input = new_wire_port_input;
+ new_wire->port_output = new_wire_port_output;
+ new_wire->start_offset = wire->start_offset;
+ new_wire->attributes = wire->attributes;
+
if (new_wire->port_input && new_wire->port_output)
log(" signal %s: inout %s\n", wire->name.c_str(), new_wire->name.c_str());
else if (new_wire->port_input)
@@ -157,36 +160,32 @@ struct SubmodWorker
else
log(" signal %s: internal\n", wire->name.c_str());
- new_mod->wires[new_wire->name] = new_wire;
flags.new_wire = new_wire;
}
+ new_mod->fixup_ports();
+
for (RTLIL::Cell *cell : submod.cells) {
- RTLIL::Cell *new_cell = new RTLIL::Cell(*cell);
- for (auto &conn : new_cell->connections)
- for (auto &c : conn.second.chunks)
- if (c.wire != NULL) {
- assert(wire_flags.count(c.wire) > 0);
- c.wire = wire_flags[c.wire].new_wire;
+ RTLIL::Cell *new_cell = new_mod->addCell(cell->name, cell);
+ for (auto &conn : new_cell->connections_)
+ for (auto &bit : conn.second)
+ if (bit.wire != NULL) {
+ log_assert(wire_flags.count(bit.wire) > 0);
+ bit.wire = wire_flags[bit.wire].new_wire;
}
log(" cell %s (%s)\n", new_cell->name.c_str(), new_cell->type.c_str());
- new_mod->cells[new_cell->name] = new_cell;
- module->cells.erase(cell->name);
- delete cell;
+ module->remove(cell);
}
submod.cells.clear();
- RTLIL::Cell *new_cell = new RTLIL::Cell;
- new_cell->name = submod.full_name;
- new_cell->type = submod.full_name;
+ RTLIL::Cell *new_cell = module->addCell(submod.full_name, submod.full_name);
for (auto &it : wire_flags)
{
RTLIL::Wire *old_wire = it.first;
RTLIL::Wire *new_wire = it.second.new_wire;
if (new_wire->port_id > 0)
- new_cell->connections[new_wire->name] = RTLIL::SigSpec(old_wire);
+ new_cell->setPort(new_wire->name, RTLIL::SigSpec(old_wire));
}
- module->cells[new_cell->name] = new_cell;
}
SubmodWorker(RTLIL::Design *design, RTLIL::Module *module, std::string opt_name = std::string()) : design(design), module(module), opt_name(opt_name)
@@ -212,10 +211,10 @@ struct SubmodWorker
if (opt_name.empty())
{
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
it.second->attributes.erase("\\submod");
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
RTLIL::Cell *cell = it.second;
if (cell->attributes.count("\\submod") == 0 || cell->attributes["\\submod"].bits.size() == 0) {
@@ -228,8 +227,8 @@ struct SubmodWorker
if (submodules.count(submod_str) == 0) {
submodules[submod_str].name = submod_str;
- submodules[submod_str].full_name = module->name + "_" + submod_str;
- while (design->modules.count(submodules[submod_str].full_name) != 0 ||
+ submodules[submod_str].full_name = module->name.str() + "_" + submod_str;
+ while (design->modules_.count(submodules[submod_str].full_name) != 0 ||
module->count_id(submodules[submod_str].full_name) != 0)
submodules[submod_str].full_name += "_";
}
@@ -239,7 +238,7 @@ struct SubmodWorker
}
else
{
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
RTLIL::Cell *cell = it.second;
if (!design->selected(module, cell))
@@ -306,18 +305,18 @@ struct SubmodPass : public Pass {
Pass::call(design, "opt_clean");
log_header("Continuing SUBMOD pass.\n");
- std::set<std::string> handled_modules;
+ std::set<RTLIL::IdString> handled_modules;
bool did_something = true;
while (did_something) {
did_something = false;
- std::vector<std::string> queued_modules;
- for (auto &mod_it : design->modules)
+ std::vector<RTLIL::IdString> queued_modules;
+ for (auto &mod_it : design->modules_)
if (handled_modules.count(mod_it.first) == 0 && design->selected_whole_module(mod_it.first))
queued_modules.push_back(mod_it.first);
for (auto &modname : queued_modules)
- if (design->modules.count(modname) != 0) {
- SubmodWorker worker(design, design->modules[modname]);
+ if (design->modules_.count(modname) != 0) {
+ SubmodWorker worker(design, design->modules_[modname]);
handled_modules.insert(modname);
did_something = true;
}
@@ -328,7 +327,7 @@ struct SubmodPass : public Pass {
else
{
RTLIL::Module *module = NULL;
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (!design->selected_module(mod_it.first))
continue;
if (module != NULL)
@@ -338,7 +337,7 @@ struct SubmodPass : public Pass {
if (module == NULL)
log("Nothing selected -> do nothing.\n");
else {
- Pass::call_newsel(design, stringf("opt_clean %s", module->name.c_str()));
+ Pass::call_on_module(design, module, "opt_clean");
log_header("Continuing SUBMOD pass.\n");
SubmodWorker worker(design, module, opt_name);
}
diff --git a/passes/memory/Makefile.inc b/passes/memory/Makefile.inc
index 21f17db5..026c5ff8 100644
--- a/passes/memory/Makefile.inc
+++ b/passes/memory/Makefile.inc
@@ -1,6 +1,7 @@
OBJS += passes/memory/memory.o
OBJS += passes/memory/memory_dff.o
+OBJS += passes/memory/memory_share.o
OBJS += passes/memory/memory_collect.o
OBJS += passes/memory/memory_unpack.o
OBJS += passes/memory/memory_map.o
diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc
index 680657a7..fc309553 100644
--- a/passes/memory/memory.cc
+++ b/passes/memory/memory.cc
@@ -33,6 +33,9 @@ struct MemoryPass : public Pass {
log("This pass calls all the other memory_* passes in a useful order:\n");
log("\n");
log(" memory_dff\n");
+ log(" opt_clean\n");
+ log(" memory_share\n");
+ log(" opt_clean\n");
log(" memory_collect\n");
log(" memory_map (skipped if called with -nomap)\n");
log("\n");
@@ -58,6 +61,9 @@ struct MemoryPass : public Pass {
extra_args(args, argidx, design);
Pass::call(design, "memory_dff");
+ Pass::call(design, "opt_clean");
+ Pass::call(design, "memory_share");
+ Pass::call(design, "opt_clean");
Pass::call(design, "memory_collect");
if (!flag_nomap)
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index 6fe5e162..9c670f00 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -22,7 +22,6 @@
#include <sstream>
#include <algorithm>
#include <stdlib.h>
-#include <assert.h>
static bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
{
@@ -58,12 +57,12 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
RTLIL::SigSpec sig_rd_addr;
RTLIL::SigSpec sig_rd_data;
- std::vector<std::string> del_cell_ids;
+ std::vector<RTLIL::Cell*> del_cells;
std::vector<RTLIL::Cell*> memcells;
- for (auto &cell_it : module->cells) {
+ for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
- if ((cell->type == "$memwr" || cell->type == "$memrd") && cell->parameters["\\MEMID"].decode_string() == memory->name)
+ if ((cell->type == "$memwr" || cell->type == "$memrd") && memory->name == cell->parameters["\\MEMID"].decode_string())
memcells.push_back(cell);
}
@@ -71,24 +70,24 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
for (auto cell : memcells)
{
- if (cell->type == "$memwr" && cell->parameters["\\MEMID"].decode_string() == memory->name)
+ if (cell->type == "$memwr" && memory->name == cell->parameters["\\MEMID"].decode_string())
{
wr_ports++;
- del_cell_ids.push_back(cell->name);
+ del_cells.push_back(cell);
- RTLIL::SigSpec clk = cell->connections["\\CLK"];
+ RTLIL::SigSpec clk = cell->getPort("\\CLK");
RTLIL::SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]);
RTLIL::SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]);
- RTLIL::SigSpec addr = cell->connections["\\ADDR"];
- RTLIL::SigSpec data = cell->connections["\\DATA"];
- RTLIL::SigSpec en = cell->connections["\\EN"];
+ RTLIL::SigSpec addr = cell->getPort("\\ADDR");
+ RTLIL::SigSpec data = cell->getPort("\\DATA");
+ RTLIL::SigSpec en = cell->getPort("\\EN");
clk.extend(1, false);
clk_enable.extend(1, false);
clk_polarity.extend(1, false);
addr.extend(addr_bits, false);
data.extend(memory->width, false);
- en.extend(1, false);
+ en.extend(memory->width, false);
sig_wr_clk.append(clk);
sig_wr_clk_enable.append(clk_enable);
@@ -98,17 +97,17 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
sig_wr_en.append(en);
}
- if (cell->type == "$memrd" && cell->parameters["\\MEMID"].decode_string() == memory->name)
+ if (cell->type == "$memrd" && memory->name == cell->parameters["\\MEMID"].decode_string())
{
rd_ports++;
- del_cell_ids.push_back(cell->name);
+ del_cells.push_back(cell);
- RTLIL::SigSpec clk = cell->connections["\\CLK"];
+ RTLIL::SigSpec clk = cell->getPort("\\CLK");
RTLIL::SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]);
RTLIL::SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]);
RTLIL::SigSpec transparent = RTLIL::SigSpec(cell->parameters["\\TRANSPARENT"]);
- RTLIL::SigSpec addr = cell->connections["\\ADDR"];
- RTLIL::SigSpec data = cell->connections["\\DATA"];
+ RTLIL::SigSpec addr = cell->getPort("\\ADDR");
+ RTLIL::SigSpec data = cell->getPort("\\DATA");
clk.extend(1, false);
clk_enable.extend(1, false);
@@ -127,61 +126,48 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
}
std::stringstream sstr;
- sstr << "$mem$" << memory->name << "$" << (RTLIL::autoidx++);
+ sstr << "$mem$" << memory->name.str() << "$" << (autoidx++);
- RTLIL::Cell *mem = new RTLIL::Cell;
- mem->name = sstr.str();
- mem->type = "$mem";
-
- mem->parameters["\\MEMID"] = RTLIL::Const(memory->name);
+ RTLIL::Cell *mem = module->addCell(sstr.str(), "$mem");
+ mem->parameters["\\MEMID"] = RTLIL::Const(memory->name.str());
mem->parameters["\\WIDTH"] = RTLIL::Const(memory->width);
mem->parameters["\\OFFSET"] = RTLIL::Const(memory->start_offset);
mem->parameters["\\SIZE"] = RTLIL::Const(memory->size);
mem->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
- sig_wr_clk_enable.optimize();
- sig_wr_clk_polarity.optimize();
-
- assert(sig_wr_clk.width == wr_ports);
- assert(sig_wr_clk_enable.width == wr_ports && sig_wr_clk_enable.is_fully_const());
- assert(sig_wr_clk_polarity.width == wr_ports && sig_wr_clk_polarity.is_fully_const());
- assert(sig_wr_addr.width == wr_ports * addr_bits);
- assert(sig_wr_data.width == wr_ports * memory->width);
- assert(sig_wr_en.width == wr_ports);
+ log_assert(sig_wr_clk.size() == wr_ports);
+ log_assert(sig_wr_clk_enable.size() == wr_ports && sig_wr_clk_enable.is_fully_const());
+ log_assert(sig_wr_clk_polarity.size() == wr_ports && sig_wr_clk_polarity.is_fully_const());
+ log_assert(sig_wr_addr.size() == wr_ports * addr_bits);
+ log_assert(sig_wr_data.size() == wr_ports * memory->width);
+ log_assert(sig_wr_en.size() == wr_ports * memory->width);
mem->parameters["\\WR_PORTS"] = RTLIL::Const(wr_ports);
- mem->parameters["\\WR_CLK_ENABLE"] = wr_ports ? sig_wr_clk_enable.chunks[0].data : RTLIL::Const(0, 0);
- mem->parameters["\\WR_CLK_POLARITY"] = wr_ports ? sig_wr_clk_polarity.chunks[0].data : RTLIL::Const(0, 0);
+ mem->parameters["\\WR_CLK_ENABLE"] = wr_ports ? sig_wr_clk_enable.as_const() : RTLIL::Const(0, 0);
+ mem->parameters["\\WR_CLK_POLARITY"] = wr_ports ? sig_wr_clk_polarity.as_const() : RTLIL::Const(0, 0);
- mem->connections["\\WR_CLK"] = sig_wr_clk;
- mem->connections["\\WR_ADDR"] = sig_wr_addr;
- mem->connections["\\WR_DATA"] = sig_wr_data;
- mem->connections["\\WR_EN"] = sig_wr_en;
+ mem->setPort("\\WR_CLK", sig_wr_clk);
+ mem->setPort("\\WR_ADDR", sig_wr_addr);
+ mem->setPort("\\WR_DATA", sig_wr_data);
+ mem->setPort("\\WR_EN", sig_wr_en);
- sig_rd_clk_enable.optimize();
- sig_rd_clk_polarity.optimize();
- sig_rd_transparent.optimize();
-
- assert(sig_rd_clk.width == rd_ports);
- assert(sig_rd_clk_enable.width == rd_ports && sig_rd_clk_enable.is_fully_const());
- assert(sig_rd_clk_polarity.width == rd_ports && sig_rd_clk_polarity.is_fully_const());
- assert(sig_rd_addr.width == rd_ports * addr_bits);
- assert(sig_rd_data.width == rd_ports * memory->width);
+ log_assert(sig_rd_clk.size() == rd_ports);
+ log_assert(sig_rd_clk_enable.size() == rd_ports && sig_rd_clk_enable.is_fully_const());
+ log_assert(sig_rd_clk_polarity.size() == rd_ports && sig_rd_clk_polarity.is_fully_const());
+ log_assert(sig_rd_addr.size() == rd_ports * addr_bits);
+ log_assert(sig_rd_data.size() == rd_ports * memory->width);
mem->parameters["\\RD_PORTS"] = RTLIL::Const(rd_ports);
- mem->parameters["\\RD_CLK_ENABLE"] = rd_ports ? sig_rd_clk_enable.chunks[0].data : RTLIL::Const(0, 0);
- mem->parameters["\\RD_CLK_POLARITY"] = rd_ports ? sig_rd_clk_polarity.chunks[0].data : RTLIL::Const(0, 0);
- mem->parameters["\\RD_TRANSPARENT"] = rd_ports ? sig_rd_transparent.chunks[0].data : RTLIL::Const(0, 0);
+ mem->parameters["\\RD_CLK_ENABLE"] = rd_ports ? sig_rd_clk_enable.as_const() : RTLIL::Const(0, 0);
+ mem->parameters["\\RD_CLK_POLARITY"] = rd_ports ? sig_rd_clk_polarity.as_const() : RTLIL::Const(0, 0);
+ mem->parameters["\\RD_TRANSPARENT"] = rd_ports ? sig_rd_transparent.as_const() : RTLIL::Const(0, 0);
- mem->connections["\\RD_CLK"] = sig_rd_clk;
- mem->connections["\\RD_ADDR"] = sig_rd_addr;
- mem->connections["\\RD_DATA"] = sig_rd_data;
+ mem->setPort("\\RD_CLK", sig_rd_clk);
+ mem->setPort("\\RD_ADDR", sig_rd_addr);
+ mem->setPort("\\RD_DATA", sig_rd_data);
- for (auto &id : del_cell_ids) {
- delete module->cells[id];
- module->cells.erase(id);
- }
- module->cells[mem->name] = mem;
+ for (auto c : del_cells)
+ module->remove(c);
}
static void handle_module(RTLIL::Design *design, RTLIL::Module *module)
@@ -213,7 +199,7 @@ struct MemoryCollectPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
log_header("Executing MEMORY_COLLECT pass (generating $mem cells).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
handle_module(design, mod_it.second);
}
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index 2502a8b6..302ab3ab 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -20,51 +20,41 @@
#include "kernel/register.h"
#include "kernel/log.h"
#include <stdlib.h>
-#include <assert.h>
#include <sstream>
static void normalize_sig(RTLIL::Module *module, RTLIL::SigSpec &sig)
{
- for (auto &conn : module->connections)
+ for (auto &conn : module->connections())
sig.replace(conn.first, conn.second);
}
-static bool find_sig_before_dff(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, bool after = false)
+static bool find_sig_before_dff(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, bool after = false)
{
normalize_sig(module, sig);
- sig.expand();
- for (size_t i = 0; i < sig.chunks.size(); i++)
+ for (auto &bit : sig)
{
- RTLIL::SigChunk &chunk = sig.chunks[i];
-
- if (chunk.wire == NULL)
+ if (bit.wire == NULL)
continue;
- for (auto &cell_it : module->cells)
+ for (auto cell : dff_cells)
{
- RTLIL::Cell *cell = cell_it.second;
-
- if (cell->type != "$dff")
- continue;
-
if (clk != RTLIL::SigSpec(RTLIL::State::Sx)) {
- if (cell->connections["\\CLK"] != clk)
+ if (cell->getPort("\\CLK") != clk)
continue;
if (cell->parameters["\\CLK_POLARITY"].as_bool() != clk_polarity)
continue;
}
- RTLIL::SigSpec q_norm = cell->connections[after ? "\\D" : "\\Q"];
+ RTLIL::SigSpec q_norm = cell->getPort(after ? "\\D" : "\\Q");
normalize_sig(module, q_norm);
- RTLIL::SigSpec d = q_norm.extract(chunk, &cell->connections[after ? "\\Q" : "\\D"]);
- if (d.width != 1)
+ RTLIL::SigSpec d = q_norm.extract(bit, &cell->getPort(after ? "\\Q" : "\\D"));
+ if (d.size() != 1)
continue;
- assert(d.chunks.size() == 1);
- chunk = d.chunks[0];
- clk = cell->connections["\\CLK"];
+ bit = d;
+ clk = cell->getPort("\\CLK");
clk_polarity = cell->parameters["\\CLK_POLARITY"].as_bool();
goto replaced_this_bit;
}
@@ -73,44 +63,46 @@ static bool find_sig_before_dff(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLI
replaced_this_bit:;
}
- sig.optimize();
return true;
}
-static void handle_wr_cell(RTLIL::Module *module, RTLIL::Cell *cell)
+static void handle_wr_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::Cell *cell)
{
log("Checking cell `%s' in module `%s': ", cell->name.c_str(), module->name.c_str());
RTLIL::SigSpec clk = RTLIL::SigSpec(RTLIL::State::Sx);
bool clk_polarity = 0;
- RTLIL::SigSpec sig_addr = cell->connections["\\ADDR"];
- if (!find_sig_before_dff(module, sig_addr, clk, clk_polarity)) {
+ RTLIL::SigSpec sig_addr = cell->getPort("\\ADDR");
+ if (!find_sig_before_dff(module, dff_cells, sig_addr, clk, clk_polarity)) {
log("no (compatible) $dff for address input found.\n");
return;
}
- RTLIL::SigSpec sig_data = cell->connections["\\DATA"];
- if (!find_sig_before_dff(module, sig_data, clk, clk_polarity)) {
+ RTLIL::SigSpec sig_data = cell->getPort("\\DATA");
+ if (!find_sig_before_dff(module, dff_cells, sig_data, clk, clk_polarity)) {
log("no (compatible) $dff for data input found.\n");
return;
}
- RTLIL::SigSpec sig_en = cell->connections["\\EN"];
- if (!find_sig_before_dff(module, sig_en, clk, clk_polarity)) {
+ RTLIL::SigSpec sig_en = cell->getPort("\\EN");
+ if (!find_sig_before_dff(module, dff_cells, sig_en, clk, clk_polarity)) {
log("no (compatible) $dff for enable input found.\n");
return;
}
if (clk != RTLIL::SigSpec(RTLIL::State::Sx)) {
- cell->connections["\\CLK"] = clk;
- cell->connections["\\ADDR"] = sig_addr;
- cell->connections["\\DATA"] = sig_data;
- cell->connections["\\EN"] = sig_en;
+ cell->setPort("\\CLK", clk);
+ cell->setPort("\\ADDR", sig_addr);
+ cell->setPort("\\DATA", sig_data);
+ cell->setPort("\\EN", sig_en);
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
log("merged $dff to cell.\n");
+ return;
}
+
+ log("no (compatible) $dff found.\n");
}
static void disconnect_dff(RTLIL::Module *module, RTLIL::SigSpec sig)
@@ -119,36 +111,32 @@ static void disconnect_dff(RTLIL::Module *module, RTLIL::SigSpec sig)
sig.sort_and_unify();
std::stringstream sstr;
- sstr << "$memory_dff_disconnected$" << (RTLIL::autoidx++);
+ sstr << "$memory_dff_disconnected$" << (autoidx++);
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = sstr.str();
- wire->width = sig.width;
- module->wires[wire->name] = wire;
+ RTLIL::SigSpec new_sig = module->addWire(sstr.str(), sig.size());
- RTLIL::SigSpec newsig(wire);
-
- for (auto &cell_it : module->cells) {
- RTLIL::Cell *cell = cell_it.second;
- if (cell->type == "$dff")
- cell->connections["\\Q"].replace(sig, newsig);
- }
+ for (auto cell : module->cells())
+ if (cell->type == "$dff") {
+ RTLIL::SigSpec new_q = cell->getPort("\\Q");
+ new_q.replace(sig, new_sig);
+ cell->setPort("\\Q", new_q);
+ }
}
-static void handle_rd_cell(RTLIL::Module *module, RTLIL::Cell *cell)
+static void handle_rd_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::Cell *cell)
{
log("Checking cell `%s' in module `%s': ", cell->name.c_str(), module->name.c_str());
bool clk_polarity = 0;
RTLIL::SigSpec clk_data = RTLIL::SigSpec(RTLIL::State::Sx);
- RTLIL::SigSpec sig_data = cell->connections["\\DATA"];
- if (find_sig_before_dff(module, sig_data, clk_data, clk_polarity, true) &&
+ RTLIL::SigSpec sig_data = cell->getPort("\\DATA");
+ if (find_sig_before_dff(module, dff_cells, sig_data, clk_data, clk_polarity, true) &&
clk_data != RTLIL::SigSpec(RTLIL::State::Sx))
{
disconnect_dff(module, sig_data);
- cell->connections["\\CLK"] = clk_data;
- cell->connections["\\DATA"] = sig_data;
+ cell->setPort("\\CLK", clk_data);
+ cell->setPort("\\DATA", sig_data);
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0);
@@ -157,12 +145,12 @@ static void handle_rd_cell(RTLIL::Module *module, RTLIL::Cell *cell)
}
RTLIL::SigSpec clk_addr = RTLIL::SigSpec(RTLIL::State::Sx);
- RTLIL::SigSpec sig_addr = cell->connections["\\ADDR"];
- if (find_sig_before_dff(module, sig_addr, clk_addr, clk_polarity) &&
+ RTLIL::SigSpec sig_addr = cell->getPort("\\ADDR");
+ if (find_sig_before_dff(module, dff_cells, sig_addr, clk_addr, clk_polarity) &&
clk_addr != RTLIL::SigSpec(RTLIL::State::Sx))
{
- cell->connections["\\CLK"] = clk_addr;
- cell->connections["\\ADDR"] = sig_addr;
+ cell->setPort("\\CLK", clk_addr);
+ cell->setPort("\\ADDR", sig_addr);
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
cell->parameters["\\TRANSPARENT"] = RTLIL::Const(1);
@@ -173,16 +161,22 @@ static void handle_rd_cell(RTLIL::Module *module, RTLIL::Cell *cell)
log("no (compatible) $dff found.\n");
}
-static void handle_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_wr_only)
+static void handle_module(RTLIL::Module *module, bool flag_wr_only)
{
- for (auto &cell_it : module->cells) {
- if (!design->selected(module, cell_it.second))
- continue;
- if (cell_it.second->type == "$memwr" && !cell_it.second->parameters["\\CLK_ENABLE"].as_bool())
- handle_wr_cell(module, cell_it.second);
- if (!flag_wr_only && cell_it.second->type == "$memrd" && !cell_it.second->parameters["\\CLK_ENABLE"].as_bool())
- handle_rd_cell(module, cell_it.second);
- }
+ std::vector<RTLIL::Cell*> dff_cells;
+
+ for (auto cell : module->cells())
+ if (cell->type == "$dff")
+ dff_cells.push_back(cell);
+
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$memwr" && !cell->parameters["\\CLK_ENABLE"].as_bool())
+ handle_wr_cell(module, dff_cells, cell);
+
+ if (!flag_wr_only)
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$memrd" && !cell->parameters["\\CLK_ENABLE"].as_bool())
+ handle_rd_cell(module, dff_cells, cell);
}
struct MemoryDffPass : public Pass {
@@ -217,9 +211,8 @@ struct MemoryDffPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod_it : design->modules)
- if (design->selected(mod_it.second))
- handle_module(design, mod_it.second, flag_wr_only);
+ for (auto mod : design->selected_modules())
+ handle_module(mod, flag_wr_only);
}
} MemoryDffPass;
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index e0e3802d..eecb6f35 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -22,316 +22,302 @@
#include <sstream>
#include <set>
#include <stdlib.h>
-#include <assert.h>
-static std::string genid(std::string name, std::string token1 = "", int i = -1, std::string token2 = "", int j = -1, std::string token3 = "", int k = -1, std::string token4 = "")
+struct MemoryMapWorker
{
- std::stringstream sstr;
- sstr << "$memory" << name << token1;
-
- if (i >= 0)
- sstr << "[" << i << "]";
+ RTLIL::Design *design;
+ RTLIL::Module *module;
- sstr << token2;
+ std::map<std::pair<RTLIL::SigSpec, RTLIL::SigSpec>, RTLIL::SigBit> decoder_cache;
- if (j >= 0)
- sstr << "[" << j << "]";
+ std::string genid(RTLIL::IdString name, std::string token1 = "", int i = -1, std::string token2 = "", int j = -1, std::string token3 = "", int k = -1, std::string token4 = "")
+ {
+ std::stringstream sstr;
+ sstr << "$memory" << name.str() << token1;
+
+ if (i >= 0)
+ sstr << "[" << i << "]";
- sstr << token3;
+ sstr << token2;
- if (k >= 0)
- sstr << "[" << k << "]";
+ if (j >= 0)
+ sstr << "[" << j << "]";
- sstr << token4 << "$" << (RTLIL::autoidx++);
- return sstr.str();
-}
+ sstr << token3;
-static void handle_cell(RTLIL::Module *module, RTLIL::Cell *cell)
-{
- std::set<int> static_ports;
- std::map<int, RTLIL::SigSpec> static_cells_map;
- int mem_size = cell->parameters["\\SIZE"].as_int();
- int mem_width = cell->parameters["\\WIDTH"].as_int();
- int mem_offset = cell->parameters["\\OFFSET"].as_int();
- int mem_abits = cell->parameters["\\ABITS"].as_int();
-
- // delete unused memory cell
- if (cell->parameters["\\RD_PORTS"].as_int() == 0 && cell->parameters["\\WR_PORTS"].as_int() == 0) {
- module->cells.erase(cell->name);
- delete cell;
- return;
- }
+ if (k >= 0)
+ sstr << "[" << k << "]";
- // all write ports must share the same clock
- RTLIL::SigSpec clocks = cell->connections["\\WR_CLK"];
- RTLIL::Const clocks_pol = cell->parameters["\\WR_CLK_POLARITY"];
- RTLIL::Const clocks_en = cell->parameters["\\WR_CLK_ENABLE"];
- RTLIL::SigSpec refclock;
- RTLIL::State refclock_pol = RTLIL::State::Sx;
- for (int i = 0; i < clocks.width; i++) {
- RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(i, 1);
- if (wr_en.is_fully_const() && wr_en.as_int() == 0) {
- static_ports.insert(i);
- continue;
- }
- if (clocks_en.bits[i] != RTLIL::State::S1) {
- RTLIL::SigSpec wr_addr = cell->connections["\\WR_ADDR"].extract(i*mem_abits, mem_abits);
- RTLIL::SigSpec wr_data = cell->connections["\\WR_DATA"].extract(i*mem_width, mem_width);
- if (wr_addr.is_fully_const()) {
- // FIXME: Actually we should check for wr_en.is_fully_const() also and
- // create a $adff cell with this ports wr_en input as reset pin when wr_en
- // is not a simple static 1.
- static_cells_map[wr_addr.as_int()] = wr_data;
- static_ports.insert(i);
- continue;
- }
- log("Not mapping memory cell %s in module %s (write port %d has no clock).\n",
- cell->name.c_str(), module->name.c_str(), i);
- return;
- }
- if (refclock.width == 0) {
- refclock = clocks.extract(i, 1);
- refclock_pol = clocks_pol.bits[i];
- }
- if (clocks.extract(i, 1) != refclock || clocks_pol.bits[i] != refclock_pol) {
- log("Not mapping memory cell %s in module %s (write clock %d is incompatible with other clocks).\n",
- cell->name.c_str(), module->name.c_str(), i);
- return;
- }
+ sstr << token4 << "$" << (autoidx++);
+ return sstr.str();
}
- log("Mapping memory cell %s in module %s:\n", cell->name.c_str(), module->name.c_str());
+ RTLIL::Wire *addr_decode(RTLIL::SigSpec addr_sig, RTLIL::SigSpec addr_val)
+ {
+ std::pair<RTLIL::SigSpec, RTLIL::SigSpec> key(addr_sig, addr_val);
+ log_assert(SIZE(addr_sig) == SIZE(addr_val));
- std::vector<RTLIL::SigSpec> data_reg_in;
- std::vector<RTLIL::SigSpec> data_reg_out;
+ if (decoder_cache.count(key) == 0) {
+ if (SIZE(addr_sig) < 2) {
+ decoder_cache[key] = module->Eq(NEW_ID, addr_sig, addr_val);
+ } else {
+ int split_at = SIZE(addr_sig) / 2;
+ RTLIL::SigBit left_eq = addr_decode(addr_sig.extract(0, split_at), addr_val.extract(0, split_at));
+ RTLIL::SigBit right_eq = addr_decode(addr_sig.extract(split_at, SIZE(addr_sig) - split_at), addr_val.extract(split_at, SIZE(addr_val) - split_at));
+ decoder_cache[key] = module->And(NEW_ID, left_eq, right_eq);
+ }
+ }
- int count_static = 0;
+ RTLIL::SigBit bit = decoder_cache.at(key);
+ log_assert(bit.wire != nullptr && SIZE(bit.wire) == 1);
+ return bit.wire;
+ }
- for (int i = 0; i < mem_size; i++)
+ void handle_cell(RTLIL::Cell *cell)
{
- if (static_cells_map.count(i) > 0)
- {
- data_reg_in.push_back(RTLIL::SigSpec(RTLIL::State::Sz, mem_width));
- data_reg_out.push_back(static_cells_map[i]);
- count_static++;
+ std::set<int> static_ports;
+ std::map<int, RTLIL::SigSpec> static_cells_map;
+ int mem_size = cell->parameters["\\SIZE"].as_int();
+ int mem_width = cell->parameters["\\WIDTH"].as_int();
+ int mem_offset = cell->parameters["\\OFFSET"].as_int();
+ int mem_abits = cell->parameters["\\ABITS"].as_int();
+
+ // delete unused memory cell
+ if (cell->parameters["\\RD_PORTS"].as_int() == 0 && cell->parameters["\\WR_PORTS"].as_int() == 0) {
+ module->remove(cell);
+ return;
}
- else
- {
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = genid(cell->name, "", i);
- c->type = "$dff";
- c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
- if (clocks_pol.bits.size() > 0) {
- c->parameters["\\CLK_POLARITY"] = RTLIL::Const(clocks_pol.bits[0]);
- c->connections["\\CLK"] = clocks.extract(0, 1);
- } else {
- c->parameters["\\CLK_POLARITY"] = RTLIL::Const(RTLIL::State::S1);
- c->connections["\\CLK"] = RTLIL::SigSpec(RTLIL::State::S0);
+
+ // all write ports must share the same clock
+ RTLIL::SigSpec clocks = cell->getPort("\\WR_CLK");
+ RTLIL::Const clocks_pol = cell->parameters["\\WR_CLK_POLARITY"];
+ RTLIL::Const clocks_en = cell->parameters["\\WR_CLK_ENABLE"];
+ RTLIL::SigSpec refclock;
+ RTLIL::State refclock_pol = RTLIL::State::Sx;
+ for (int i = 0; i < clocks.size(); i++) {
+ RTLIL::SigSpec wr_en = cell->getPort("\\WR_EN").extract(i * mem_width, mem_width);
+ if (wr_en.is_fully_const() && !wr_en.as_bool()) {
+ static_ports.insert(i);
+ continue;
+ }
+ if (clocks_en.bits[i] != RTLIL::State::S1) {
+ RTLIL::SigSpec wr_addr = cell->getPort("\\WR_ADDR").extract(i*mem_abits, mem_abits);
+ RTLIL::SigSpec wr_data = cell->getPort("\\WR_DATA").extract(i*mem_width, mem_width);
+ if (wr_addr.is_fully_const()) {
+ // FIXME: Actually we should check for wr_en.is_fully_const() also and
+ // create a $adff cell with this ports wr_en input as reset pin when wr_en
+ // is not a simple static 1.
+ static_cells_map[wr_addr.as_int()] = wr_data;
+ static_ports.insert(i);
+ continue;
+ }
+ log("Not mapping memory cell %s in module %s (write port %d has no clock).\n",
+ cell->name.c_str(), module->name.c_str(), i);
+ return;
+ }
+ if (refclock.size() == 0) {
+ refclock = clocks.extract(i, 1);
+ refclock_pol = clocks_pol.bits[i];
+ }
+ if (clocks.extract(i, 1) != refclock || clocks_pol.bits[i] != refclock_pol) {
+ log("Not mapping memory cell %s in module %s (write clock %d is incompatible with other clocks).\n",
+ cell->name.c_str(), module->name.c_str(), i);
+ return;
}
- module->cells[c->name] = c;
-
- RTLIL::Wire *w_in = new RTLIL::Wire;
- w_in->name = genid(cell->name, "", i, "$d");
- w_in->width = mem_width;
- module->wires[w_in->name] = w_in;
- data_reg_in.push_back(RTLIL::SigSpec(w_in));
- c->connections["\\D"] = data_reg_in.back();
-
- RTLIL::Wire *w_out = new RTLIL::Wire;
- w_out->name = stringf("%s[%d]", cell->parameters["\\MEMID"].decode_string().c_str(), i);
- if (module->wires.count(w_out->name) > 0)
- w_out->name = genid(cell->name, "", i, "$q");
- w_out->width = mem_width;
- w_out->start_offset = mem_offset;
- module->wires[w_out->name] = w_out;
- data_reg_out.push_back(RTLIL::SigSpec(w_out));
- c->connections["\\Q"] = data_reg_out.back();
}
- }
- log(" created %d $dff cells and %d static cells of width %d.\n", mem_size-count_static, count_static, mem_width);
+ log("Mapping memory cell %s in module %s:\n", cell->name.c_str(), module->name.c_str());
- int count_dff = 0, count_mux = 0, count_wrmux = 0;
-
- for (int i = 0; i < cell->parameters["\\RD_PORTS"].as_int(); i++)
- {
- RTLIL::SigSpec rd_addr = cell->connections["\\RD_ADDR"].extract(i*mem_abits, mem_abits);
+ std::vector<RTLIL::SigSpec> data_reg_in;
+ std::vector<RTLIL::SigSpec> data_reg_out;
- std::vector<RTLIL::SigSpec> rd_signals;
- rd_signals.push_back(cell->connections["\\RD_DATA"].extract(i*mem_width, mem_width));
+ int count_static = 0;
- if (cell->parameters["\\RD_CLK_ENABLE"].bits[i] == RTLIL::State::S1)
+ for (int i = 0; i < mem_size; i++)
{
- if (cell->parameters["\\RD_TRANSPARENT"].bits[i] == RTLIL::State::S1)
+ if (static_cells_map.count(i) > 0)
{
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = genid(cell->name, "$rdreg", i);
- c->type = "$dff";
- c->parameters["\\WIDTH"] = RTLIL::Const(mem_abits);
- c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
- c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1);
- c->connections["\\D"] = rd_addr;
- module->cells[c->name] = c;
- count_dff++;
-
- RTLIL::Wire *w = new RTLIL::Wire;
- w->name = genid(cell->name, "$rdreg", i, "$q");
- w->width = mem_abits;
- module->wires[w->name] = w;
-
- c->connections["\\Q"] = RTLIL::SigSpec(w);
- rd_addr = RTLIL::SigSpec(w);
+ data_reg_in.push_back(RTLIL::SigSpec(RTLIL::State::Sz, mem_width));
+ data_reg_out.push_back(static_cells_map[i]);
+ count_static++;
}
else
{
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = genid(cell->name, "$rdreg", i);
- c->type = "$dff";
+ RTLIL::Cell *c = module->addCell(genid(cell->name, "", i), "$dff");
c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
- c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
- c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1);
- c->connections["\\Q"] = rd_signals.back();
- module->cells[c->name] = c;
- count_dff++;
-
- RTLIL::Wire *w = new RTLIL::Wire;
- w->name = genid(cell->name, "$rdreg", i, "$d");
- w->width = mem_width;
- module->wires[w->name] = w;
-
- rd_signals.clear();
- rd_signals.push_back(RTLIL::SigSpec(w));
- c->connections["\\D"] = rd_signals.back();
+ if (clocks_pol.bits.size() > 0) {
+ c->parameters["\\CLK_POLARITY"] = RTLIL::Const(clocks_pol.bits[0]);
+ c->setPort("\\CLK", clocks.extract(0, 1));
+ } else {
+ c->parameters["\\CLK_POLARITY"] = RTLIL::Const(RTLIL::State::S1);
+ c->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::S0));
+ }
+
+ RTLIL::Wire *w_in = module->addWire(genid(cell->name, "", i, "$d"), mem_width);
+ data_reg_in.push_back(RTLIL::SigSpec(w_in));
+ c->setPort("\\D", data_reg_in.back());
+
+ std::string w_out_name = stringf("%s[%d]", cell->parameters["\\MEMID"].decode_string().c_str(), i);
+ if (module->wires_.count(w_out_name) > 0)
+ w_out_name = genid(cell->name, "", i, "$q");
+
+ RTLIL::Wire *w_out = module->addWire(w_out_name, mem_width);
+ w_out->start_offset = mem_offset;
+
+ data_reg_out.push_back(RTLIL::SigSpec(w_out));
+ c->setPort("\\Q", data_reg_out.back());
}
}
- for (int j = 0; j < mem_abits; j++)
+ log(" created %d $dff cells and %d static cells of width %d.\n", mem_size-count_static, count_static, mem_width);
+
+ int count_dff = 0, count_mux = 0, count_wrmux = 0;
+
+ for (int i = 0; i < cell->parameters["\\RD_PORTS"].as_int(); i++)
{
- std::vector<RTLIL::SigSpec> next_rd_signals;
+ RTLIL::SigSpec rd_addr = cell->getPort("\\RD_ADDR").extract(i*mem_abits, mem_abits);
+
+ std::vector<RTLIL::SigSpec> rd_signals;
+ rd_signals.push_back(cell->getPort("\\RD_DATA").extract(i*mem_width, mem_width));
- for (size_t k = 0; k < rd_signals.size(); k++)
+ if (cell->parameters["\\RD_CLK_ENABLE"].bits[i] == RTLIL::State::S1)
{
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = genid(cell->name, "$rdmux", i, "", j, "", k);
- c->type = "$mux";
- c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
- c->connections["\\Y"] = rd_signals[k];
- c->connections["\\S"] = rd_addr.extract(mem_abits-j-1, 1);
- module->cells[c->name] = c;
- count_mux++;
-
- RTLIL::Wire *w = new RTLIL::Wire;
- w->name = genid(cell->name, "$rdmux", i, "", j, "", k, "$a");
- w->width = mem_width;
- module->wires[w->name] = w;
- c->connections["\\A"] = RTLIL::SigSpec(w);
-
- w = new RTLIL::Wire;
- w->name = genid(cell->name, "$rdmux", i, "", j, "", k, "$b");
- w->width = mem_width;
- module->wires[w->name] = w;
- c->connections["\\B"] = RTLIL::SigSpec(w);
-
- next_rd_signals.push_back(c->connections["\\A"]);
- next_rd_signals.push_back(c->connections["\\B"]);
+ if (cell->parameters["\\RD_TRANSPARENT"].bits[i] == RTLIL::State::S1)
+ {
+ RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
+ c->parameters["\\WIDTH"] = RTLIL::Const(mem_abits);
+ c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
+ c->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
+ c->setPort("\\D", rd_addr);
+ count_dff++;
+
+ RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$q"), mem_abits);
+
+ c->setPort("\\Q", RTLIL::SigSpec(w));
+ rd_addr = RTLIL::SigSpec(w);
+ }
+ else
+ {
+ RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
+ c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
+ c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
+ c->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
+ c->setPort("\\Q", rd_signals.back());
+ count_dff++;
+
+ RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$d"), mem_width);
+
+ rd_signals.clear();
+ rd_signals.push_back(RTLIL::SigSpec(w));
+ c->setPort("\\D", rd_signals.back());
+ }
}
- next_rd_signals.swap(rd_signals);
- }
+ for (int j = 0; j < mem_abits; j++)
+ {
+ std::vector<RTLIL::SigSpec> next_rd_signals;
- for (int j = 0; j < mem_size; j++)
- module->connections.push_back(RTLIL::SigSig(rd_signals[j], data_reg_out[j]));
- }
+ for (size_t k = 0; k < rd_signals.size(); k++)
+ {
+ RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdmux", i, "", j, "", k), "$mux");
+ c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
+ c->setPort("\\Y", rd_signals[k]);
+ c->setPort("\\S", rd_addr.extract(mem_abits-j-1, 1));
+ count_mux++;
- log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux);
+ c->setPort("\\A", module->addWire(genid(cell->name, "$rdmux", i, "", j, "", k, "$a"), mem_width));
+ c->setPort("\\B", module->addWire(genid(cell->name, "$rdmux", i, "", j, "", k, "$b"), mem_width));
- for (int i = 0; i < mem_size; i++)
- {
- if (static_cells_map.count(i) > 0)
- continue;
+ next_rd_signals.push_back(c->getPort("\\A"));
+ next_rd_signals.push_back(c->getPort("\\B"));
+ }
- RTLIL::SigSpec sig = data_reg_out[i];
+ next_rd_signals.swap(rd_signals);
+ }
- for (int j = 0; j < cell->parameters["\\WR_PORTS"].as_int(); j++)
+ for (int j = 0; j < mem_size; j++)
+ module->connect(RTLIL::SigSig(rd_signals[j], data_reg_out[j]));
+ }
+
+ log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux);
+
+ for (int i = 0; i < mem_size; i++)
{
- RTLIL::SigSpec wr_addr = cell->connections["\\WR_ADDR"].extract(j*mem_abits, mem_abits);
- RTLIL::SigSpec wr_data = cell->connections["\\WR_DATA"].extract(j*mem_width, mem_width);
- RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(j, 1);
-
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = genid(cell->name, "$wreq", i, "", j);
- c->type = "$eq";
- c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- c->parameters["\\B_SIGNED"] = RTLIL::Const(0);
- c->parameters["\\A_WIDTH"] = cell->parameters["\\ABITS"];
- c->parameters["\\B_WIDTH"] = cell->parameters["\\ABITS"];
- c->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- c->connections["\\A"] = RTLIL::SigSpec(i, mem_abits);
- c->connections["\\B"] = wr_addr;
- module->cells[c->name] = c;
- count_wrmux++;
-
- RTLIL::Wire *w = new RTLIL::Wire;
- w->name = genid(cell->name, "$wreq", i, "", j, "$y");
- module->wires[w->name] = w;
- c->connections["\\Y"] = RTLIL::SigSpec(w);
-
- if (wr_en != RTLIL::SigSpec(1, 1))
+ if (static_cells_map.count(i) > 0)
+ continue;
+
+ RTLIL::SigSpec sig = data_reg_out[i];
+
+ for (int j = 0; j < cell->parameters["\\WR_PORTS"].as_int(); j++)
{
- c = new RTLIL::Cell;
- c->name = genid(cell->name, "$wren", i, "", j);
- c->type = "$and";
- c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- c->parameters["\\B_SIGNED"] = RTLIL::Const(0);
- c->parameters["\\A_WIDTH"] = RTLIL::Const(1);
- c->parameters["\\B_WIDTH"] = RTLIL::Const(1);
- c->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- c->connections["\\A"] = RTLIL::SigSpec(w);
- c->connections["\\B"] = wr_en;
- module->cells[c->name] = c;
-
- w = new RTLIL::Wire;
- w->name = genid(cell->name, "$wren", i, "", j, "$y");
- module->wires[w->name] = w;
- c->connections["\\Y"] = RTLIL::SigSpec(w);
+ RTLIL::SigSpec wr_addr = cell->getPort("\\WR_ADDR").extract(j*mem_abits, mem_abits);
+ RTLIL::SigSpec wr_data = cell->getPort("\\WR_DATA").extract(j*mem_width, mem_width);
+ RTLIL::SigSpec wr_en = cell->getPort("\\WR_EN").extract(j*mem_width, mem_width);
+ RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(i, mem_abits));
+
+ int wr_offset = 0;
+ while (wr_offset < wr_en.size())
+ {
+ int wr_width = 1;
+ RTLIL::SigSpec wr_bit = wr_en.extract(wr_offset, 1);
+
+ while (wr_offset + wr_width < wr_en.size()) {
+ RTLIL::SigSpec next_wr_bit = wr_en.extract(wr_offset + wr_width, 1);
+ if (next_wr_bit != wr_bit)
+ break;
+ wr_width++;
+ }
+
+ RTLIL::Wire *w = w_seladdr;
+
+ if (wr_bit != RTLIL::SigSpec(1, 1))
+ {
+ RTLIL::Cell *c = module->addCell(genid(cell->name, "$wren", i, "", j, "", wr_offset), "$and");
+ c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
+ c->parameters["\\B_SIGNED"] = RTLIL::Const(0);
+ c->parameters["\\A_WIDTH"] = RTLIL::Const(1);
+ c->parameters["\\B_WIDTH"] = RTLIL::Const(1);
+ c->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+ c->setPort("\\A", w);
+ c->setPort("\\B", wr_bit);
+
+ w = module->addWire(genid(cell->name, "$wren", i, "", j, "", wr_offset, "$y"));
+ c->setPort("\\Y", RTLIL::SigSpec(w));
+ }
+
+ RTLIL::Cell *c = module->addCell(genid(cell->name, "$wrmux", i, "", j, "", wr_offset), "$mux");
+ c->parameters["\\WIDTH"] = wr_width;
+ c->setPort("\\A", sig.extract(wr_offset, wr_width));
+ c->setPort("\\B", wr_data.extract(wr_offset, wr_width));
+ c->setPort("\\S", RTLIL::SigSpec(w));
+
+ w = module->addWire(genid(cell->name, "$wrmux", i, "", j, "", wr_offset, "$y"), wr_width);
+ c->setPort("\\Y", w);
+
+ sig.replace(wr_offset, w);
+ wr_offset += wr_width;
+ count_wrmux++;
+ }
}
- c = new RTLIL::Cell;
- c->name = genid(cell->name, "$wrmux", i, "", j);
- c->type = "$mux";
- c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
- c->connections["\\A"] = sig;
- c->connections["\\B"] = wr_data;
- c->connections["\\S"] = RTLIL::SigSpec(w);
- module->cells[c->name] = c;
-
- w = new RTLIL::Wire;
- w->name = genid(cell->name, "$wrmux", i, "", j, "$y");
- w->width = mem_width;
- module->wires[w->name] = w;
- c->connections["\\Y"] = RTLIL::SigSpec(w);
- sig = RTLIL::SigSpec(w);
+ module->connect(RTLIL::SigSig(data_reg_in[i], sig));
}
- module->connections.push_back(RTLIL::SigSig(data_reg_in[i], sig));
- }
-
- log(" write interface: %d blocks of $eq, $and and $mux cells.\n", count_wrmux);
+ log(" write interface: %d write mux blocks.\n", count_wrmux);
- module->cells.erase(cell->name);
- delete cell;
- return;
-}
+ module->remove(cell);
+ }
-static void handle_module(RTLIL::Design *design, RTLIL::Module *module)
-{
- std::vector<RTLIL::Cell*> cells;
- for (auto &it : module->cells)
- if (it.second->type == "$mem" && design->selected(module, it.second))
- cells.push_back(it.second);
- for (auto cell : cells)
- handle_cell(module, cell);
-}
+ MemoryMapWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module)
+ {
+ std::vector<RTLIL::Cell*> cells;
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$mem" && design->selected(module, cell))
+ cells.push_back(cell);
+ for (auto cell : cells)
+ handle_cell(cell);
+ }
+};
struct MemoryMapPass : public Pass {
MemoryMapPass() : Pass("memory_map", "translate multiport memories to basic cells") { }
@@ -348,9 +334,8 @@ struct MemoryMapPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
log_header("Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
- if (design->selected(mod_it.second))
- handle_module(design, mod_it.second);
+ for (auto mod : design->selected_modules())
+ MemoryMapWorker(design, mod);
}
} MemoryMapPass;
diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc
new file mode 100644
index 00000000..3ae0cd2c
--- /dev/null
+++ b/passes/memory/memory_share.cc
@@ -0,0 +1,744 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/satgen.h"
+#include "kernel/sigtools.h"
+#include "kernel/modtools.h"
+
+PRIVATE_NAMESPACE_BEGIN
+
+static bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
+{
+ if (a->type == "$memrd" && b->type == "$memrd")
+ return a->name < b->name;
+ if (a->type == "$memrd" || b->type == "$memrd")
+ return (a->type == "$memrd") < (b->type == "$memrd");
+ return a->parameters.at("\\PRIORITY").as_int() < b->parameters.at("\\PRIORITY").as_int();
+}
+
+struct MemoryShareWorker
+{
+ RTLIL::Design *design;
+ RTLIL::Module *module;
+ SigMap sigmap, sigmap_xmux;
+ ModWalker modwalker;
+ CellTypes cone_ct;
+
+ std::map<RTLIL::SigBit, std::pair<RTLIL::Cell*, int>> sig_to_mux;
+ std::map<std::set<std::map<RTLIL::SigBit, bool>>, RTLIL::SigBit> conditions_logic_cache;
+
+
+ // -----------------------------------------------------------------
+ // Converting feedbacks to async read ports to proper enable signals
+ // -----------------------------------------------------------------
+
+ bool find_data_feedback(const std::set<RTLIL::SigBit> &async_rd_bits, RTLIL::SigBit sig,
+ std::map<RTLIL::SigBit, bool> &state, std::set<std::map<RTLIL::SigBit, bool>> &conditions)
+ {
+ if (async_rd_bits.count(sig)) {
+ conditions.insert(state);
+ return true;
+ }
+
+ if (sig_to_mux.count(sig) == 0)
+ return false;
+
+ RTLIL::Cell *cell = sig_to_mux.at(sig).first;
+ int bit_idx = sig_to_mux.at(sig).second;
+
+ std::vector<RTLIL::SigBit> sig_a = sigmap(cell->getPort("\\A"));
+ std::vector<RTLIL::SigBit> sig_b = sigmap(cell->getPort("\\B"));
+ std::vector<RTLIL::SigBit> sig_s = sigmap(cell->getPort("\\S"));
+ std::vector<RTLIL::SigBit> sig_y = sigmap(cell->getPort("\\Y"));
+ log_assert(sig_y.at(bit_idx) == sig);
+
+ for (int i = 0; i < int(sig_s.size()); i++)
+ if (state.count(sig_s[i]) && state.at(sig_s[i]) == true) {
+ if (find_data_feedback(async_rd_bits, sig_b.at(bit_idx + i*sig_y.size()), state, conditions)) {
+ RTLIL::SigSpec new_b = cell->getPort("\\B");
+ new_b.replace(bit_idx + i*sig_y.size(), RTLIL::State::Sx);
+ cell->setPort("\\B", new_b);
+ }
+ return false;
+ }
+
+
+ for (int i = 0; i < int(sig_s.size()); i++)
+ {
+ if (state.count(sig_s[i]) && state.at(sig_s[i]) == false)
+ continue;
+
+ std::map<RTLIL::SigBit, bool> new_state = state;
+ new_state[sig_s[i]] = true;
+
+ if (find_data_feedback(async_rd_bits, sig_b.at(bit_idx + i*sig_y.size()), new_state, conditions)) {
+ RTLIL::SigSpec new_b = cell->getPort("\\B");
+ new_b.replace(bit_idx + i*sig_y.size(), RTLIL::State::Sx);
+ cell->setPort("\\B", new_b);
+ }
+ }
+
+ std::map<RTLIL::SigBit, bool> new_state = state;
+ for (int i = 0; i < int(sig_s.size()); i++)
+ new_state[sig_s[i]] = false;
+
+ if (find_data_feedback(async_rd_bits, sig_a.at(bit_idx), new_state, conditions)) {
+ RTLIL::SigSpec new_a = cell->getPort("\\A");
+ new_a.replace(bit_idx, RTLIL::State::Sx);
+ cell->setPort("\\A", new_a);
+ }
+
+ return false;
+ }
+
+ RTLIL::SigBit conditions_to_logic(std::set<std::map<RTLIL::SigBit, bool>> &conditions, int &created_conditions)
+ {
+ if (conditions_logic_cache.count(conditions))
+ return conditions_logic_cache.at(conditions);
+
+ RTLIL::SigSpec terms;
+ for (auto &cond : conditions) {
+ RTLIL::SigSpec sig1, sig2;
+ for (auto &it : cond) {
+ sig1.append_bit(it.first);
+ sig2.append_bit(it.second ? RTLIL::State::S1 : RTLIL::State::S0);
+ }
+ terms.append(module->Ne(NEW_ID, sig1, sig2));
+ created_conditions++;
+ }
+
+ if (terms.size() > 1)
+ terms = module->ReduceAnd(NEW_ID, terms);
+
+ return conditions_logic_cache[conditions] = terms;
+ }
+
+ void translate_rd_feedback_to_en(std::string memid, std::vector<RTLIL::Cell*> &rd_ports, std::vector<RTLIL::Cell*> &wr_ports)
+ {
+ std::map<RTLIL::SigSpec, std::vector<std::set<RTLIL::SigBit>>> async_rd_bits;
+ std::map<RTLIL::SigBit, std::set<RTLIL::SigBit>> muxtree_upstream_map;
+ std::set<RTLIL::SigBit> non_feedback_nets;
+
+ for (auto wire_it : module->wires_)
+ if (wire_it.second->port_output) {
+ std::vector<RTLIL::SigBit> bits = RTLIL::SigSpec(wire_it.second);
+ non_feedback_nets.insert(bits.begin(), bits.end());
+ }
+
+ for (auto cell_it : module->cells_)
+ {
+ RTLIL::Cell *cell = cell_it.second;
+ bool ignore_data_port = false;
+
+ if (cell->type == "$mux" || cell->type == "$pmux")
+ {
+ std::vector<RTLIL::SigBit> sig_a = sigmap(cell->getPort("\\A"));
+ std::vector<RTLIL::SigBit> sig_b = sigmap(cell->getPort("\\B"));
+ std::vector<RTLIL::SigBit> sig_s = sigmap(cell->getPort("\\S"));
+ std::vector<RTLIL::SigBit> sig_y = sigmap(cell->getPort("\\Y"));
+
+ non_feedback_nets.insert(sig_s.begin(), sig_s.end());
+
+ for (int i = 0; i < int(sig_y.size()); i++) {
+ muxtree_upstream_map[sig_y[i]].insert(sig_a[i]);
+ for (int j = 0; j < int(sig_s.size()); j++)
+ muxtree_upstream_map[sig_y[i]].insert(sig_b[i + j*sig_y.size()]);
+ }
+
+ continue;
+ }
+
+ if ((cell->type == "$memwr" || cell->type == "$memrd") &&
+ cell->parameters.at("\\MEMID").decode_string() == memid)
+ ignore_data_port = true;
+
+ for (auto conn : cell_it.second->connections())
+ {
+ if (ignore_data_port && conn.first == "\\DATA")
+ continue;
+ std::vector<RTLIL::SigBit> bits = sigmap(conn.second);
+ non_feedback_nets.insert(bits.begin(), bits.end());
+ }
+ }
+
+ std::set<RTLIL::SigBit> expand_non_feedback_nets = non_feedback_nets;
+ while (!expand_non_feedback_nets.empty())
+ {
+ std::set<RTLIL::SigBit> new_expand_non_feedback_nets;
+
+ for (auto &bit : expand_non_feedback_nets)
+ if (muxtree_upstream_map.count(bit))
+ for (auto &new_bit : muxtree_upstream_map.at(bit))
+ if (!non_feedback_nets.count(new_bit)) {
+ non_feedback_nets.insert(new_bit);
+ new_expand_non_feedback_nets.insert(new_bit);
+ }
+
+ expand_non_feedback_nets.swap(new_expand_non_feedback_nets);
+ }
+
+ for (auto cell : rd_ports)
+ {
+ if (cell->parameters.at("\\CLK_ENABLE").as_bool())
+ continue;
+
+ RTLIL::SigSpec sig_addr = sigmap(cell->getPort("\\ADDR"));
+ std::vector<RTLIL::SigBit> sig_data = sigmap(cell->getPort("\\DATA"));
+
+ for (int i = 0; i < int(sig_data.size()); i++)
+ if (non_feedback_nets.count(sig_data[i]))
+ goto not_pure_feedback_port;
+
+ async_rd_bits[sig_addr].resize(std::max(async_rd_bits.size(), sig_data.size()));
+ for (int i = 0; i < int(sig_data.size()); i++)
+ async_rd_bits[sig_addr][i].insert(sig_data[i]);
+
+ not_pure_feedback_port:;
+ }
+
+ if (async_rd_bits.empty())
+ return;
+
+ log("Populating enable bits on write ports of memory %s.%s with aync read feedback:\n", log_id(module), log_id(memid));
+
+ for (auto cell : wr_ports)
+ {
+ RTLIL::SigSpec sig_addr = sigmap_xmux(cell->getPort("\\ADDR"));
+ if (!async_rd_bits.count(sig_addr))
+ continue;
+
+ log(" Analyzing write port %s.\n", log_id(cell));
+
+ std::vector<RTLIL::SigBit> cell_data = cell->getPort("\\DATA");
+ std::vector<RTLIL::SigBit> cell_en = cell->getPort("\\EN");
+
+ int created_conditions = 0;
+ for (int i = 0; i < int(cell_data.size()); i++)
+ if (cell_en[i] != RTLIL::SigBit(RTLIL::State::S0))
+ {
+ std::map<RTLIL::SigBit, bool> state;
+ std::set<std::map<RTLIL::SigBit, bool>> conditions;
+
+ if (cell_en[i].wire != NULL) {
+ state[cell_en[i]] = false;
+ conditions.insert(state);
+ }
+
+ find_data_feedback(async_rd_bits.at(sig_addr).at(i), cell_data[i], state, conditions);
+ cell_en[i] = conditions_to_logic(conditions, created_conditions);
+ }
+
+ if (created_conditions) {
+ log(" Added enable logic for %d different cases.\n", created_conditions);
+ cell->setPort("\\EN", cell_en);
+ }
+ }
+ }
+
+
+ // ------------------------------------------------------
+ // Consolidate write ports that write to the same address
+ // ------------------------------------------------------
+
+ RTLIL::SigSpec mask_en_naive(RTLIL::SigSpec do_mask, RTLIL::SigSpec bits, RTLIL::SigSpec mask_bits)
+ {
+ // this is the naive version of the function that does not care about grouping the EN bits.
+
+ RTLIL::SigSpec inv_mask_bits = module->Not(NEW_ID, mask_bits);
+ RTLIL::SigSpec inv_mask_bits_filtered = module->Mux(NEW_ID, RTLIL::SigSpec(RTLIL::State::S1, bits.size()), inv_mask_bits, do_mask);
+ RTLIL::SigSpec result = module->And(NEW_ID, inv_mask_bits_filtered, bits);
+ return result;
+ }
+
+ RTLIL::SigSpec mask_en_grouped(RTLIL::SigSpec do_mask, RTLIL::SigSpec bits, RTLIL::SigSpec mask_bits)
+ {
+ // this version of the function preserves the bit grouping in the EN bits.
+
+ std::vector<RTLIL::SigBit> v_bits = bits;
+ std::vector<RTLIL::SigBit> v_mask_bits = mask_bits;
+
+ std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>, std::pair<int, std::vector<int>>> groups;
+ RTLIL::SigSpec grouped_bits, grouped_mask_bits;
+
+ for (int i = 0; i < bits.size(); i++) {
+ std::pair<RTLIL::SigBit, RTLIL::SigBit> key(v_bits[i], v_mask_bits[i]);
+ if (groups.count(key) == 0) {
+ groups[key].first = grouped_bits.size();
+ grouped_bits.append_bit(v_bits[i]);
+ grouped_mask_bits.append_bit(v_mask_bits[i]);
+ }
+ groups[key].second.push_back(i);
+ }
+
+ std::vector<RTLIL::SigBit> grouped_result = mask_en_naive(do_mask, grouped_bits, grouped_mask_bits);
+ RTLIL::SigSpec result;
+
+ for (int i = 0; i < bits.size(); i++) {
+ std::pair<RTLIL::SigBit, RTLIL::SigBit> key(v_bits[i], v_mask_bits[i]);
+ result.append_bit(grouped_result.at(groups.at(key).first));
+ }
+
+ return result;
+ }
+
+ void merge_en_data(RTLIL::SigSpec &merged_en, RTLIL::SigSpec &merged_data, RTLIL::SigSpec next_en, RTLIL::SigSpec next_data)
+ {
+ std::vector<RTLIL::SigBit> v_old_en = merged_en;
+ std::vector<RTLIL::SigBit> v_next_en = next_en;
+
+ // The new merged_en signal is just the old merged_en signal and next_en OR'ed together.
+ // But of course we need to preserve the bit grouping..
+
+ std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>, int> groups;
+ std::vector<RTLIL::SigBit> grouped_old_en, grouped_next_en;
+ RTLIL::SigSpec new_merged_en;
+
+ for (int i = 0; i < int(v_old_en.size()); i++) {
+ std::pair<RTLIL::SigBit, RTLIL::SigBit> key(v_old_en[i], v_next_en[i]);
+ if (groups.count(key) == 0) {
+ groups[key] = grouped_old_en.size();
+ grouped_old_en.push_back(key.first);
+ grouped_next_en.push_back(key.second);
+ }
+ }
+
+ std::vector<RTLIL::SigBit> grouped_new_en = module->Or(NEW_ID, grouped_old_en, grouped_next_en);
+
+ for (int i = 0; i < int(v_old_en.size()); i++) {
+ std::pair<RTLIL::SigBit, RTLIL::SigBit> key(v_old_en[i], v_next_en[i]);
+ new_merged_en.append_bit(grouped_new_en.at(groups.at(key)));
+ }
+
+ // Create the new merged_data signal.
+
+ RTLIL::SigSpec new_merged_data(RTLIL::State::Sx, merged_data.size());
+
+ RTLIL::SigSpec old_data_set = module->And(NEW_ID, merged_en, merged_data);
+ RTLIL::SigSpec old_data_unset = module->And(NEW_ID, merged_en, module->Not(NEW_ID, merged_data));
+
+ RTLIL::SigSpec new_data_set = module->And(NEW_ID, next_en, next_data);
+ RTLIL::SigSpec new_data_unset = module->And(NEW_ID, next_en, module->Not(NEW_ID, next_data));
+
+ new_merged_data = module->Or(NEW_ID, new_merged_data, old_data_set);
+ new_merged_data = module->And(NEW_ID, new_merged_data, module->Not(NEW_ID, old_data_unset));
+
+ new_merged_data = module->Or(NEW_ID, new_merged_data, new_data_set);
+ new_merged_data = module->And(NEW_ID, new_merged_data, module->Not(NEW_ID, new_data_unset));
+
+ // Update merged_* signals
+
+ merged_en = new_merged_en;
+ merged_data = new_merged_data;
+ }
+
+ void consolidate_wr_by_addr(std::string memid, std::vector<RTLIL::Cell*> &wr_ports)
+ {
+ if (wr_ports.size() <= 1)
+ return;
+
+ log("Consolidating write ports of memory %s.%s by address:\n", log_id(module), log_id(memid));
+
+ std::map<RTLIL::SigSpec, int> last_port_by_addr;
+ std::vector<std::vector<bool>> active_bits_on_port;
+
+ bool cache_clk_enable = false;
+ bool cache_clk_polarity = false;
+ RTLIL::SigSpec cache_clk;
+
+ for (int i = 0; i < int(wr_ports.size()); i++)
+ {
+ RTLIL::Cell *cell = wr_ports.at(i);
+ RTLIL::SigSpec addr = sigmap_xmux(cell->getPort("\\ADDR"));
+
+ if (cell->parameters.at("\\CLK_ENABLE").as_bool() != cache_clk_enable ||
+ (cache_clk_enable && (sigmap(cell->getPort("\\CLK")) != cache_clk ||
+ cell->parameters.at("\\CLK_POLARITY").as_bool() != cache_clk_polarity)))
+ {
+ cache_clk_enable = cell->parameters.at("\\CLK_ENABLE").as_bool();
+ cache_clk_polarity = cell->parameters.at("\\CLK_POLARITY").as_bool();
+ cache_clk = sigmap(cell->getPort("\\CLK"));
+ last_port_by_addr.clear();
+
+ if (cache_clk_enable)
+ log(" New clock domain: %s %s\n", cache_clk_polarity ? "posedge" : "negedge", log_signal(cache_clk));
+ else
+ log(" New clock domain: unclocked\n");
+ }
+
+ log(" Port %d (%s) has addr %s.\n", i, log_id(cell), log_signal(addr));
+
+ log(" Active bits: ");
+ std::vector<RTLIL::SigBit> en_bits = sigmap(cell->getPort("\\EN"));
+ active_bits_on_port.push_back(std::vector<bool>(en_bits.size()));
+ for (int k = int(en_bits.size())-1; k >= 0; k--) {
+ active_bits_on_port[i][k] = en_bits[k].wire != NULL || en_bits[k].data != RTLIL::State::S0;
+ log("%c", active_bits_on_port[i][k] ? '1' : '0');
+ }
+ log("\n");
+
+ if (last_port_by_addr.count(addr))
+ {
+ int last_i = last_port_by_addr.at(addr);
+ log(" Merging port %d into this one.\n", last_i);
+
+ bool found_overlapping_bits = false;
+ for (int k = 0; k < int(en_bits.size()); k++) {
+ if (active_bits_on_port[i][k] && active_bits_on_port[last_i][k])
+ found_overlapping_bits = true;
+ active_bits_on_port[i][k] = active_bits_on_port[i][k] || active_bits_on_port[last_i][k];
+ }
+
+ // Force this ports addr input to addr directly (skip don't care muxes)
+
+ cell->setPort("\\ADDR", addr);
+
+ // If any of the ports between `last_i' and `i' write to the same address, this
+ // will have priority over whatever `last_i` wrote. So we need to revisit those
+ // ports and mask the EN bits accordingly.
+
+ RTLIL::SigSpec merged_en = sigmap(wr_ports[last_i]->getPort("\\EN"));
+
+ for (int j = last_i+1; j < i; j++)
+ {
+ if (wr_ports[j] == NULL)
+ continue;
+
+ for (int k = 0; k < int(en_bits.size()); k++)
+ if (active_bits_on_port[i][k] && active_bits_on_port[j][k])
+ goto found_overlapping_bits_i_j;
+
+ if (0) {
+ found_overlapping_bits_i_j:
+ log(" Creating collosion-detect logic for port %d.\n", j);
+ RTLIL::SigSpec is_same_addr = module->addWire(NEW_ID);
+ module->addEq(NEW_ID, addr, wr_ports[j]->getPort("\\ADDR"), is_same_addr);
+ merged_en = mask_en_grouped(is_same_addr, merged_en, sigmap(wr_ports[j]->getPort("\\EN")));
+ }
+ }
+
+ // Then we need to merge the (masked) EN and the DATA signals.
+
+ RTLIL::SigSpec merged_data = wr_ports[last_i]->getPort("\\DATA");
+ if (found_overlapping_bits) {
+ log(" Creating logic for merging DATA and EN ports.\n");
+ merge_en_data(merged_en, merged_data, sigmap(cell->getPort("\\EN")), sigmap(cell->getPort("\\DATA")));
+ } else {
+ RTLIL::SigSpec cell_en = sigmap(cell->getPort("\\EN"));
+ RTLIL::SigSpec cell_data = sigmap(cell->getPort("\\DATA"));
+ for (int k = 0; k < int(en_bits.size()); k++)
+ if (!active_bits_on_port[last_i][k]) {
+ merged_en.replace(k, cell_en.extract(k, 1));
+ merged_data.replace(k, cell_data.extract(k, 1));
+ }
+ }
+
+ // Connect the new EN and DATA signals and remove the old write port.
+
+ cell->setPort("\\EN", merged_en);
+ cell->setPort("\\DATA", merged_data);
+
+ module->remove(wr_ports[last_i]);
+ wr_ports[last_i] = NULL;
+
+ log(" Active bits: ");
+ std::vector<RTLIL::SigBit> en_bits = sigmap(cell->getPort("\\EN"));
+ active_bits_on_port.push_back(std::vector<bool>(en_bits.size()));
+ for (int k = int(en_bits.size())-1; k >= 0; k--)
+ log("%c", active_bits_on_port[i][k] ? '1' : '0');
+ log("\n");
+ }
+
+ last_port_by_addr[addr] = i;
+ }
+
+ // Clean up `wr_ports': remove all NULL entries
+
+ std::vector<RTLIL::Cell*> wr_ports_with_nulls;
+ wr_ports_with_nulls.swap(wr_ports);
+
+ for (auto cell : wr_ports_with_nulls)
+ if (cell != NULL)
+ wr_ports.push_back(cell);
+ }
+
+
+ // --------------------------------------------------------
+ // Consolidate write ports using sat-based resource sharing
+ // --------------------------------------------------------
+
+ void consolidate_wr_using_sat(std::string memid, std::vector<RTLIL::Cell*> &wr_ports)
+ {
+ if (wr_ports.size() <= 1)
+ return;
+
+ ezDefaultSAT ez;
+ SatGen satgen(&ez, &modwalker.sigmap);
+
+ // find list of considered ports and port pairs
+
+ std::set<int> considered_ports;
+ std::set<int> considered_port_pairs;
+
+ for (int i = 0; i < int(wr_ports.size()); i++) {
+ std::vector<RTLIL::SigBit> bits = modwalker.sigmap(wr_ports[i]->getPort("\\EN"));
+ for (auto bit : bits)
+ if (bit == RTLIL::State::S1)
+ goto port_is_always_active;
+ if (modwalker.has_drivers(bits))
+ considered_ports.insert(i);
+ port_is_always_active:;
+ }
+
+ log("Consolidating write ports of memory %s.%s using sat-based resource sharing:\n", log_id(module), log_id(memid));
+
+ bool cache_clk_enable = false;
+ bool cache_clk_polarity = false;
+ RTLIL::SigSpec cache_clk;
+
+ for (int i = 0; i < int(wr_ports.size()); i++)
+ {
+ RTLIL::Cell *cell = wr_ports.at(i);
+
+ if (cell->parameters.at("\\CLK_ENABLE").as_bool() != cache_clk_enable ||
+ (cache_clk_enable && (sigmap(cell->getPort("\\CLK")) != cache_clk ||
+ cell->parameters.at("\\CLK_POLARITY").as_bool() != cache_clk_polarity)))
+ {
+ cache_clk_enable = cell->parameters.at("\\CLK_ENABLE").as_bool();
+ cache_clk_polarity = cell->parameters.at("\\CLK_POLARITY").as_bool();
+ cache_clk = sigmap(cell->getPort("\\CLK"));
+ }
+ else if (i > 0 && considered_ports.count(i-1) && considered_ports.count(i))
+ considered_port_pairs.insert(i);
+
+ if (cache_clk_enable)
+ log(" Port %d (%s) on %s %s: %s\n", i, log_id(cell),
+ cache_clk_polarity ? "posedge" : "negedge", log_signal(cache_clk),
+ considered_ports.count(i) ? "considered" : "not considered");
+ else
+ log(" Port %d (%s) unclocked: %s\n", i, log_id(cell),
+ considered_ports.count(i) ? "considered" : "not considered");
+ }
+
+ if (considered_port_pairs.size() < 1) {
+ log(" No two subsequent ports in same clock domain considered -> nothing to consolidate.\n");
+ return;
+ }
+
+ // create SAT representation of common input cone of all considered EN signals
+
+ std::set<RTLIL::Cell*> sat_cells;
+ std::set<RTLIL::SigBit> bits_queue;
+ std::map<int, int> port_to_sat_variable;
+
+ for (int i = 0; i < int(wr_ports.size()); i++)
+ if (considered_port_pairs.count(i) || considered_port_pairs.count(i+1))
+ {
+ RTLIL::SigSpec sig = modwalker.sigmap(wr_ports[i]->getPort("\\EN"));
+ port_to_sat_variable[i] = ez.expression(ez.OpOr, satgen.importSigSpec(sig));
+
+ std::vector<RTLIL::SigBit> bits = sig;
+ bits_queue.insert(bits.begin(), bits.end());
+ }
+
+ while (!bits_queue.empty())
+ {
+ std::set<ModWalker::PortBit> portbits;
+ modwalker.get_drivers(portbits, bits_queue);
+ bits_queue.clear();
+
+ for (auto &pbit : portbits)
+ if (sat_cells.count(pbit.cell) == 0 && cone_ct.cell_known(pbit.cell->type)) {
+ std::set<RTLIL::SigBit> &cell_inputs = modwalker.cell_inputs[pbit.cell];
+ bits_queue.insert(cell_inputs.begin(), cell_inputs.end());
+ sat_cells.insert(pbit.cell);
+ }
+ }
+
+ log(" Common input cone for all EN signals: %d cells.\n", int(sat_cells.size()));
+
+ for (auto cell : sat_cells)
+ satgen.importCell(cell);
+
+ log(" Size of unconstrained SAT problem: %d variables, %d clauses\n", ez.numCnfVariables(), ez.numCnfClauses());
+
+ // merge subsequent ports if possible
+
+ for (int i = 0; i < int(wr_ports.size()); i++)
+ {
+ if (!considered_port_pairs.count(i))
+ continue;
+
+ if (ez.solve(port_to_sat_variable.at(i-1), port_to_sat_variable.at(i))) {
+ log(" According to SAT solver sharing of port %d with port %d is not possible.\n", i-1, i);
+ continue;
+ }
+
+ log(" Merging port %d into port %d.\n", i-1, i);
+ port_to_sat_variable.at(i) = ez.OR(port_to_sat_variable.at(i-1), port_to_sat_variable.at(i));
+
+ RTLIL::SigSpec last_addr = wr_ports[i-1]->getPort("\\ADDR");
+ RTLIL::SigSpec last_data = wr_ports[i-1]->getPort("\\DATA");
+ std::vector<RTLIL::SigBit> last_en = modwalker.sigmap(wr_ports[i-1]->getPort("\\EN"));
+
+ RTLIL::SigSpec this_addr = wr_ports[i]->getPort("\\ADDR");
+ RTLIL::SigSpec this_data = wr_ports[i]->getPort("\\DATA");
+ std::vector<RTLIL::SigBit> this_en = modwalker.sigmap(wr_ports[i]->getPort("\\EN"));
+
+ RTLIL::SigBit this_en_active = module->ReduceOr(NEW_ID, this_en);
+
+ wr_ports[i]->setPort("\\ADDR", module->Mux(NEW_ID, last_addr, this_addr, this_en_active));
+ wr_ports[i]->setPort("\\DATA", module->Mux(NEW_ID, last_data, this_data, this_en_active));
+
+ std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>, int> groups_en;
+ RTLIL::SigSpec grouped_last_en, grouped_this_en, en;
+ RTLIL::Wire *grouped_en = module->addWire(NEW_ID, 0);
+
+ for (int j = 0; j < int(this_en.size()); j++) {
+ std::pair<RTLIL::SigBit, RTLIL::SigBit> key(last_en[j], this_en[j]);
+ if (!groups_en.count(key)) {
+ grouped_last_en.append_bit(last_en[j]);
+ grouped_this_en.append_bit(this_en[j]);
+ groups_en[key] = grouped_en->width;
+ grouped_en->width++;
+ }
+ en.append(RTLIL::SigSpec(grouped_en, groups_en[key]));
+ }
+
+ module->addMux(NEW_ID, grouped_last_en, grouped_this_en, this_en_active, grouped_en);
+ wr_ports[i]->setPort("\\EN", en);
+
+ module->remove(wr_ports[i-1]);
+ wr_ports[i-1] = NULL;
+ }
+
+ // Clean up `wr_ports': remove all NULL entries
+
+ std::vector<RTLIL::Cell*> wr_ports_with_nulls;
+ wr_ports_with_nulls.swap(wr_ports);
+
+ for (auto cell : wr_ports_with_nulls)
+ if (cell != NULL)
+ wr_ports.push_back(cell);
+ }
+
+
+ // -------------
+ // Setup and run
+ // -------------
+
+ MemoryShareWorker(RTLIL::Design *design, RTLIL::Module *module) :
+ design(design), module(module), sigmap(module)
+ {
+ std::map<std::string, std::pair<std::vector<RTLIL::Cell*>, std::vector<RTLIL::Cell*>>> memindex;
+
+ sigmap_xmux = sigmap;
+ for (auto &it : module->cells_)
+ {
+ RTLIL::Cell *cell = it.second;
+
+ if (cell->type == "$memrd")
+ memindex[cell->parameters.at("\\MEMID").decode_string()].first.push_back(cell);
+
+ if (cell->type == "$memwr")
+ memindex[cell->parameters.at("\\MEMID").decode_string()].second.push_back(cell);
+
+ if (cell->type == "$mux")
+ {
+ RTLIL::SigSpec sig_a = sigmap_xmux(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = sigmap_xmux(cell->getPort("\\B"));
+
+ if (sig_a.is_fully_undef())
+ sigmap_xmux.add(cell->getPort("\\Y"), sig_b);
+ else if (sig_b.is_fully_undef())
+ sigmap_xmux.add(cell->getPort("\\Y"), sig_a);
+ }
+
+ if (cell->type == "$mux" || cell->type == "$pmux")
+ {
+ std::vector<RTLIL::SigBit> sig_y = sigmap(cell->getPort("\\Y"));
+ for (int i = 0; i < int(sig_y.size()); i++)
+ sig_to_mux[sig_y[i]] = std::pair<RTLIL::Cell*, int>(cell, i);
+ }
+ }
+
+ for (auto &it : memindex) {
+ std::sort(it.second.first.begin(), it.second.first.end(), memcells_cmp);
+ std::sort(it.second.second.begin(), it.second.second.end(), memcells_cmp);
+ translate_rd_feedback_to_en(it.first, it.second.first, it.second.second);
+ consolidate_wr_by_addr(it.first, it.second.second);
+ }
+
+ cone_ct.setup_internals();
+ cone_ct.cell_types.erase("$mul");
+ cone_ct.cell_types.erase("$mod");
+ cone_ct.cell_types.erase("$div");
+ cone_ct.cell_types.erase("$pow");
+ cone_ct.cell_types.erase("$shl");
+ cone_ct.cell_types.erase("$shr");
+ cone_ct.cell_types.erase("$sshl");
+ cone_ct.cell_types.erase("$sshr");
+ cone_ct.cell_types.erase("$shift");
+ cone_ct.cell_types.erase("$shiftx");
+
+ modwalker.setup(design, module, &cone_ct);
+
+ for (auto &it : memindex)
+ consolidate_wr_using_sat(it.first, it.second.second);
+ }
+};
+
+struct MemorySharePass : public Pass {
+ MemorySharePass() : Pass("memory_share", "consolidate memory ports") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" memory_share [selection]\n");
+ log("\n");
+ log("This pass merges share-able memory ports into single memory ports.\n");
+ log("\n");
+ log("The following methods are used to consolidate the number of memory ports:\n");
+ log("\n");
+ log(" - When write ports are connected to async read ports accessing the same\n");
+ log(" address, then this feedback path is converted to a write port with\n");
+ log(" byte/part enable signals.\n");
+ log("\n");
+ log(" - When multiple write ports access the same address then this is converted\n");
+ log(" to a single write port with a more complex data and/or enable logic path.\n");
+ log("\n");
+ log(" - When multiple write ports are never accessed at the same time (a SAT\n");
+ log(" solver is used to determine this), then the ports are merged into a single\n");
+ log(" write port.\n");
+ log("\n");
+ log("Note that in addition to the algorithms implemented in this pass, the $memrd\n");
+ log("and $memwr cells are also subject to generic resource sharing passes (and other\n");
+ log("optimizations) such as opt_share.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ log_header("Executing MEMORY_SHARE pass (consolidating $memrc/$memwr cells).\n");
+ extra_args(args, 1, design);
+ for (auto module : design->selected_modules())
+ MemoryShareWorker(design, module);
+ }
+} MemorySharePass;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc
index 782c0cd7..5a4c4eac 100644
--- a/passes/memory/memory_unpack.cc
+++ b/passes/memory/memory_unpack.cc
@@ -22,7 +22,6 @@
#include <sstream>
#include <algorithm>
#include <stdlib.h>
-#include <assert.h>
static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
{
@@ -32,7 +31,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
RTLIL::IdString mem_name = RTLIL::escape_id(memory->parameters.at("\\MEMID").decode_string());
while (module->memories.count(mem_name) != 0)
- mem_name += stringf("_%d", RTLIL::autoidx++);
+ mem_name = mem_name.str() + stringf("_%d", autoidx++);
RTLIL::Memory *mem = new RTLIL::Memory;
mem->name = mem_name;
@@ -47,51 +46,44 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
for (int i = 0; i < num_rd_ports; i++)
{
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$memrd";
- cell->parameters["\\MEMID"] = mem_name;
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$memrd");
+ cell->parameters["\\MEMID"] = mem_name.str();
cell->parameters["\\ABITS"] = memory->parameters.at("\\ABITS");
cell->parameters["\\WIDTH"] = memory->parameters.at("\\WIDTH");
cell->parameters["\\CLK_ENABLE"] = RTLIL::SigSpec(memory->parameters.at("\\RD_CLK_ENABLE")).extract(i, 1).as_const();
cell->parameters["\\CLK_POLARITY"] = RTLIL::SigSpec(memory->parameters.at("\\RD_CLK_POLARITY")).extract(i, 1).as_const();
cell->parameters["\\TRANSPARENT"] = RTLIL::SigSpec(memory->parameters.at("\\RD_TRANSPARENT")).extract(i, 1).as_const();
- cell->connections["\\CLK"] = memory->connections.at("\\RD_CLK").extract(i, 1);
- cell->connections["\\ADDR"] = memory->connections.at("\\RD_ADDR").extract(i*abits, abits);
- cell->connections["\\DATA"] = memory->connections.at("\\RD_DATA").extract(i*mem->width, mem->width);
- module->add(cell);
+ cell->setPort("\\CLK", memory->getPort("\\RD_CLK").extract(i, 1));
+ cell->setPort("\\ADDR", memory->getPort("\\RD_ADDR").extract(i*abits, abits));
+ cell->setPort("\\DATA", memory->getPort("\\RD_DATA").extract(i*mem->width, mem->width));
}
for (int i = 0; i < num_wr_ports; i++)
{
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$memwr";
- cell->parameters["\\MEMID"] = mem_name;
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$memwr");
+ cell->parameters["\\MEMID"] = mem_name.str();
cell->parameters["\\ABITS"] = memory->parameters.at("\\ABITS");
cell->parameters["\\WIDTH"] = memory->parameters.at("\\WIDTH");
cell->parameters["\\CLK_ENABLE"] = RTLIL::SigSpec(memory->parameters.at("\\WR_CLK_ENABLE")).extract(i, 1).as_const();
cell->parameters["\\CLK_POLARITY"] = RTLIL::SigSpec(memory->parameters.at("\\WR_CLK_POLARITY")).extract(i, 1).as_const();
cell->parameters["\\PRIORITY"] = i;
- cell->connections["\\CLK"] = memory->connections.at("\\WR_CLK").extract(i, 1);
- cell->connections["\\EN"] = memory->connections.at("\\WR_EN").extract(i, 1);
- cell->connections["\\ADDR"] = memory->connections.at("\\WR_ADDR").extract(i*abits, abits);
- cell->connections["\\DATA"] = memory->connections.at("\\WR_DATA").extract(i*mem->width, mem->width);
- module->add(cell);
+ cell->setPort("\\CLK", memory->getPort("\\WR_CLK").extract(i, 1));
+ cell->setPort("\\EN", memory->getPort("\\WR_EN").extract(i*mem->width, mem->width));
+ cell->setPort("\\ADDR", memory->getPort("\\WR_ADDR").extract(i*abits, abits));
+ cell->setPort("\\DATA", memory->getPort("\\WR_DATA").extract(i*mem->width, mem->width));
}
- module->cells.erase(memory->name);
- delete memory;
+ module->remove(memory);
}
static void handle_module(RTLIL::Design *design, RTLIL::Module *module)
{
std::vector<RTLIL::IdString> memcells;
- for (auto &cell_it : module->cells)
+ for (auto &cell_it : module->cells_)
if (cell_it.second->type == "$mem" && design->selected(module, cell_it.second))
memcells.push_back(cell_it.first);
for (auto &it : memcells)
- handle_memory(module, module->cells.at(it));
+ handle_memory(module, module->cells_.at(it));
}
struct MemoryUnpackPass : public Pass {
@@ -109,7 +101,7 @@ struct MemoryUnpackPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
log_header("Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
handle_module(design, mod_it.second);
}
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index 9dfb32c8..3a8d27f9 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -6,4 +6,6 @@ OBJS += passes/opt/opt_reduce.o
OBJS += passes/opt/opt_rmdff.o
OBJS += passes/opt/opt_clean.o
OBJS += passes/opt/opt_const.o
+OBJS += passes/opt/share.o
+OBJS += passes/opt/wreduce.o
diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc
index 8f4725e1..b20521d1 100644
--- a/passes/opt/opt.cc
+++ b/passes/opt/opt.cc
@@ -17,43 +17,55 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
-bool OPT_DID_SOMETHING;
-
struct OptPass : public Pass {
OptPass() : Pass("opt", "perform simple optimizations") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" opt [-purge] [-mux_undef] [-mux_bool] [-undriven] [selection]\n");
+ log(" opt [options] [selection]\n");
log("\n");
log("This pass calls all the other opt_* passes in a useful order. This performs\n");
log("a series of trivial optimizations and cleanups. This pass executes the other\n");
log("passes in the following order:\n");
log("\n");
- log(" opt_const\n");
+ log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-keepdc]\n");
log(" opt_share -nomux\n");
log("\n");
log(" do\n");
log(" opt_muxtree\n");
- log(" opt_reduce\n");
+ log(" opt_reduce [-fine]\n");
+ log(" opt_share\n");
+ log(" opt_rmdff\n");
+ log(" opt_clean [-purge]\n");
+ log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-keepdc]\n");
+ log(" while <changed design>\n");
+ log("\n");
+ log("When called with -fast the following script is used instead:\n");
+ log("\n");
+ log(" do\n");
+ log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-keepdc]\n");
log(" opt_share\n");
log(" opt_rmdff\n");
log(" opt_clean [-purge]\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven]\n");
- log(" while [changed design]\n");
+ log(" while <changed design in opt_rmdff>\n");
+ log("\n");
+ log("Note: Options in square brackets (such as [-keepdc]) are passed through to\n");
+ log("the opt_* commands when given to 'opt'.\n");
+ log("\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
std::string opt_clean_args;
std::string opt_const_args;
+ std::string opt_reduce_args;
+ bool fast_mode = false;
log_header("Executing OPT pass (performing simple optimizations).\n");
log_push();
@@ -76,32 +88,56 @@ struct OptPass : public Pass {
opt_const_args += " -undriven";
continue;
}
+ if (args[argidx] == "-fine") {
+ opt_const_args += " -fine";
+ opt_reduce_args += " -fine";
+ continue;
+ }
+ if (args[argidx] == "-keepdc") {
+ opt_const_args += " -keepdc";
+ continue;
+ }
+ if (args[argidx] == "-fast") {
+ fast_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
- log_header("Optimizing in-memory representation of design.\n");
- design->optimize();
-
- Pass::call(design, "opt_const");
- Pass::call(design, "opt_share -nomux");
- while (1) {
- OPT_DID_SOMETHING = false;
- Pass::call(design, "opt_muxtree");
- Pass::call(design, "opt_reduce");
- Pass::call(design, "opt_share");
- Pass::call(design, "opt_rmdff");
+ if (fast_mode)
+ {
+ while (1) {
+ Pass::call(design, "opt_const" + opt_const_args);
+ Pass::call(design, "opt_share");
+ design->scratchpad_unset("opt.did_something");
+ Pass::call(design, "opt_rmdff");
+ if (design->scratchpad_get_bool("opt.did_something") == false)
+ break;
+ Pass::call(design, "opt_clean" + opt_clean_args);
+ log_header("Rerunning OPT passes. (Removed registers in this run.)\n");
+ }
Pass::call(design, "opt_clean" + opt_clean_args);
+ }
+ else
+ {
Pass::call(design, "opt_const" + opt_const_args);
- if (OPT_DID_SOMETHING == false)
- break;
- log_header("Rerunning OPT passes. (Maybe there is more to do..)\n");
+ Pass::call(design, "opt_share -nomux");
+ while (1) {
+ design->scratchpad_unset("opt.did_something");
+ Pass::call(design, "opt_muxtree");
+ Pass::call(design, "opt_reduce" + opt_reduce_args);
+ Pass::call(design, "opt_share");
+ Pass::call(design, "opt_rmdff");
+ Pass::call(design, "opt_clean" + opt_clean_args);
+ Pass::call(design, "opt_const" + opt_const_args);
+ if (design->scratchpad_get_bool("opt.did_something") == false)
+ break;
+ log_header("Rerunning OPT passes. (Maybe there is more to do..)\n");
+ }
}
- log_header("Optimizing in-memory representation of design.\n");
- design->optimize();
-
- log_header("Finished OPT passes. (There is nothing left to do.)\n");
+ log_header(fast_mode ? "Finished fast OPT passes." : "Finished OPT passes. (There is nothing left to do.)\n");
log_pop();
}
} OptPass;
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 733a1cbf..5046752f 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -17,13 +17,11 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include "kernel/celltypes.h"
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <set>
@@ -35,12 +33,12 @@ static int count_rm_cells, count_rm_wires;
static void rmunused_module_cells(RTLIL::Module *module, bool verbose)
{
SigMap assign_map(module);
- std::set<RTLIL::Cell*, RTLIL::sort_by_name<RTLIL::Cell>> queue, unused;
+ std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> queue, unused;
SigSet<RTLIL::Cell*> wire2driver;
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
- for (auto &it2 : cell->connections) {
+ for (auto &it2 : cell->connections()) {
if (!ct.cell_input(cell->type, it2.first)) {
RTLIL::SigSpec sig = it2.second;
assign_map.apply(sig);
@@ -52,7 +50,7 @@ static void rmunused_module_cells(RTLIL::Module *module, bool verbose)
unused.insert(cell);
}
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
RTLIL::Wire *wire = it.second;
if (wire->port_output || wire->get_bool_attribute("\\keep")) {
std::set<RTLIL::Cell*> cell_list;
@@ -66,11 +64,11 @@ static void rmunused_module_cells(RTLIL::Module *module, bool verbose)
while (queue.size() > 0)
{
- std::set<RTLIL::Cell*, RTLIL::sort_by_name<RTLIL::Cell>> new_queue;
+ std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> new_queue;
for (auto cell : queue)
unused.erase(cell);
for (auto cell : queue) {
- for (auto &it : cell->connections) {
+ for (auto &it : cell->connections()) {
if (!ct.cell_output(cell->type, it.first)) {
std::set<RTLIL::Cell*> cell_list;
RTLIL::SigSpec sig = it.second;
@@ -89,10 +87,9 @@ static void rmunused_module_cells(RTLIL::Module *module, bool verbose)
for (auto cell : unused) {
if (verbose)
log(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str());
- OPT_DID_SOMETHING = true;
- module->cells.erase(cell->name);
+ module->design->scratchpad_set_bool("opt.did_something", true);
+ module->remove(cell);
count_rm_cells++;
- delete cell;
}
}
@@ -104,15 +101,10 @@ static int count_nontrivial_wire_attrs(RTLIL::Wire *w)
return count;
}
-static bool compare_signals(RTLIL::SigSpec &s1, RTLIL::SigSpec &s2, SigPool &regs, SigPool &conns, std::set<RTLIL::Wire*> &direct_wires)
+static bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPool &conns, std::set<RTLIL::Wire*> &direct_wires)
{
- assert(s1.width == 1);
- assert(s2.width == 1);
- assert(s1.chunks.size() == 1);
- assert(s2.chunks.size() == 1);
-
- RTLIL::Wire *w1 = s1.chunks[0].wire;
- RTLIL::Wire *w2 = s2.chunks[0].wire;
+ RTLIL::Wire *w1 = s1.wire;
+ RTLIL::Wire *w2 = s2.wire;
if (w1 == NULL || w2 == NULL)
return w2 == NULL;
@@ -146,11 +138,12 @@ static bool compare_signals(RTLIL::SigSpec &s1, RTLIL::SigSpec &s2, SigPool &reg
static bool check_public_name(RTLIL::IdString id)
{
- if (id[0] == '$')
+ const std::string &id_str = id.str();
+ if (id_str[0] == '$')
return false;
- if (id.substr(0, 2) == "\\_" && (id[id.size()-1] == '_' || id.find("_[") != std::string::npos))
+ if (id_str.substr(0, 2) == "\\_" && (id_str[id_str.size()-1] == '_' || id_str.find("_[") != std::string::npos))
return false;
- if (id.find(".$") != std::string::npos)
+ if (id_str.find(".$") != std::string::npos)
return false;
return true;
}
@@ -161,54 +154,54 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
SigPool connected_signals;
if (!purge_mode)
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
if (ct_reg.cell_known(cell->type))
- for (auto &it2 : cell->connections)
+ for (auto &it2 : cell->connections())
if (ct_reg.cell_output(cell->type, it2.first))
register_signals.add(it2.second);
- for (auto &it2 : cell->connections)
+ for (auto &it2 : cell->connections())
connected_signals.add(it2.second);
}
SigMap assign_map(module);
std::set<RTLIL::SigSpec> direct_sigs;
std::set<RTLIL::Wire*> direct_wires;
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
if (ct_all.cell_known(cell->type))
- for (auto &it2 : cell->connections)
+ for (auto &it2 : cell->connections())
if (ct_all.cell_output(cell->type, it2.first))
direct_sigs.insert(assign_map(it2.second));
}
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
if (direct_sigs.count(assign_map(it.second)) || it.second->port_input)
direct_wires.insert(it.second);
}
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
RTLIL::Wire *wire = it.second;
for (int i = 0; i < wire->width; i++) {
- RTLIL::SigSpec s1 = RTLIL::SigSpec(wire, 1, i), s2 = assign_map(s1);
+ RTLIL::SigBit s1 = RTLIL::SigBit(wire, i), s2 = assign_map(s1);
if (!compare_signals(s1, s2, register_signals, connected_signals, direct_wires))
assign_map.add(s1);
}
}
- module->connections.clear();
+ module->connections_.clear();
SigPool used_signals;
SigPool used_signals_nodrivers;
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
- for (auto &it2 : cell->connections) {
+ for (auto &it2 : cell->connections_) {
assign_map.apply(it2.second);
used_signals.add(it2.second);
if (!ct.cell_output(cell->type, it2.first))
used_signals_nodrivers.add(it2.second);
}
}
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
RTLIL::Wire *wire = it.second;
if (wire->port_id > 0) {
RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
@@ -224,47 +217,43 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
}
}
- std::vector<RTLIL::Wire*> del_wires;
- for (auto &it : module->wires) {
- RTLIL::Wire *wire = it.second;
- if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0) {
+ std::vector<RTLIL::Wire*> maybe_del_wires;
+ for (auto wire : module->wires())
+ {
+ if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep")) {
RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1;
assign_map.apply(s2);
- if (!used_signals.check_any(s2) && wire->port_id == 0) {
- del_wires.push_back(wire);
+ if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) {
+ maybe_del_wires.push_back(wire);
} else {
- s1.expand();
- s2.expand();
- assert(s1.chunks.size() == s2.chunks.size());
+ log_assert(SIZE(s1) == SIZE(s2));
RTLIL::SigSig new_conn;
- for (size_t i = 0; i < s1.chunks.size(); i++)
- if (s1.chunks[i] != s2.chunks[i]) {
- new_conn.first.append(s1.chunks[i]);
- new_conn.second.append(s2.chunks[i]);
+ for (int i = 0; i < SIZE(s1); i++)
+ if (s1[i] != s2[i]) {
+ new_conn.first.append_bit(s1[i]);
+ new_conn.second.append_bit(s2[i]);
}
- if (new_conn.first.width > 0) {
- new_conn.first.optimize();
- new_conn.second.optimize();
+ if (new_conn.first.size() > 0) {
used_signals.add(new_conn.first);
used_signals.add(new_conn.second);
- module->connections.push_back(new_conn);
+ module->connect(new_conn);
}
}
} else {
if (!used_signals.check_any(RTLIL::SigSpec(wire)))
- del_wires.push_back(wire);
+ maybe_del_wires.push_back(wire);
}
+
RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire));
if (!used_signals_nodrivers.check_any(sig)) {
std::string unused_bits;
- sig.expand();
- for (size_t i = 0; i < sig.chunks.size(); i++) {
- if (sig.chunks[i].wire == NULL)
+ for (int i = 0; i < SIZE(sig); i++) {
+ if (sig[i].wire == NULL)
continue;
- if (!used_signals_nodrivers.check_any(sig)) {
+ if (!used_signals_nodrivers.check(sig[i])) {
if (!unused_bits.empty())
unused_bits += " ";
- unused_bits += stringf("%zd", i);
+ unused_bits += stringf("%d", i);
}
}
if (unused_bits.empty() || wire->port_id != 0)
@@ -276,18 +265,22 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
}
}
+
+ std::set<RTLIL::Wire*> del_wires;
+
int del_wires_count = 0;
- for (auto wire : del_wires)
+ for (auto wire : maybe_del_wires)
if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
if (check_public_name(wire->name) && verbose) {
log(" removing unused non-port wire %s.\n", wire->name.c_str());
del_wires_count++;
}
- module->wires.erase(wire->name);
- count_rm_wires++;
- delete wire;
+ del_wires.insert(wire);
}
+ module->remove(del_wires);
+ count_rm_wires += del_wires.size();;
+
if (del_wires_count > 0)
log(" removed %d unused temporary wires.\n", del_wires_count);
}
@@ -345,7 +338,7 @@ struct OptCleanPass : public Pass {
ct_reg.setup_internals_mem();
ct_reg.setup_stdcells_mem();
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (!design->selected_whole_module(mod_it.first)) {
if (design->selected(mod_it.second))
log("Skipping module %s as it is only partially selected.\n", id2cstr(mod_it.second->name));
@@ -374,10 +367,10 @@ struct CleanPass : public Pass {
log("\n");
log("This is identical to 'opt_clean', but less verbose.\n");
log("\n");
- log("When commands are seperated using the ';;' token, this command will be executed\n");
+ log("When commands are separated using the ';;' token, this command will be executed\n");
log("between the commands.\n");
log("\n");
- log("When commands are seperated using the ';;;' token, this command will be executed\n");
+ log("When commands are separated using the ';;;' token, this command will be executed\n");
log("in -purge mode between the commands.\n");
log("\n");
}
@@ -409,12 +402,12 @@ struct CleanPass : public Pass {
count_rm_cells = 0;
count_rm_wires = 0;
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (design->selected_whole_module(mod_it.first) && mod_it.second->processes.size() == 0)
do {
- OPT_DID_SOMETHING = false;
+ design->scratchpad_unset("opt.did_something");
rmunused_module(mod_it.second, purge_mode, false);
- } while (OPT_DID_SOMETHING);
+ } while (design->scratchpad_get_bool("opt.did_something"));
}
if (count_rm_cells > 0 || count_rm_wires > 0)
diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_const.cc
index 34d1a69c..f9b78c05 100644
--- a/passes/opt/opt_const.cc
+++ b/passes/opt/opt_const.cc
@@ -17,19 +17,18 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
+#include "kernel/utils.h"
#include "kernel/log.h"
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
-#include <set>
+#include <algorithm>
static bool did_something;
-void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
+static void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
{
CellTypes ct(design);
SigMap sigmap(module);
@@ -37,95 +36,350 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
SigPool used_signals;
SigPool all_signals;
- for (auto &it : module->cells)
- for (auto &conn : it.second->connections) {
- if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first))
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections()) {
+ if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first))
driven_signals.add(sigmap(conn.second));
- if (!ct.cell_known(it.second->type) || ct.cell_input(it.second->type, conn.first))
+ if (!ct.cell_known(cell->type) || ct.cell_input(cell->type, conn.first))
used_signals.add(sigmap(conn.second));
}
- for (auto &it : module->wires) {
- if (it.second->port_input)
- driven_signals.add(sigmap(it.second));
- if (it.second->port_output)
- used_signals.add(sigmap(it.second));
- all_signals.add(sigmap(it.second));
+ for (auto wire : module->wires()) {
+ if (wire->port_input)
+ driven_signals.add(sigmap(wire));
+ if (wire->port_output)
+ used_signals.add(sigmap(wire));
+ all_signals.add(sigmap(wire));
}
all_signals.del(driven_signals);
RTLIL::SigSpec undriven_signals = all_signals.export_all();
- for (auto &c : undriven_signals.chunks)
+ for (auto &c : undriven_signals.chunks())
{
RTLIL::SigSpec sig = c;
if (c.wire->name[0] == '$')
sig = used_signals.extract(sig);
- if (sig.width == 0)
+ if (sig.size() == 0)
continue;
log("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c));
- module->connections.push_back(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width)));
- OPT_DID_SOMETHING = true;
+ module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width)));
+ did_something = true;
}
}
-void replace_cell(RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
+static void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
{
- RTLIL::SigSpec Y = cell->connections[out_port];
+ RTLIL::SigSpec Y = cell->getPort(out_port);
+ out_val.extend_u0(Y.size(), false);
+
log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
cell->type.c_str(), cell->name.c_str(), info.c_str(),
module->name.c_str(), log_signal(Y), log_signal(out_val));
- // ILANG_BACKEND::dump_cell(stderr, "--> ", cell);
- module->connections.push_back(RTLIL::SigSig(Y, out_val));
- module->cells.erase(cell->name);
- delete cell;
- OPT_DID_SOMETHING = true;
+ // log_cell(cell);
+ assign_map.add(Y, out_val);
+ module->connect(Y, out_val);
+ module->remove(cell);
did_something = true;
}
-void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool)
+static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap)
+{
+ std::string b_name = cell->hasPort("\\B") ? "\\B" : "\\A";
+
+ bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool();
+ bool b_signed = cell->parameters.at(b_name + "_SIGNED").as_bool();
+
+ RTLIL::SigSpec sig_a = sigmap(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = sigmap(cell->getPort(b_name));
+ RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
+
+ sig_a.extend_u0(sig_y.size(), a_signed);
+ sig_b.extend_u0(sig_y.size(), b_signed);
+
+ std::vector<RTLIL::SigBit> bits_a = sig_a, bits_b = sig_b, bits_y = sig_y;
+
+ enum { GRP_DYN, GRP_CONST_A, GRP_CONST_B, GRP_CONST_AB, GRP_N };
+ std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>, std::set<RTLIL::SigBit>> grouped_bits[GRP_N];
+
+ for (int i = 0; i < SIZE(bits_y); i++)
+ {
+ int group_idx = GRP_DYN;
+ RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i];
+
+ if (cell->type == "$or" && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1))
+ bit_a = bit_b = RTLIL::State::S1;
+
+ if (cell->type == "$and" && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0))
+ bit_a = bit_b = RTLIL::State::S0;
+
+ if (bit_a.wire == NULL && bit_b.wire == NULL)
+ group_idx = GRP_CONST_AB;
+ else if (bit_a.wire == NULL)
+ group_idx = GRP_CONST_A;
+ else if (bit_b.wire == NULL && commutative)
+ group_idx = GRP_CONST_A, std::swap(bit_a, bit_b);
+ else if (bit_b.wire == NULL)
+ group_idx = GRP_CONST_B;
+
+ grouped_bits[group_idx][std::pair<RTLIL::SigBit, RTLIL::SigBit>(bit_a, bit_b)].insert(bits_y[i]);
+ }
+
+ for (int i = 0; i < GRP_N; i++)
+ if (SIZE(grouped_bits[i]) == SIZE(bits_y))
+ return false;
+
+ log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
+ log_id(cell->type), log_id(cell), log_id(module));
+
+ for (int i = 0; i < GRP_N; i++)
+ {
+ if (grouped_bits[i].empty())
+ continue;
+
+ RTLIL::Wire *new_y = module->addWire(NEW_ID, SIZE(grouped_bits[i]));
+ RTLIL::SigSpec new_a, new_b;
+ RTLIL::SigSig new_conn;
+
+ for (auto &it : grouped_bits[i]) {
+ for (auto &bit : it.second) {
+ new_conn.first.append_bit(bit);
+ new_conn.second.append_bit(RTLIL::SigBit(new_y, new_a.size()));
+ }
+ new_a.append_bit(it.first.first);
+ new_b.append_bit(it.first.second);
+ }
+
+ RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
+
+ c->setPort("\\A", new_a);
+ c->parameters["\\A_WIDTH"] = new_a.size();
+ c->parameters["\\A_SIGNED"] = false;
+
+ if (b_name == "\\B") {
+ c->setPort("\\B", new_b);
+ c->parameters["\\B_WIDTH"] = new_b.size();
+ c->parameters["\\B_SIGNED"] = false;
+ }
+
+ c->setPort("\\Y", new_y);
+ c->parameters["\\Y_WIDTH"] = new_y->width;
+ c->check();
+
+ module->connect(new_conn);
+
+ log(" New cell `%s': A=%s", log_id(c), log_signal(new_a));
+ if (b_name == "\\B")
+ log(", B=%s", log_signal(new_b));
+ log("\n");
+ }
+
+ cover_list("opt.opt_const.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str());
+
+ module->remove(cell);
+ did_something = true;
+ return true;
+}
+
+static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc)
{
if (!design->selected(module))
return;
+ CellTypes ct_combinational;
+ ct_combinational.setup_internals();
+ ct_combinational.setup_stdcells();
+
SigMap assign_map(module);
std::map<RTLIL::SigSpec, RTLIL::SigSpec> invert_map;
- std::vector<RTLIL::Cell*> cells;
- cells.reserve(module->cells.size());
- for (auto &cell_it : module->cells)
- if (design->selected(module, cell_it.second)) {
- if ((cell_it.second->type == "$_INV_" || cell_it.second->type == "$not" || cell_it.second->type == "$logic_not") &&
- cell_it.second->connections["\\A"].width == 1 && cell_it.second->connections["\\Y"].width == 1)
- invert_map[assign_map(cell_it.second->connections["\\Y"])] = assign_map(cell_it.second->connections["\\A"]);
- cells.push_back(cell_it.second);
+ TopoSort<RTLIL::Cell*> cells;
+ std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit;
+ std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell;
+
+ for (auto cell : module->cells())
+ if (design->selected(module, cell) && cell->type[0] == '$') {
+ if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") &&
+ cell->getPort("\\A").size() == 1 && cell->getPort("\\Y").size() == 1)
+ invert_map[assign_map(cell->getPort("\\Y"))] = assign_map(cell->getPort("\\A"));
+ if (ct_combinational.cell_known(cell->type))
+ for (auto &conn : cell->connections()) {
+ RTLIL::SigSpec sig = assign_map(conn.second);
+ sig.remove_const();
+ if (ct_combinational.cell_input(cell->type, conn.first))
+ cell_to_inbit[cell].insert(sig.begin(), sig.end());
+ if (ct_combinational.cell_output(cell->type, conn.first))
+ for (auto &bit : sig)
+ outbit_to_cell[bit].insert(cell);
+ }
+ cells.node(cell);
}
- for (auto cell : cells)
+ for (auto &it_right : cell_to_inbit)
+ for (auto &it_sigbit : it_right.second)
+ for (auto &it_left : outbit_to_cell[it_sigbit])
+ cells.edge(it_left, it_right.first);
+
+ cells.sort();
+
+ for (auto cell : cells.sorted)
{
-#define ACTION_DO(_p_, _s_) do { replace_cell(module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
+#define ACTION_DO(_p_, _s_) do { cover("opt.opt_const.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
#define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
- if ((cell->type == "$_INV_" || cell->type == "$not" || cell->type == "$logic_not") &&
- invert_map.count(assign_map(cell->connections["\\A"])) != 0) {
- replace_cell(module, cell, "double_invert", "\\Y", invert_map.at(assign_map(cell->connections["\\A"])));
+ if (do_fine)
+ {
+ if (cell->type == "$not" || cell->type == "$pos" ||
+ cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor")
+ if (group_cell_inputs(module, cell, true, assign_map))
+ goto next_cell;
+
+ if (cell->type == "$reduce_and")
+ {
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+
+ RTLIL::State new_a = RTLIL::State::S1;
+ for (auto &bit : sig_a.to_sigbit_vector())
+ if (bit == RTLIL::State::Sx) {
+ if (new_a == RTLIL::State::S1)
+ new_a = RTLIL::State::Sx;
+ } else if (bit == RTLIL::State::S0) {
+ new_a = RTLIL::State::S0;
+ break;
+ } else if (bit.wire != NULL) {
+ new_a = RTLIL::State::Sm;
+ }
+
+ if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
+ cover("opt.opt_const.fine.$reduce_and");
+ log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
+ cell->setPort("\\A", sig_a = new_a);
+ cell->parameters.at("\\A_WIDTH") = 1;
+ did_something = true;
+ }
+ }
+
+ if (cell->type == "$logic_not" || cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$reduce_or" || cell->type == "$reduce_bool")
+ {
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+
+ RTLIL::State new_a = RTLIL::State::S0;
+ for (auto &bit : sig_a.to_sigbit_vector())
+ if (bit == RTLIL::State::Sx) {
+ if (new_a == RTLIL::State::S0)
+ new_a = RTLIL::State::Sx;
+ } else if (bit == RTLIL::State::S1) {
+ new_a = RTLIL::State::S1;
+ break;
+ } else if (bit.wire != NULL) {
+ new_a = RTLIL::State::Sm;
+ }
+
+ if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
+ cover_list("opt.opt_const.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str());
+ log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
+ cell->setPort("\\A", sig_a = new_a);
+ cell->parameters.at("\\A_WIDTH") = 1;
+ did_something = true;
+ }
+ }
+
+ if (cell->type == "$logic_and" || cell->type == "$logic_or")
+ {
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+
+ RTLIL::State new_b = RTLIL::State::S0;
+ for (auto &bit : sig_b.to_sigbit_vector())
+ if (bit == RTLIL::State::Sx) {
+ if (new_b == RTLIL::State::S0)
+ new_b = RTLIL::State::Sx;
+ } else if (bit == RTLIL::State::S1) {
+ new_b = RTLIL::State::S1;
+ break;
+ } else if (bit.wire != NULL) {
+ new_b = RTLIL::State::Sm;
+ }
+
+ if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) {
+ cover_list("opt.opt_const.fine.B", "$logic_and", "$logic_or", cell->type.str());
+ log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b));
+ cell->setPort("\\B", sig_b = new_b);
+ cell->parameters.at("\\B_WIDTH") = 1;
+ did_something = true;
+ }
+ }
+ }
+
+ if (cell->type == "$logic_or" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S1 || assign_map(cell->getPort("\\B")) == RTLIL::State::S1)) {
+ cover("opt.opt_const.one_high");
+ replace_cell(assign_map, module, cell, "one high", "\\Y", RTLIL::State::S1);
goto next_cell;
}
- if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->connections["\\S"])) != 0) {
- RTLIL::SigSpec tmp = cell->connections["\\A"];
- cell->connections["\\A"] = cell->connections["\\B"];
- cell->connections["\\B"] = tmp;
- cell->connections["\\S"] = invert_map.at(assign_map(cell->connections["\\S"]));
- OPT_DID_SOMETHING = true;
+ if (cell->type == "$logic_and" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S0 || assign_map(cell->getPort("\\B")) == RTLIL::State::S0)) {
+ cover("opt.opt_const.one_low");
+ replace_cell(assign_map, module, cell, "one low", "\\Y", RTLIL::State::S0);
+ goto next_cell;
+ }
+
+ if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || cell->type == "$shift" || cell->type == "$shiftx" ||
+ cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" ||
+ cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt" ||
+ cell->type == "$neg" || cell->type == "$add" || cell->type == "$sub" ||
+ cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod" || cell->type == "$pow")
+ {
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = cell->hasPort("\\B") ? assign_map(cell->getPort("\\B")) : RTLIL::SigSpec();
+
+ if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx")
+ sig_a = RTLIL::SigSpec();
+
+ for (auto &bit : sig_a.to_sigbit_vector())
+ if (bit == RTLIL::State::Sx)
+ goto found_the_x_bit;
+
+ for (auto &bit : sig_b.to_sigbit_vector())
+ if (bit == RTLIL::State::Sx)
+ goto found_the_x_bit;
+
+ if (0) {
+ found_the_x_bit:
+ cover_list("opt.opt_const.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
+ "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str());
+ if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" ||
+ cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt")
+ replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::State::Sx);
+ else
+ replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::SigSpec(RTLIL::State::Sx, cell->getPort("\\Y").size()));
+ goto next_cell;
+ }
+ }
+
+ if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") && cell->getPort("\\Y").size() == 1 &&
+ invert_map.count(assign_map(cell->getPort("\\A"))) != 0) {
+ cover_list("opt.opt_const.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str());
+ replace_cell(assign_map, module, cell, "double_invert", "\\Y", invert_map.at(assign_map(cell->getPort("\\A"))));
+ goto next_cell;
+ }
+
+ if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) {
+ cover_list("opt.opt_const.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
+ log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module));
+ RTLIL::SigSpec tmp = cell->getPort("\\A");
+ cell->setPort("\\A", cell->getPort("\\B"));
+ cell->setPort("\\B", tmp);
+ cell->setPort("\\S", invert_map.at(assign_map(cell->getPort("\\S"))));
did_something = true;
goto next_cell;
}
- if (cell->type == "$_INV_") {
- RTLIL::SigSpec input = cell->connections["\\A"];
+ if (cell->type == "$_NOT_") {
+ RTLIL::SigSpec input = cell->getPort("\\A");
assign_map.apply(input);
if (input.match("1")) ACTION_DO_Y(0);
if (input.match("0")) ACTION_DO_Y(1);
@@ -134,8 +388,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type == "$_AND_") {
RTLIL::SigSpec input;
- input.append(cell->connections["\\B"]);
- input.append(cell->connections["\\A"]);
+ input.append(cell->getPort("\\B"));
+ input.append(cell->getPort("\\A"));
assign_map.apply(input);
if (input.match(" 0")) ACTION_DO_Y(0);
if (input.match("0 ")) ACTION_DO_Y(0);
@@ -153,8 +407,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type == "$_OR_") {
RTLIL::SigSpec input;
- input.append(cell->connections["\\B"]);
- input.append(cell->connections["\\A"]);
+ input.append(cell->getPort("\\B"));
+ input.append(cell->getPort("\\A"));
assign_map.apply(input);
if (input.match(" 1")) ACTION_DO_Y(1);
if (input.match("1 ")) ACTION_DO_Y(1);
@@ -172,8 +426,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type == "$_XOR_") {
RTLIL::SigSpec input;
- input.append(cell->connections["\\B"]);
- input.append(cell->connections["\\A"]);
+ input.append(cell->getPort("\\B"));
+ input.append(cell->getPort("\\A"));
assign_map.apply(input);
if (input.match("00")) ACTION_DO_Y(0);
if (input.match("01")) ACTION_DO_Y(1);
@@ -187,9 +441,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type == "$_MUX_") {
RTLIL::SigSpec input;
- input.append(cell->connections["\\S"]);
- input.append(cell->connections["\\B"]);
- input.append(cell->connections["\\A"]);
+ input.append(cell->getPort("\\S"));
+ input.append(cell->getPort("\\B"));
+ input.append(cell->getPort("\\A"));
assign_map.apply(input);
if (input.extract(2, 1) == input.extract(1, 1))
ACTION_DO("\\Y", input.extract(2, 1));
@@ -197,10 +451,11 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1));
if (input.match("01 ")) ACTION_DO("\\Y", input.extract(0, 1));
if (input.match("10 ")) {
- cell->type = "$_INV_";
- cell->connections["\\A"] = input.extract(0, 1);
- cell->connections.erase("\\B");
- cell->connections.erase("\\S");
+ cover("opt.opt_const.mux_to_inv");
+ cell->type = "$_NOT_";
+ cell->setPort("\\A", input.extract(0, 1));
+ cell->unsetPort("\\B");
+ cell->unsetPort("\\S");
goto next_cell;
}
if (input.match("11 ")) ACTION_DO_Y(1);
@@ -217,8 +472,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex")
{
- RTLIL::SigSpec a = cell->connections["\\A"];
- RTLIL::SigSpec b = cell->connections["\\B"];
+ RTLIL::SigSpec a = cell->getPort("\\A");
+ RTLIL::SigSpec b = cell->getPort("\\B");
if (cell->parameters["\\A_WIDTH"].as_int() != cell->parameters["\\B_WIDTH"].as_int()) {
int width = std::max(cell->parameters["\\A_WIDTH"].as_int(), cell->parameters["\\B_WIDTH"].as_int());
@@ -227,78 +482,189 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
RTLIL::SigSpec new_a, new_b;
- a.expand(), b.expand();
- assert(a.chunks.size() == b.chunks.size());
- for (size_t i = 0; i < a.chunks.size(); i++) {
- if (a.chunks[i].wire == NULL && b.chunks[i].wire == NULL && a.chunks[i].data.bits[0] != b.chunks[i].data.bits[0] &&
- a.chunks[i].data.bits[0] <= RTLIL::State::S1 && b.chunks[i].data.bits[0] <= RTLIL::State::S1) {
+ log_assert(SIZE(a) == SIZE(b));
+ for (int i = 0; i < SIZE(a); i++) {
+ if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) {
+ cover_list("opt.opt_const.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S0 : RTLIL::State::S1);
new_y.extend(cell->parameters["\\Y_WIDTH"].as_int(), false);
- replace_cell(module, cell, "empty", "\\Y", new_y);
+ replace_cell(assign_map, module, cell, "isneq", "\\Y", new_y);
goto next_cell;
}
- if (a.chunks[i] == b.chunks[i])
+ if (a[i] == b[i])
continue;
- new_a.append(a.chunks[i]);
- new_b.append(b.chunks[i]);
+ new_a.append(a[i]);
+ new_b.append(b[i]);
}
- if (new_a.width == 0) {
+ if (new_a.size() == 0) {
+ cover_list("opt.opt_const.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S1 : RTLIL::State::S0);
new_y.extend(cell->parameters["\\Y_WIDTH"].as_int(), false);
- replace_cell(module, cell, "empty", "\\Y", new_y);
+ replace_cell(assign_map, module, cell, "empty", "\\Y", new_y);
goto next_cell;
}
- if (new_a.width < a.width || new_b.width < b.width) {
- new_a.optimize();
- new_b.optimize();
- cell->connections["\\A"] = new_a;
- cell->connections["\\B"] = new_b;
- cell->parameters["\\A_WIDTH"] = new_a.width;
- cell->parameters["\\B_WIDTH"] = new_b.width;
+ if (new_a.size() < a.size() || new_b.size() < b.size()) {
+ cover_list("opt.opt_const.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
+ cell->setPort("\\A", new_a);
+ cell->setPort("\\B", new_b);
+ cell->parameters["\\A_WIDTH"] = new_a.size();
+ cell->parameters["\\B_WIDTH"] = new_b.size();
}
}
if ((cell->type == "$eq" || cell->type == "$ne") && cell->parameters["\\Y_WIDTH"].as_int() == 1 &&
cell->parameters["\\A_WIDTH"].as_int() == 1 && cell->parameters["\\B_WIDTH"].as_int() == 1)
{
- RTLIL::SigSpec a = assign_map(cell->connections["\\A"]);
- RTLIL::SigSpec b = assign_map(cell->connections["\\B"]);
+ RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
if (a.is_fully_const()) {
- RTLIL::SigSpec tmp;
- tmp = a, a = b, b = tmp;
- cell->connections["\\A"] = a;
- cell->connections["\\B"] = b;
+ cover_list("opt.opt_const.eqneq.swapconst", "$eq", "$ne", cell->type.str());
+ RTLIL::SigSpec tmp = cell->getPort("\\A");
+ cell->setPort("\\A", cell->getPort("\\B"));
+ cell->setPort("\\B", tmp);
}
if (b.is_fully_const()) {
if (b.as_bool() == (cell->type == "$eq")) {
RTLIL::SigSpec input = b;
- ACTION_DO("\\Y", cell->connections["\\A"]);
+ ACTION_DO("\\Y", cell->getPort("\\A"));
} else {
+ cover_list("opt.opt_const.eqneq.isnot", "$eq", "$ne", cell->type.str());
+ log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->type = "$not";
cell->parameters.erase("\\B_WIDTH");
cell->parameters.erase("\\B_SIGNED");
- cell->connections.erase("\\B");
+ cell->unsetPort("\\B");
+ did_something = true;
+ }
+ goto next_cell;
+ }
+ }
+
+ if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx") && assign_map(cell->getPort("\\B")).is_fully_const())
+ {
+ bool sign_ext = cell->type == "$sshr" && cell->getParam("\\A_SIGNED").as_bool();
+ int shift_bits = assign_map(cell->getPort("\\B")).as_int(cell->type.in("$shift", "$shiftx") && cell->getParam("\\B_SIGNED").as_bool());
+
+ if (cell->type.in("$shl", "$sshl"))
+ shift_bits *= -1;
+
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_y(cell->type == "$shiftx" ? RTLIL::State::Sx : RTLIL::State::S0, cell->getParam("\\Y_WIDTH").as_int());
+
+ if (SIZE(sig_a) < SIZE(sig_y))
+ sig_a.extend(SIZE(sig_y), cell->getParam("\\A_SIGNED").as_bool());
+
+ for (int i = 0; i < SIZE(sig_y); i++) {
+ int idx = i + shift_bits;
+ if (0 <= idx && idx < SIZE(sig_a))
+ sig_y[i] = sig_a[idx];
+ else if (SIZE(sig_a) <= idx && sign_ext)
+ sig_y[i] = sig_a[SIZE(sig_a)-1];
+ }
+
+ cover_list("opt.opt_const.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
+
+ log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
+ log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y));
+
+ module->connect(cell->getPort("\\Y"), sig_y);
+ module->remove(cell);
+
+ did_something = true;
+ goto next_cell;
+ }
+
+ if (!keepdc)
+ {
+ bool identity_wrt_a = false;
+ bool identity_wrt_b = false;
+
+ if (cell->type == "$add" || cell->type == "$sub" || cell->type == "$or" || cell->type == "$xor")
+ {
+ RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
+
+ if (cell->type != "$sub" && a.is_fully_const() && a.as_bool() == false)
+ identity_wrt_b = true;
+
+ if (b.is_fully_const() && b.as_bool() == false)
+ identity_wrt_a = true;
+ }
+
+ if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx")
+ {
+ RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
+
+ if (b.is_fully_const() && b.as_bool() == false)
+ identity_wrt_a = true;
+ }
+
+ if (cell->type == "$mul")
+ {
+ RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
+
+ if (a.is_fully_const() && a.size() <= 32 && a.as_int() == 1)
+ identity_wrt_b = true;
+
+ if (b.is_fully_const() && b.size() <= 32 && b.as_int() == 1)
+ identity_wrt_a = true;
+ }
+
+ if (cell->type == "$div")
+ {
+ RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
+
+ if (b.is_fully_const() && b.size() <= 32 && b.as_int() == 1)
+ identity_wrt_a = true;
+ }
+
+ if (identity_wrt_a || identity_wrt_b)
+ {
+ if (identity_wrt_a)
+ cover_list("opt.opt_const.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
+ if (identity_wrt_b)
+ cover_list("opt.opt_const.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
+
+ log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B');
+
+ if (!identity_wrt_a) {
+ cell->setPort("\\A", cell->getPort("\\B"));
+ cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH");
+ cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED");
}
+
+ cell->type = "$pos";
+ cell->unsetPort("\\B");
+ cell->parameters.erase("\\B_WIDTH");
+ cell->parameters.erase("\\B_SIGNED");
+ cell->check();
+
+ did_something = true;
goto next_cell;
}
}
if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
- cell->connections["\\A"] == RTLIL::SigSpec(0, 1) && cell->connections["\\B"] == RTLIL::SigSpec(1, 1)) {
- replace_cell(module, cell, "mux_bool", "\\Y", cell->connections["\\S"]);
+ cell->getPort("\\A") == RTLIL::SigSpec(0, 1) && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
+ cover_list("opt.opt_const.mux_bool", "$mux", "$_MUX_", cell->type.str());
+ replace_cell(assign_map, module, cell, "mux_bool", "\\Y", cell->getPort("\\S"));
goto next_cell;
}
if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
- cell->connections["\\A"] == RTLIL::SigSpec(1, 1) && cell->connections["\\B"] == RTLIL::SigSpec(0, 1)) {
- cell->connections["\\A"] = cell->connections["\\S"];
- cell->connections.erase("\\B");
- cell->connections.erase("\\S");
+ cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) {
+ cover_list("opt.opt_const.mux_invert", "$mux", "$_MUX_", cell->type.str());
+ log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
+ cell->setPort("\\A", cell->getPort("\\S"));
+ cell->unsetPort("\\B");
+ cell->unsetPort("\\S");
if (cell->type == "$mux") {
cell->parameters["\\A_WIDTH"] = cell->parameters["\\WIDTH"];
cell->parameters["\\Y_WIDTH"] = cell->parameters["\\WIDTH"];
@@ -306,15 +672,16 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cell->parameters.erase("\\WIDTH");
cell->type = "$not";
} else
- cell->type = "$_INV_";
- OPT_DID_SOMETHING = true;
+ cell->type = "$_NOT_";
did_something = true;
goto next_cell;
}
- if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->connections["\\A"] == RTLIL::SigSpec(0, 1)) {
- cell->connections["\\A"] = cell->connections["\\S"];
- cell->connections.erase("\\S");
+ if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) {
+ cover_list("opt.opt_const.mux_and", "$mux", "$_MUX_", cell->type.str());
+ log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
+ cell->setPort("\\A", cell->getPort("\\S"));
+ cell->unsetPort("\\S");
if (cell->type == "$mux") {
cell->parameters["\\A_WIDTH"] = cell->parameters["\\WIDTH"];
cell->parameters["\\B_WIDTH"] = cell->parameters["\\WIDTH"];
@@ -325,14 +692,15 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cell->type = "$and";
} else
cell->type = "$_AND_";
- OPT_DID_SOMETHING = true;
did_something = true;
goto next_cell;
}
- if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->connections["\\B"] == RTLIL::SigSpec(1, 1)) {
- cell->connections["\\B"] = cell->connections["\\S"];
- cell->connections.erase("\\S");
+ if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
+ cover_list("opt.opt_const.mux_or", "$mux", "$_MUX_", cell->type.str());
+ log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
+ cell->setPort("\\B", cell->getPort("\\S"));
+ cell->unsetPort("\\S");
if (cell->type == "$mux") {
cell->parameters["\\A_WIDTH"] = cell->parameters["\\WIDTH"];
cell->parameters["\\B_WIDTH"] = cell->parameters["\\WIDTH"];
@@ -342,87 +710,88 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cell->parameters.erase("\\WIDTH");
cell->type = "$or";
} else
- cell->type = "$_or_";
- OPT_DID_SOMETHING = true;
+ cell->type = "$_OR_";
did_something = true;
goto next_cell;
}
if (mux_undef && (cell->type == "$mux" || cell->type == "$pmux")) {
RTLIL::SigSpec new_a, new_b, new_s;
- int width = cell->connections.at("\\A").width;
- if ((cell->connections.at("\\A").is_fully_undef() && cell->connections.at("\\B").is_fully_undef()) ||
- cell->connections.at("\\S").is_fully_undef()) {
- replace_cell(module, cell, "mux undef", "\\Y", cell->connections.at("\\A"));
+ int width = cell->getPort("\\A").size();
+ if ((cell->getPort("\\A").is_fully_undef() && cell->getPort("\\B").is_fully_undef()) ||
+ cell->getPort("\\S").is_fully_undef()) {
+ cover_list("opt.opt_const.mux_undef", "$mux", "$pmux", cell->type.str());
+ replace_cell(assign_map, module, cell, "mux_undef", "\\Y", cell->getPort("\\A"));
goto next_cell;
}
- for (int i = 0; i < cell->connections.at("\\S").width; i++) {
- RTLIL::SigSpec old_b = cell->connections.at("\\B").extract(i*width, width);
- RTLIL::SigSpec old_s = cell->connections.at("\\S").extract(i, 1);
+ for (int i = 0; i < cell->getPort("\\S").size(); i++) {
+ RTLIL::SigSpec old_b = cell->getPort("\\B").extract(i*width, width);
+ RTLIL::SigSpec old_s = cell->getPort("\\S").extract(i, 1);
if (old_b.is_fully_undef() || old_s.is_fully_undef())
continue;
new_b.append(old_b);
new_s.append(old_s);
}
- new_a = cell->connections.at("\\A");
- if (new_a.is_fully_undef() && new_s.width > 0) {
- new_a = new_b.extract((new_s.width-1)*width, width);
- new_b = new_b.extract(0, (new_s.width-1)*width);
- new_s = new_s.extract(0, new_s.width-1);
+ new_a = cell->getPort("\\A");
+ if (new_a.is_fully_undef() && new_s.size() > 0) {
+ new_a = new_b.extract((new_s.size()-1)*width, width);
+ new_b = new_b.extract(0, (new_s.size()-1)*width);
+ new_s = new_s.extract(0, new_s.size()-1);
}
- if (new_s.width == 0) {
- replace_cell(module, cell, "mux undef", "\\Y", new_a);
+ if (new_s.size() == 0) {
+ cover_list("opt.opt_const.mux_empty", "$mux", "$pmux", cell->type.str());
+ replace_cell(assign_map, module, cell, "mux_empty", "\\Y", new_a);
goto next_cell;
}
if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) {
- replace_cell(module, cell, "mux undef", "\\Y", new_s);
+ cover_list("opt.opt_const.mux_sel01", "$mux", "$pmux", cell->type.str());
+ replace_cell(assign_map, module, cell, "mux_sel01", "\\Y", new_s);
goto next_cell;
}
- if (cell->connections.at("\\S").width != new_s.width) {
- cell->connections.at("\\A") = new_a;
- cell->connections.at("\\B") = new_b;
- cell->connections.at("\\S") = new_s;
- if (new_s.width > 1) {
+ if (cell->getPort("\\S").size() != new_s.size()) {
+ cover_list("opt.opt_const.mux_reduce", "$mux", "$pmux", cell->type.str());
+ log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
+ SIZE(cell->getPort("\\S")) - SIZE(new_s), log_id(cell->type), log_id(cell), log_id(module));
+ cell->setPort("\\A", new_a);
+ cell->setPort("\\B", new_b);
+ cell->setPort("\\S", new_s);
+ if (new_s.size() > 1) {
cell->type = "$pmux";
- cell->parameters["\\S_WIDTH"] = new_s.width;
+ cell->parameters["\\S_WIDTH"] = new_s.size();
} else {
cell->type = "$mux";
cell->parameters.erase("\\S_WIDTH");
}
- OPT_DID_SOMETHING = true;
did_something = true;
}
}
#define FOLD_1ARG_CELL(_t) \
if (cell->type == "$" #_t) { \
- RTLIL::SigSpec a = cell->connections["\\A"]; \
+ RTLIL::SigSpec a = cell->getPort("\\A"); \
assign_map.apply(a); \
if (a.is_fully_const()) { \
- a.optimize(); \
- if (a.chunks.empty()) a.chunks.push_back(RTLIL::SigChunk()); \
RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \
- RTLIL::SigSpec y(RTLIL::const_ ## _t(a.chunks[0].data, dummy_arg, \
+ RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
cell->parameters["\\A_SIGNED"].as_bool(), false, \
cell->parameters["\\Y_WIDTH"].as_int())); \
- replace_cell(module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
+ cover("opt.opt_const.const.$" #_t); \
+ replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
goto next_cell; \
} \
}
#define FOLD_2ARG_CELL(_t) \
if (cell->type == "$" #_t) { \
- RTLIL::SigSpec a = cell->connections["\\A"]; \
- RTLIL::SigSpec b = cell->connections["\\B"]; \
+ RTLIL::SigSpec a = cell->getPort("\\A"); \
+ RTLIL::SigSpec b = cell->getPort("\\B"); \
assign_map.apply(a), assign_map.apply(b); \
if (a.is_fully_const() && b.is_fully_const()) { \
- a.optimize(), b.optimize(); \
- if (a.chunks.empty()) a.chunks.push_back(RTLIL::SigChunk()); \
- if (b.chunks.empty()) b.chunks.push_back(RTLIL::SigChunk()); \
- RTLIL::SigSpec y(RTLIL::const_ ## _t(a.chunks[0].data, b.chunks[0].data, \
+ RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \
cell->parameters["\\A_SIGNED"].as_bool(), \
cell->parameters["\\B_SIGNED"].as_bool(), \
cell->parameters["\\Y_WIDTH"].as_int())); \
- replace_cell(module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
+ cover("opt.opt_const.const.$" #_t); \
+ replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
goto next_cell; \
} \
}
@@ -447,6 +816,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
FOLD_2ARG_CELL(shr)
FOLD_2ARG_CELL(sshl)
FOLD_2ARG_CELL(sshr)
+ FOLD_2ARG_CELL(shift)
+ FOLD_2ARG_CELL(shiftx)
FOLD_2ARG_CELL(lt)
FOLD_2ARG_CELL(le)
@@ -467,13 +838,78 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
// be very conservative with optimizing $mux cells as we do not want to break mux trees
if (cell->type == "$mux") {
- RTLIL::SigSpec input = assign_map(cell->connections["\\S"]);
- RTLIL::SigSpec inA = assign_map(cell->connections["\\A"]);
- RTLIL::SigSpec inB = assign_map(cell->connections["\\B"]);
+ RTLIL::SigSpec input = assign_map(cell->getPort("\\S"));
+ RTLIL::SigSpec inA = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec inB = assign_map(cell->getPort("\\B"));
if (input.is_fully_const())
- ACTION_DO("\\Y", input.as_bool() ? cell->connections["\\B"] : cell->connections["\\A"]);
+ ACTION_DO("\\Y", input.as_bool() ? cell->getPort("\\B") : cell->getPort("\\A"));
else if (inA == inB)
- ACTION_DO("\\Y", cell->connections["\\A"]);
+ ACTION_DO("\\Y", cell->getPort("\\A"));
+ }
+
+ if (!keepdc && cell->type == "$mul")
+ {
+ bool a_signed = cell->parameters["\\A_SIGNED"].as_bool();
+ bool b_signed = cell->parameters["\\B_SIGNED"].as_bool();
+ bool swapped_ab = false;
+
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec sig_y = assign_map(cell->getPort("\\Y"));
+
+ if (sig_b.is_fully_const() && sig_b.size() <= 32)
+ std::swap(sig_a, sig_b), std::swap(a_signed, b_signed), swapped_ab = true;
+
+ if (sig_a.is_fully_def() && sig_a.size() <= 32)
+ {
+ int a_val = sig_a.as_int();
+
+ if (a_val == 0)
+ {
+ cover("opt.opt_const.mul_shift.zero");
+
+ log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
+ cell->name.c_str(), module->name.c_str());
+
+ module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
+ module->remove(cell);
+
+ did_something = true;
+ goto next_cell;
+ }
+
+ for (int i = 1; i < (a_signed ? sig_a.size()-1 : sig_a.size()); i++)
+ if (a_val == (1 << i))
+ {
+ if (swapped_ab)
+ cover("opt.opt_const.mul_shift.swapped");
+ else
+ cover("opt.opt_const.mul_shift.unswapped");
+
+ log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
+ a_val, cell->name.c_str(), module->name.c_str(), i);
+
+ if (!swapped_ab) {
+ cell->setPort("\\A", cell->getPort("\\B"));
+ cell->parameters["\\A_WIDTH"] = cell->parameters["\\B_WIDTH"];
+ cell->parameters["\\A_SIGNED"] = cell->parameters["\\B_SIGNED"];
+ }
+
+ std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
+
+ while (SIZE(new_b) > 1 && new_b.back() == RTLIL::State::S0)
+ new_b.pop_back();
+
+ cell->type = "$shl";
+ cell->parameters["\\B_WIDTH"] = SIZE(new_b);
+ cell->parameters["\\B_SIGNED"] = false;
+ cell->setPort("\\B", new_b);
+ cell->check();
+
+ did_something = true;
+ goto next_cell;
+ }
+ }
}
next_cell:;
@@ -503,12 +939,23 @@ struct OptConstPass : public Pass {
log(" -undriven\n");
log(" replace undriven nets with undef (x) constants\n");
log("\n");
+ log(" -keepdc\n");
+ log(" some optimizations change the behavior of the circuit with respect to\n");
+ log(" don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n");
+ log(" all result bits to be set to x. this behavior changes when 'a+0' is\n");
+ log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
+ log("\n");
+ log(" -fine\n");
+ log(" perform fine-grain optimizations\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
bool mux_undef = false;
bool mux_bool = false;
bool undriven = false;
+ bool do_fine = false;
+ bool keepdc = false;
log_header("Executing OPT_CONST pass (perform const folding).\n");
log_push();
@@ -527,21 +974,31 @@ struct OptConstPass : public Pass {
undriven = true;
continue;
}
+ if (args[argidx] == "-fine") {
+ do_fine = true;
+ continue;
+ }
+ if (args[argidx] == "-keepdc") {
+ keepdc = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
- for (auto &mod_it : design->modules)
+ for (auto module : design->modules())
{
if (undriven)
- replace_undriven(design, mod_it.second);
+ replace_undriven(design, module);
do {
do {
did_something = false;
- replace_const_cells(design, mod_it.second, false, mux_undef, mux_bool);
+ replace_const_cells(design, module, false, mux_undef, mux_bool, do_fine, keepdc);
+ if (did_something)
+ design->scratchpad_set_bool("opt.did_something", true);
} while (did_something);
- replace_const_cells(design, mod_it.second, true, mux_undef, mux_bool);
+ replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc);
} while (did_something);
}
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index 47100869..2c5dcf66 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -17,13 +17,11 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include "kernel/celltypes.h"
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <set>
@@ -36,7 +34,11 @@ struct OptMuxtreeWorker
SigMap assign_map;
int removed_count;
- typedef std::pair<RTLIL::Wire*,int> bitDef_t;
+ struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
+ bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
+ bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
+ };
+
struct bitinfo_t {
int num;
@@ -79,21 +81,20 @@ struct OptMuxtreeWorker
// .ctrl_sigs
// .input_sigs
// .const_activated
- for (auto &cell_it : module->cells)
+ for (auto cell : module->cells())
{
- RTLIL::Cell *cell = cell_it.second;
- if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux")
+ if (cell->type == "$mux" || cell->type == "$pmux")
{
- RTLIL::SigSpec sig_a = cell->connections["\\A"];
- RTLIL::SigSpec sig_b = cell->connections["\\B"];
- RTLIL::SigSpec sig_s = cell->connections["\\S"];
- RTLIL::SigSpec sig_y = cell->connections["\\Y"];
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_s = cell->getPort("\\S");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
muxinfo_t muxinfo;
muxinfo.cell = cell;
- for (int i = 0; i < sig_s.width; i++) {
- RTLIL::SigSpec sig = sig_b.extract(i*sig_a.width, sig_a.width);
+ for (int i = 0; i < sig_s.size(); i++) {
+ RTLIL::SigSpec sig = sig_b.extract(i*sig_a.size(), sig_a.size());
RTLIL::SigSpec ctrl_sig = assign_map(sig_s.extract(i, 1));
portinfo_t portinfo;
for (int idx : sig2bits(sig)) {
@@ -126,15 +127,15 @@ struct OptMuxtreeWorker
}
else
{
- for (auto &it : cell->connections) {
+ for (auto &it : cell->connections()) {
for (int idx : sig2bits(it.second))
bit2info[idx].seen_non_mux = true;
}
}
}
- for (auto &it : module->wires) {
- if (it.second->port_output)
- for (int idx : sig2bits(RTLIL::SigSpec(it.second)))
+ for (auto wire : module->wires()) {
+ if (wire->port_output)
+ for (int idx : sig2bits(RTLIL::SigSpec(wire)))
bit2info[idx].seen_non_mux = true;
}
@@ -177,7 +178,6 @@ struct OptMuxtreeWorker
} else {
log(" dead port %zd/%zd on %s %s.\n", port_idx+1, mi.ports.size(),
mi.cell->type.c_str(), mi.cell->name.c_str());
- OPT_DID_SOMETHING = true;
removed_count++;
}
}
@@ -186,32 +186,30 @@ struct OptMuxtreeWorker
continue;
if (live_ports.size() == 0) {
- module->cells.erase(mi.cell->name);
- delete mi.cell;
+ module->remove(mi.cell);
continue;
}
- RTLIL::SigSpec sig_a = mi.cell->connections["\\A"];
- RTLIL::SigSpec sig_b = mi.cell->connections["\\B"];
- RTLIL::SigSpec sig_s = mi.cell->connections["\\S"];
- RTLIL::SigSpec sig_y = mi.cell->connections["\\Y"];
+ RTLIL::SigSpec sig_a = mi.cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = mi.cell->getPort("\\B");
+ RTLIL::SigSpec sig_s = mi.cell->getPort("\\S");
+ RTLIL::SigSpec sig_y = mi.cell->getPort("\\Y");
RTLIL::SigSpec sig_ports = sig_b;
sig_ports.append(sig_a);
if (live_ports.size() == 1)
{
- RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[0]*sig_a.width, sig_a.width);
- module->connections.push_back(RTLIL::SigSig(sig_y, sig_in));
- module->cells.erase(mi.cell->name);
- delete mi.cell;
+ RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[0]*sig_a.size(), sig_a.size());
+ module->connect(RTLIL::SigSig(sig_y, sig_in));
+ module->remove(mi.cell);
}
else
{
RTLIL::SigSpec new_sig_a, new_sig_b, new_sig_s;
for (size_t i = 0; i < live_ports.size(); i++) {
- RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[i]*sig_a.width, sig_a.width);
+ RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[i]*sig_a.size(), sig_a.size());
if (i == live_ports.size()-1) {
new_sig_a = sig_in;
} else {
@@ -220,14 +218,14 @@ struct OptMuxtreeWorker
}
}
- mi.cell->connections["\\A"] = new_sig_a;
- mi.cell->connections["\\B"] = new_sig_b;
- mi.cell->connections["\\S"] = new_sig_s;
- if (new_sig_s.width == 1) {
+ mi.cell->setPort("\\A", new_sig_a);
+ mi.cell->setPort("\\B", new_sig_b);
+ mi.cell->setPort("\\S", new_sig_s);
+ if (new_sig_s.size() == 1) {
mi.cell->type = "$mux";
mi.cell->parameters.erase("\\S_WIDTH");
} else {
- mi.cell->parameters["\\S_WIDTH"] = RTLIL::Const(new_sig_s.width);
+ mi.cell->parameters["\\S_WIDTH"] = RTLIL::Const(new_sig_s.size());
}
}
}
@@ -259,10 +257,8 @@ struct OptMuxtreeWorker
{
std::vector<int> results;
assign_map.apply(sig);
- sig.expand();
- for (auto &c : sig.chunks)
- if (c.wire != NULL) {
- bitDef_t bit(c.wire, c.offset);
+ for (auto &bit : sig)
+ if (bit.wire != NULL) {
if (bit2num.count(bit) == 0) {
bitinfo_t info;
info.num = bit2info.size();
@@ -309,13 +305,17 @@ struct OptMuxtreeWorker
if (port_idx < int(muxinfo.ports.size())-1 && !muxinfo.ports[port_idx].const_activated)
knowledge.known_active.push_back(muxinfo.ports[port_idx].ctrl_sigs);
+ std::vector<int> parent_muxes;
for (int m : muxinfo.ports[port_idx].input_muxes) {
if (knowledge.visited_muxes.count(m) > 0)
continue;
knowledge.visited_muxes.insert(m);
+ parent_muxes.push_back(m);
+ }
+ for (int m : parent_muxes)
eval_mux(knowledge, m);
+ for (int m : parent_muxes)
knowledge.visited_muxes.erase(m);
- }
if (port_idx < int(muxinfo.ports.size())-1 && !muxinfo.ports[port_idx].const_activated)
knowledge.known_active.pop_back();
@@ -393,6 +393,7 @@ struct OptMuxtreeWorker
void eval_root_mux(int mux_idx)
{
knowledge_t knowledge;
+ knowledge.visited_muxes.insert(mux_idx);
eval_mux(knowledge, mux_idx);
}
};
@@ -418,19 +419,21 @@ struct OptMuxtreePass : public Pass {
extra_args(args, 1, design);
int total_count = 0;
- for (auto &mod_it : design->modules) {
- if (!design->selected_whole_module(mod_it.first)) {
- if (design->selected(mod_it.second))
- log("Skipping module %s as it is only partially selected.\n", id2cstr(mod_it.second->name));
+ for (auto mod : design->modules()) {
+ if (!design->selected_whole_module(mod)) {
+ if (design->selected(mod))
+ log("Skipping module %s as it is only partially selected.\n", log_id(mod));
continue;
}
- if (mod_it.second->processes.size() > 0) {
- log("Skipping module %s as it contains processes.\n", id2cstr(mod_it.second->name));
+ if (mod->processes.size() > 0) {
+ log("Skipping module %s as it contains processes.\n", log_id(mod));
} else {
- OptMuxtreeWorker worker(design, mod_it.second);
+ OptMuxtreeWorker worker(design, mod);
total_count += worker.removed_count;
}
}
+ if (total_count)
+ design->scratchpad_set_bool("opt.did_something", true);
log("Removed %d multiplexer ports.\n", total_count);
}
} OptMuxtreePass;
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index dd129981..e9e2bb39 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -17,14 +17,11 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include "kernel/celltypes.h"
-#include "libs/sha1/sha1.h"
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <set>
@@ -43,97 +40,95 @@ struct OptReduceWorker
return;
cells.erase(cell);
- RTLIL::SigSpec sig_a = assign_map(cell->connections["\\A"]);
- sig_a.sort_and_unify();
- sig_a.expand();
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ std::set<RTLIL::SigBit> new_sig_a_bits;
- RTLIL::SigSpec new_sig_a;
- for (auto &chunk : sig_a.chunks)
+ for (auto &bit : sig_a.to_sigbit_set())
{
- if (chunk.wire == NULL && chunk.data.bits[0] == RTLIL::State::S0) {
+ if (bit == RTLIL::State::S0) {
if (cell->type == "$reduce_and") {
- new_sig_a = RTLIL::SigSpec(RTLIL::State::S0);
+ new_sig_a_bits.clear();
+ new_sig_a_bits.insert(RTLIL::State::S0);
break;
}
continue;
}
- if (chunk.wire == NULL && chunk.data.bits[0] == RTLIL::State::S1) {
+ if (bit == RTLIL::State::S1) {
if (cell->type == "$reduce_or") {
- new_sig_a = RTLIL::SigSpec(RTLIL::State::S1);
+ new_sig_a_bits.clear();
+ new_sig_a_bits.insert(RTLIL::State::S1);
break;
}
continue;
}
- if (chunk.wire == NULL) {
- new_sig_a = RTLIL::SigSpec(RTLIL::State::Sx);
- break;
+ if (bit.wire == NULL) {
+ new_sig_a_bits.insert(bit);
+ continue;
}
bool imported_children = false;
- for (auto child_cell : drivers.find(chunk)) {
+ for (auto child_cell : drivers.find(bit)) {
if (child_cell->type == cell->type) {
opt_reduce(cells, drivers, child_cell);
- new_sig_a.append(child_cell->connections["\\A"]);
+ if (child_cell->getPort("\\Y")[0] == bit) {
+ std::set<RTLIL::SigBit> child_sig_a_bits = assign_map(child_cell->getPort("\\A")).to_sigbit_set();
+ new_sig_a_bits.insert(child_sig_a_bits.begin(), child_sig_a_bits.end());
+ } else
+ new_sig_a_bits.insert(RTLIL::State::S0);
imported_children = true;
}
}
if (!imported_children)
- new_sig_a.append(chunk);
+ new_sig_a_bits.insert(bit);
}
- new_sig_a.sort_and_unify();
- if (new_sig_a != sig_a || sig_a.width != cell->connections["\\A"].width) {
+ RTLIL::SigSpec new_sig_a(new_sig_a_bits);
+
+ if (new_sig_a != sig_a || sig_a.size() != cell->getPort("\\A").size()) {
log(" New input vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_a));
did_something = true;
- OPT_DID_SOMETHING = true;
total_count++;
}
- cell->connections["\\A"] = new_sig_a;
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(new_sig_a.width);
+ cell->setPort("\\A", new_sig_a);
+ cell->parameters["\\A_WIDTH"] = RTLIL::Const(new_sig_a.size());
return;
}
void opt_mux(RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = assign_map(cell->connections["\\A"]);
- RTLIL::SigSpec sig_b = assign_map(cell->connections["\\B"]);
- RTLIL::SigSpec sig_s = assign_map(cell->connections["\\S"]);
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec sig_s = assign_map(cell->getPort("\\S"));
RTLIL::SigSpec new_sig_b, new_sig_s;
std::set<RTLIL::SigSpec> handled_sig;
handled_sig.insert(sig_a);
- for (int i = 0; i < sig_s.width; i++)
+ for (int i = 0; i < sig_s.size(); i++)
{
- RTLIL::SigSpec this_b = sig_b.extract(i*sig_a.width, sig_a.width);
+ RTLIL::SigSpec this_b = sig_b.extract(i*sig_a.size(), sig_a.size());
if (handled_sig.count(this_b) > 0)
continue;
RTLIL::SigSpec this_s = sig_s.extract(i, 1);
- for (int j = i+1; j < sig_s.width; j++) {
- RTLIL::SigSpec that_b = sig_b.extract(j*sig_a.width, sig_a.width);
+ for (int j = i+1; j < sig_s.size(); j++) {
+ RTLIL::SigSpec that_b = sig_b.extract(j*sig_a.size(), sig_a.size());
if (this_b == that_b)
this_s.append(sig_s.extract(j, 1));
}
- if (this_s.width > 1)
+ if (this_s.size() > 1)
{
- RTLIL::Wire *reduce_or_wire = new RTLIL::Wire;
- reduce_or_wire->name = NEW_ID;
- module->wires[reduce_or_wire->name] = reduce_or_wire;
-
- RTLIL::Cell *reduce_or_cell = new RTLIL::Cell;
- reduce_or_cell->name = NEW_ID;
- reduce_or_cell->type = "$reduce_or";
- reduce_or_cell->connections["\\A"] = this_s;
+ RTLIL::Cell *reduce_or_cell = module->addCell(NEW_ID, "$reduce_or");
+ reduce_or_cell->setPort("\\A", this_s);
reduce_or_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- reduce_or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(this_s.width);
+ reduce_or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(this_s.size());
reduce_or_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- module->cells[reduce_or_cell->name] = reduce_or_cell;
+ RTLIL::Wire *reduce_or_wire = module->addWire(NEW_ID);
this_s = RTLIL::SigSpec(reduce_or_wire);
- reduce_or_cell->connections["\\Y"] = this_s;
+ reduce_or_cell->setPort("\\Y", this_s);
}
new_sig_b.append(this_b);
@@ -141,26 +136,24 @@ struct OptReduceWorker
handled_sig.insert(this_b);
}
- if (new_sig_s.width != sig_s.width) {
+ if (new_sig_s.size() != sig_s.size()) {
log(" New ctrl vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_s));
did_something = true;
- OPT_DID_SOMETHING = true;
total_count++;
}
- if (new_sig_s.width == 0)
+ if (new_sig_s.size() == 0)
{
- module->connections.push_back(RTLIL::SigSig(cell->connections["\\Y"], cell->connections["\\A"]));
- assign_map.add(cell->connections["\\Y"], cell->connections["\\A"]);
- module->cells.erase(cell->name);
- delete cell;
+ module->connect(RTLIL::SigSig(cell->getPort("\\Y"), cell->getPort("\\A")));
+ assign_map.add(cell->getPort("\\Y"), cell->getPort("\\A"));
+ module->remove(cell);
}
else
{
- cell->connections["\\B"] = new_sig_b;
- cell->connections["\\S"] = new_sig_s;
- if (new_sig_s.width > 1) {
- cell->parameters["\\S_WIDTH"] = RTLIL::Const(new_sig_s.width);
+ cell->setPort("\\B", new_sig_b);
+ cell->setPort("\\S", new_sig_s);
+ if (new_sig_s.size() > 1) {
+ cell->parameters["\\S_WIDTH"] = RTLIL::Const(new_sig_s.size());
} else {
cell->type = "$mux";
cell->parameters.erase("\\S_WIDTH");
@@ -168,7 +161,85 @@ struct OptReduceWorker
}
}
- OptReduceWorker(RTLIL::Design *design, RTLIL::Module *module) :
+ void opt_mux_bits(RTLIL::Cell *cell)
+ {
+ std::vector<RTLIL::SigBit> sig_a = assign_map(cell->getPort("\\A")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_b = assign_map(cell->getPort("\\B")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_y = assign_map(cell->getPort("\\Y")).to_sigbit_vector();
+
+ std::vector<RTLIL::SigBit> new_sig_y;
+ RTLIL::SigSig old_sig_conn;
+
+ std::vector<std::vector<RTLIL::SigBit>> consolidated_in_tuples;
+ std::map<std::vector<RTLIL::SigBit>, RTLIL::SigBit> consolidated_in_tuples_map;
+
+ for (int i = 0; i < int(sig_y.size()); i++)
+ {
+ std::vector<RTLIL::SigBit> in_tuple;
+ bool all_tuple_bits_same = true;
+
+ in_tuple.push_back(sig_a.at(i));
+ for (int j = i; j < int(sig_b.size()); j += int(sig_a.size())) {
+ if (sig_b.at(j) != sig_a.at(i))
+ all_tuple_bits_same = false;
+ in_tuple.push_back(sig_b.at(j));
+ }
+
+ if (all_tuple_bits_same)
+ {
+ old_sig_conn.first.append_bit(sig_y.at(i));
+ old_sig_conn.second.append_bit(sig_a.at(i));
+ }
+ else if (consolidated_in_tuples_map.count(in_tuple))
+ {
+ old_sig_conn.first.append_bit(sig_y.at(i));
+ old_sig_conn.second.append_bit(consolidated_in_tuples_map.at(in_tuple));
+ }
+ else
+ {
+ consolidated_in_tuples_map[in_tuple] = sig_y.at(i);
+ consolidated_in_tuples.push_back(in_tuple);
+ new_sig_y.push_back(sig_y.at(i));
+ }
+ }
+
+ if (new_sig_y.size() != sig_y.size())
+ {
+ log(" Consolidated identical input bits for %s cell %s:\n", cell->type.c_str(), cell->name.c_str());
+ log(" Old ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort("\\A")),
+ log_signal(cell->getPort("\\B")), log_signal(cell->getPort("\\Y")));
+
+ cell->setPort("\\A", RTLIL::SigSpec());
+ for (auto &in_tuple : consolidated_in_tuples) {
+ RTLIL::SigSpec new_a = cell->getPort("\\A");
+ new_a.append(in_tuple.at(0));
+ cell->setPort("\\A", new_a);
+ }
+
+ cell->setPort("\\B", RTLIL::SigSpec());
+ for (int i = 1; i <= cell->getPort("\\S").size(); i++)
+ for (auto &in_tuple : consolidated_in_tuples) {
+ RTLIL::SigSpec new_b = cell->getPort("\\B");
+ new_b.append(in_tuple.at(i));
+ cell->setPort("\\B", new_b);
+ }
+
+ cell->parameters["\\WIDTH"] = RTLIL::Const(new_sig_y.size());
+ cell->setPort("\\Y", new_sig_y);
+
+ log(" New ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort("\\A")),
+ log_signal(cell->getPort("\\B")), log_signal(cell->getPort("\\Y")));
+ log(" New connections: %s = %s\n", log_signal(old_sig_conn.first), log_signal(old_sig_conn.second));
+
+ module->connect(old_sig_conn);
+ module->check();
+
+ did_something = true;
+ total_count++;
+ }
+ }
+
+ OptReduceWorker(RTLIL::Design *design, RTLIL::Module *module, bool do_fine) :
design(design), module(module), assign_map(module)
{
log(" Optimizing cells in module %s.\n", module->name.c_str());
@@ -176,6 +247,35 @@ struct OptReduceWorker
total_count = 0;
did_something = true;
+ SigPool mem_wren_sigs;
+ for (auto &cell_it : module->cells_) {
+ RTLIL::Cell *cell = cell_it.second;
+ if (cell->type == "$mem")
+ mem_wren_sigs.add(assign_map(cell->getPort("\\WR_EN")));
+ if (cell->type == "$memwr")
+ mem_wren_sigs.add(assign_map(cell->getPort("\\EN")));
+ }
+ for (auto &cell_it : module->cells_) {
+ RTLIL::Cell *cell = cell_it.second;
+ if (cell->type == "$dff" && mem_wren_sigs.check_any(assign_map(cell->getPort("\\Q"))))
+ mem_wren_sigs.add(assign_map(cell->getPort("\\D")));
+ }
+
+ bool keep_expanding_mem_wren_sigs = true;
+ while (keep_expanding_mem_wren_sigs) {
+ keep_expanding_mem_wren_sigs = false;
+ for (auto &cell_it : module->cells_) {
+ RTLIL::Cell *cell = cell_it.second;
+ if (cell->type == "$mux" && mem_wren_sigs.check_any(assign_map(cell->getPort("\\Y")))) {
+ if (!mem_wren_sigs.check_all(assign_map(cell->getPort("\\A"))) ||
+ !mem_wren_sigs.check_all(assign_map(cell->getPort("\\B"))))
+ keep_expanding_mem_wren_sigs = true;
+ mem_wren_sigs.add(assign_map(cell->getPort("\\A")));
+ mem_wren_sigs.add(assign_map(cell->getPort("\\B")));
+ }
+ }
+ }
+
while (did_something)
{
did_something = false;
@@ -189,11 +289,11 @@ struct OptReduceWorker
SigSet<RTLIL::Cell*> drivers;
std::set<RTLIL::Cell*> cells;
- for (auto &cell_it : module->cells) {
+ for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
if (cell->type != type || !design->selected(module, cell))
continue;
- drivers.insert(assign_map(cell->connections["\\Y"]), cell);
+ drivers.insert(assign_map(cell->getPort("\\Y")), cell);
cells.insert(cell);
}
@@ -205,11 +305,19 @@ struct OptReduceWorker
// merge identical inputs on $mux and $pmux cells
- for (auto &cell_it : module->cells)
+ std::vector<RTLIL::Cell*> cells;
+
+ for (auto &it : module->cells_)
+ if ((it.second->type == "$mux" || it.second->type == "$pmux") && design->selected(module, it.second))
+ cells.push_back(it.second);
+
+ for (auto cell : cells)
{
- RTLIL::Cell *cell = cell_it.second;
- if ((cell->type != "$mux" && cell->type != "$pmux" && cell->type != "$safe_pmux") || !design->selected(module, cell))
- continue;
+ // this optimization is to aggressive for most coarse-grain applications.
+ // but we always want it for multiplexers driving write enable ports.
+ if (do_fine || mem_wren_sigs.check_any(assign_map(cell->getPort("\\Y"))))
+ opt_mux_bits(cell);
+
opt_mux(cell);
}
}
@@ -222,7 +330,7 @@ struct OptReducePass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" opt_reduce [selection]\n");
+ log(" opt_reduce [options] [selection]\n");
log("\n");
log("This pass performs two interlinked optimizations:\n");
log("\n");
@@ -232,20 +340,40 @@ struct OptReducePass : public Pass {
log("2. it identifies duplicated inputs to MUXes and replaces them with a single\n");
log("input with the original control signals OR'ed together.\n");
log("\n");
+ log(" -fine\n");
+ log(" perform fine-grain optimizations\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
+ bool do_fine = false;
+
log_header("Executing OPT_REDUCE pass (consolidate $*mux and $reduce_* inputs).\n");
- extra_args(args, 1, design);
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-fine") {
+ do_fine = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
int total_count = 0;
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (!design->selected(mod_it.second))
continue;
- OptReduceWorker worker(design, mod_it.second);
- total_count += worker.total_count;
+ do {
+ OptReduceWorker worker(design, mod_it.second, do_fine);
+ total_count += worker.total_count;
+ if (worker.total_count == 0)
+ break;
+ } while (1);
}
+ if (total_count)
+ design->scratchpad_set_bool("opt.did_something", true);
log("Performed a total of %d changes.\n", total_count);
}
} OptReducePass;
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index 9a438537..48f406f6 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -17,7 +17,6 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
@@ -33,34 +32,34 @@ static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
RTLIL::Const val_cp, val_rp, val_rv;
if (dff->type == "$_DFF_N_" || dff->type == "$_DFF_P_") {
- sig_d = dff->connections["\\D"];
- sig_q = dff->connections["\\Q"];
- sig_c = dff->connections["\\C"];
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ sig_c = dff->getPort("\\C");
val_cp = RTLIL::Const(dff->type == "$_DFF_P_", 1);
}
else if (dff->type.substr(0,6) == "$_DFF_" && dff->type.substr(9) == "_" &&
(dff->type[6] == 'N' || dff->type[6] == 'P') &&
(dff->type[7] == 'N' || dff->type[7] == 'P') &&
(dff->type[8] == '0' || dff->type[8] == '1')) {
- sig_d = dff->connections["\\D"];
- sig_q = dff->connections["\\Q"];
- sig_c = dff->connections["\\C"];
- sig_r = dff->connections["\\R"];
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ sig_c = dff->getPort("\\C");
+ sig_r = dff->getPort("\\R");
val_cp = RTLIL::Const(dff->type[6] == 'P', 1);
val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
val_rv = RTLIL::Const(dff->type[8] == '1', 1);
}
else if (dff->type == "$dff") {
- sig_d = dff->connections["\\D"];
- sig_q = dff->connections["\\Q"];
- sig_c = dff->connections["\\CLK"];
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ sig_c = dff->getPort("\\CLK");
val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
}
else if (dff->type == "$adff") {
- sig_d = dff->connections["\\D"];
- sig_q = dff->connections["\\Q"];
- sig_c = dff->connections["\\CLK"];
- sig_r = dff->connections["\\ARST"];
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ sig_c = dff->getPort("\\CLK");
+ sig_r = dff->getPort("\\ARST");
val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
val_rp = RTLIL::Const(dff->parameters["\\ARST_POLARITY"].as_bool(), 1);
val_rv = dff->parameters["\\ARST_VALUE"];
@@ -85,55 +84,55 @@ static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
std::set<RTLIL::Cell*> muxes;
mux_drivers.find(sig_d, muxes);
for (auto mux : muxes) {
- RTLIL::SigSpec sig_a = assign_map(mux->connections.at("\\A"));
- RTLIL::SigSpec sig_b = assign_map(mux->connections.at("\\B"));
+ RTLIL::SigSpec sig_a = assign_map(mux->getPort("\\A"));
+ RTLIL::SigSpec sig_b = assign_map(mux->getPort("\\B"));
if (sig_a == sig_q && sig_b.is_fully_const()) {
RTLIL::SigSig conn(sig_q, sig_b);
- mod->connections.push_back(conn);
+ mod->connect(conn);
goto delete_dff;
}
if (sig_b == sig_q && sig_a.is_fully_const()) {
RTLIL::SigSig conn(sig_q, sig_a);
- mod->connections.push_back(conn);
+ mod->connect(conn);
goto delete_dff;
}
}
}
- if (sig_c.is_fully_const() && (!sig_r.width || !has_init)) {
+ if (sig_c.is_fully_const() && (!sig_r.size() || !has_init)) {
if (val_rv.bits.size() == 0)
val_rv = val_init;
RTLIL::SigSig conn(sig_q, val_rv);
- mod->connections.push_back(conn);
+ mod->connect(conn);
goto delete_dff;
}
- if (sig_d.is_fully_undef() && sig_r.width && !has_init) {
+ if (sig_d.is_fully_undef() && sig_r.size() && !has_init) {
RTLIL::SigSig conn(sig_q, val_rv);
- mod->connections.push_back(conn);
+ mod->connect(conn);
goto delete_dff;
}
- if (sig_d.is_fully_undef() && !sig_r.width && has_init) {
+ if (sig_d.is_fully_undef() && !sig_r.size() && has_init) {
RTLIL::SigSig conn(sig_q, val_init);
- mod->connections.push_back(conn);
+ mod->connect(conn);
goto delete_dff;
}
- if (sig_d.is_fully_const() && !sig_r.width && !has_init) {
+ if (sig_d.is_fully_const() && !sig_r.size() && !has_init) {
RTLIL::SigSig conn(sig_q, sig_d);
- mod->connections.push_back(conn);
+ mod->connect(conn);
goto delete_dff;
}
- if (sig_d == sig_q && !(sig_r.width && has_init)) {
- if (sig_r.width) {
+ if (sig_d == sig_q && !(sig_r.size() && has_init)) {
+ if (sig_r.size()) {
RTLIL::SigSig conn(sig_q, val_rv);
- mod->connections.push_back(conn);
+ mod->connect(conn);
}
if (has_init) {
RTLIL::SigSig conn(sig_q, val_init);
- mod->connections.push_back(conn);
+ mod->connect(conn);
}
goto delete_dff;
}
@@ -142,9 +141,7 @@ static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
delete_dff:
log("Removing %s (%s) from module %s.\n", dff->name.c_str(), dff->type.c_str(), mod->name.c_str());
- OPT_DID_SOMETHING = true;
- mod->cells.erase(dff->name);
- delete dff;
+ mod->remove(dff);
return true;
}
@@ -167,23 +164,23 @@ struct OptRmdffPass : public Pass {
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (!design->selected(mod_it.second))
continue;
assign_map.set(mod_it.second);
dff_init_map.set(mod_it.second);
- for (auto &it : mod_it.second->wires)
+ for (auto &it : mod_it.second->wires_)
if (it.second->attributes.count("\\init") != 0)
dff_init_map.add(it.second, it.second->attributes.at("\\init"));
mux_drivers.clear();
- std::vector<std::string> dff_list;
- for (auto &it : mod_it.second->cells) {
+ std::vector<RTLIL::IdString> dff_list;
+ for (auto &it : mod_it.second->cells_) {
if (it.second->type == "$mux" || it.second->type == "$pmux") {
- if (it.second->connections.at("\\A").width == it.second->connections.at("\\B").width)
- mux_drivers.insert(assign_map(it.second->connections.at("\\Y")), it.second);
+ if (it.second->getPort("\\A").size() == it.second->getPort("\\B").size())
+ mux_drivers.insert(assign_map(it.second->getPort("\\Y")), it.second);
continue;
}
if (!design->selected(mod_it.second, it.second))
@@ -203,14 +200,17 @@ struct OptRmdffPass : public Pass {
}
for (auto &id : dff_list) {
- if (mod_it.second->cells.count(id) > 0 &&
- handle_dff(mod_it.second, mod_it.second->cells[id]))
+ if (mod_it.second->cells_.count(id) > 0 &&
+ handle_dff(mod_it.second, mod_it.second->cells_[id]))
total_count++;
}
}
assign_map.clear();
mux_drivers.clear();
+
+ if (total_count)
+ design->scratchpad_set_bool("opt.did_something", true);
log("Replaced %d DFF cells.\n", total_count);
}
} OptRmdffPass;
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index eb639d8a..4b76a5a2 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -17,14 +17,12 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include "kernel/celltypes.h"
#include "libs/sha1/sha1.h"
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <set>
@@ -61,12 +59,12 @@ struct OptShareWorker
if (cell_hash_cache.count(cell) > 0)
return cell_hash_cache[cell];
- std::string hash_string = cell->type + "\n";
+ std::string hash_string = cell->type.str() + "\n";
for (auto &it : cell->parameters)
- hash_string += "P " + it.first + "=" + it.second.as_string() + "\n";
+ hash_string += "P " + it.first.str() + "=" + it.second.as_string() + "\n";
- const std::map<RTLIL::IdString, RTLIL::SigSpec> *conn = &cell->connections;
+ const std::map<RTLIL::IdString, RTLIL::SigSpec> *conn = &cell->connections();
std::map<RTLIL::IdString, RTLIL::SigSpec> alt_conn;
if (cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor" || cell->type == "$add" || cell->type == "$mul" ||
@@ -96,24 +94,19 @@ struct OptShareWorker
continue;
RTLIL::SigSpec sig = it.second;
assign_map.apply(sig);
- hash_string += "C " + it.first + "=";
- for (auto &chunk : sig.chunks) {
+ hash_string += "C " + it.first.str() + "=";
+ for (auto &chunk : sig.chunks()) {
if (chunk.wire)
- hash_string += "{" + chunk.wire->name + " " +
+ hash_string += "{" + chunk.wire->name.str() + " " +
int_to_hash_string(chunk.offset) + " " +
int_to_hash_string(chunk.width) + "}";
else
- hash_string += chunk.data.as_string();
+ hash_string += RTLIL::Const(chunk.data).as_string();
}
hash_string += "\n";
}
- unsigned char hash[20];
- char hash_hex_string[41];
- sha1::calc(hash_string.c_str(), hash_string.size(), hash);
- sha1::toHexString(hash, hash_hex_string);
- cell_hash_cache[cell] = hash_hex_string;
-
+ cell_hash_cache[cell] = sha1(hash_string);
return cell_hash_cache[cell];
}
#endif
@@ -135,8 +128,8 @@ struct OptShareWorker
return true;
}
- std::map<RTLIL::IdString, RTLIL::SigSpec> conn1 = cell1->connections;
- std::map<RTLIL::IdString, RTLIL::SigSpec> conn2 = cell2->connections;
+ std::map<RTLIL::IdString, RTLIL::SigSpec> conn1 = cell1->connections();
+ std::map<RTLIL::IdString, RTLIL::SigSpec> conn2 = cell2->connections();
for (auto &it : conn1) {
if (ct.cell_output(cell1->type, it.first))
@@ -180,8 +173,8 @@ struct OptShareWorker
}
if (cell1->type.substr(0, 1) == "$" && conn1.count("\\Q") != 0) {
- std::vector<RTLIL::SigBit> q1 = dff_init_map(cell1->connections.at("\\Q")).to_sigbit_vector();
- std::vector<RTLIL::SigBit> q2 = dff_init_map(cell2->connections.at("\\Q")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> q1 = dff_init_map(cell1->getPort("\\Q")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> q2 = dff_init_map(cell2->getPort("\\Q")).to_sigbit_vector();
for (size_t i = 0; i < q1.size(); i++)
if ((q1.at(i).wire == NULL || q2.at(i).wire == NULL) && q1.at(i) != q2.at(i)) {
lt = q1.at(i) < q2.at(i);
@@ -230,14 +223,13 @@ struct OptShareWorker
if (mode_nomux) {
ct.cell_types.erase("$mux");
ct.cell_types.erase("$pmux");
- ct.cell_types.erase("$safe_pmux");
}
log("Finding identical cells in module `%s'.\n", module->name.c_str());
assign_map.set(module);
dff_init_map.set(module);
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->attributes.count("\\init") != 0)
dff_init_map.add(it.second, it.second->attributes.at("\\init"));
@@ -248,8 +240,8 @@ struct OptShareWorker
cell_hash_cache.clear();
#endif
std::vector<RTLIL::Cell*> cells;
- cells.reserve(module->cells.size());
- for (auto &it : module->cells) {
+ cells.reserve(module->cells_.size());
+ for (auto &it : module->cells_) {
if (ct.cell_known(it.second->type) && design->selected(module, it.second))
cells.push_back(it.second);
}
@@ -261,20 +253,18 @@ struct OptShareWorker
if (sharemap.count(cell) > 0) {
did_something = true;
log(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str());
- for (auto &it : cell->connections) {
+ for (auto &it : cell->connections()) {
if (ct.cell_output(cell->type, it.first)) {
- RTLIL::SigSpec other_sig = sharemap[cell]->connections[it.first];
+ RTLIL::SigSpec other_sig = sharemap[cell]->getPort(it.first);
log(" Redirecting output %s: %s = %s\n", it.first.c_str(),
log_signal(it.second), log_signal(other_sig));
- module->connections.push_back(RTLIL::SigSig(it.second, other_sig));
+ module->connect(RTLIL::SigSig(it.second, other_sig));
assign_map.add(it.second, other_sig);
}
}
log(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str());
- module->cells.erase(cell->name);
- OPT_DID_SOMETHING = true;
+ module->remove(cell);
total_count++;
- delete cell;
} else {
sharemap[cell] = cell;
}
@@ -316,13 +306,15 @@ struct OptSharePass : public Pass {
extra_args(args, argidx, design);
int total_count = 0;
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (!design->selected(mod_it.second))
continue;
OptShareWorker worker(design, mod_it.second, mode_nomux);
total_count += worker.total_count;
}
+ if (total_count)
+ design->scratchpad_set_bool("opt.did_something", true);
log("Removed a total of %d cells.\n", total_count);
}
} OptSharePass;
diff --git a/passes/opt/opt_status.h b/passes/opt/opt_status.h
deleted file mode 100644
index 3d12baa7..00000000
--- a/passes/opt/opt_status.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-#ifndef OPT_STATUS_H
-#define OPT_STATUS_H
-
-extern bool OPT_DID_SOMETHING;
-
-#endif
-
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
new file mode 100644
index 00000000..74b049bb
--- /dev/null
+++ b/passes/opt/share.cc
@@ -0,0 +1,1171 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/satgen.h"
+#include "kernel/sigtools.h"
+#include "kernel/modtools.h"
+#include "kernel/utils.h"
+
+PRIVATE_NAMESPACE_BEGIN
+
+struct ShareWorkerConfig
+{
+ int limit;
+ bool opt_force;
+ bool opt_aggressive;
+ bool opt_fast;
+ std::set<RTLIL::IdString> generic_uni_ops, generic_bin_ops, generic_cbin_ops;
+};
+
+struct ShareWorker
+{
+ ShareWorkerConfig config;
+ std::set<RTLIL::IdString> generic_ops;
+
+ RTLIL::Design *design;
+ RTLIL::Module *module;
+
+ CellTypes fwd_ct, cone_ct;
+ ModWalker modwalker;
+ ModIndex mi;
+
+ std::set<RTLIL::Cell*> cells_to_remove;
+ std::set<RTLIL::Cell*> recursion_state;
+
+ SigMap topo_sigmap;
+ std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> topo_cell_drivers;
+ std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> topo_bit_drivers;
+
+
+ // ------------------------------------------------------------------------------
+ // Find terminal bits -- i.e. bits that do not (exclusively) feed into a mux tree
+ // ------------------------------------------------------------------------------
+
+ std::set<RTLIL::SigBit> terminal_bits;
+
+ void find_terminal_bits()
+ {
+ std::set<RTLIL::SigBit> queue_bits;
+ std::set<RTLIL::Cell*> visited_cells;
+
+ queue_bits.insert(modwalker.signal_outputs.begin(), modwalker.signal_outputs.end());
+
+ for (auto &it : module->cells_)
+ if (!fwd_ct.cell_known(it.second->type)) {
+ std::set<RTLIL::SigBit> &bits = modwalker.cell_inputs[it.second];
+ queue_bits.insert(bits.begin(), bits.end());
+ }
+
+ terminal_bits.insert(queue_bits.begin(), queue_bits.end());
+
+ while (!queue_bits.empty())
+ {
+ std::set<ModWalker::PortBit> portbits;
+ modwalker.get_drivers(portbits, queue_bits);
+ queue_bits.clear();
+
+ for (auto &pbit : portbits) {
+ if (pbit.cell->type == "$mux" || pbit.cell->type == "$pmux") {
+ std::set<RTLIL::SigBit> bits = modwalker.sigmap(pbit.cell->getPort("\\S")).to_sigbit_set();
+ terminal_bits.insert(bits.begin(), bits.end());
+ queue_bits.insert(bits.begin(), bits.end());
+ visited_cells.insert(pbit.cell);
+ }
+ if (fwd_ct.cell_known(pbit.cell->type) && visited_cells.count(pbit.cell) == 0) {
+ std::set<RTLIL::SigBit> &bits = modwalker.cell_inputs[pbit.cell];
+ terminal_bits.insert(bits.begin(), bits.end());
+ queue_bits.insert(bits.begin(), bits.end());
+ visited_cells.insert(pbit.cell);
+ }
+ }
+ }
+ }
+
+
+ // ---------------------------------------------------
+ // Find shareable cells and compatible groups of cells
+ // ---------------------------------------------------
+
+ std::set<RTLIL::Cell*, RTLIL::sort_by_name_str<RTLIL::Cell>> shareable_cells;
+
+ void find_shareable_cells()
+ {
+ for (auto &it : module->cells_)
+ {
+ RTLIL::Cell *cell = it.second;
+
+ if (!design->selected(module, cell) || !modwalker.ct.cell_known(cell->type))
+ continue;
+
+ for (auto &bit : modwalker.cell_outputs[cell])
+ if (terminal_bits.count(bit))
+ goto not_a_muxed_cell;
+
+ if (0)
+ not_a_muxed_cell:
+ continue;
+
+ if (config.opt_force) {
+ shareable_cells.insert(cell);
+ continue;
+ }
+
+ if (cell->type == "$memrd") {
+ if (!cell->parameters.at("\\CLK_ENABLE").as_bool())
+ shareable_cells.insert(cell);
+ continue;
+ }
+
+ if (cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod") {
+ if (config.opt_aggressive || cell->parameters.at("\\Y_WIDTH").as_int() >= 4)
+ shareable_cells.insert(cell);
+ continue;
+ }
+
+ if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr") {
+ if (config.opt_aggressive || cell->parameters.at("\\Y_WIDTH").as_int() >= 8)
+ shareable_cells.insert(cell);
+ continue;
+ }
+
+ if (generic_ops.count(cell->type)) {
+ if (config.opt_aggressive || cell->parameters.at("\\Y_WIDTH").as_int() >= 10)
+ shareable_cells.insert(cell);
+ continue;
+ }
+ }
+ }
+
+ bool is_shareable_pair(RTLIL::Cell *c1, RTLIL::Cell *c2)
+ {
+ if (c1->type != c2->type)
+ return false;
+
+ if (c1->type == "$memrd")
+ {
+ if (c1->parameters.at("\\MEMID").decode_string() != c2->parameters.at("\\MEMID").decode_string())
+ return false;
+
+ return true;
+ }
+
+ if (config.generic_uni_ops.count(c1->type))
+ {
+ if (!config.opt_aggressive)
+ {
+ int a1_width = c1->parameters.at("\\A_WIDTH").as_int();
+ int y1_width = c1->parameters.at("\\Y_WIDTH").as_int();
+
+ int a2_width = c2->parameters.at("\\A_WIDTH").as_int();
+ int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
+
+ if (std::max(a1_width, a2_width) > 2 * std::min(a1_width, a2_width)) return false;
+ if (std::max(y1_width, y2_width) > 2 * std::min(y1_width, y2_width)) return false;
+ }
+
+ return true;
+ }
+
+ if (config.generic_bin_ops.count(c1->type))
+ {
+ if (!config.opt_aggressive)
+ {
+ int a1_width = c1->parameters.at("\\A_WIDTH").as_int();
+ int b1_width = c1->parameters.at("\\B_WIDTH").as_int();
+ int y1_width = c1->parameters.at("\\Y_WIDTH").as_int();
+
+ int a2_width = c2->parameters.at("\\A_WIDTH").as_int();
+ int b2_width = c2->parameters.at("\\B_WIDTH").as_int();
+ int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
+
+ if (std::max(a1_width, a2_width) > 2 * std::min(a1_width, a2_width)) return false;
+ if (std::max(b1_width, b2_width) > 2 * std::min(b1_width, b2_width)) return false;
+ if (std::max(y1_width, y2_width) > 2 * std::min(y1_width, y2_width)) return false;
+ }
+
+ return true;
+ }
+
+ if (config.generic_cbin_ops.count(c1->type))
+ {
+ if (!config.opt_aggressive)
+ {
+ int a1_width = c1->parameters.at("\\A_WIDTH").as_int();
+ int b1_width = c1->parameters.at("\\B_WIDTH").as_int();
+ int y1_width = c1->parameters.at("\\Y_WIDTH").as_int();
+
+ int a2_width = c2->parameters.at("\\A_WIDTH").as_int();
+ int b2_width = c2->parameters.at("\\B_WIDTH").as_int();
+ int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
+
+ int min1_width = std::min(a1_width, b1_width);
+ int max1_width = std::max(a1_width, b1_width);
+
+ int min2_width = std::min(a2_width, b2_width);
+ int max2_width = std::max(a2_width, b2_width);
+
+ if (std::max(min1_width, min2_width) > 2 * std::min(min1_width, min2_width)) return false;
+ if (std::max(max1_width, max2_width) > 2 * std::min(max1_width, max2_width)) return false;
+ if (std::max(y1_width, y2_width) > 2 * std::min(y1_width, y2_width)) return false;
+ }
+
+ return true;
+ }
+
+ for (auto &it : c1->parameters)
+ if (c2->parameters.count(it.first) == 0 || c2->parameters.at(it.first) != it.second)
+ return false;
+
+ for (auto &it : c2->parameters)
+ if (c1->parameters.count(it.first) == 0 || c1->parameters.at(it.first) != it.second)
+ return false;
+
+ return true;
+ }
+
+ void find_shareable_partners(std::vector<RTLIL::Cell*> &results, RTLIL::Cell *cell)
+ {
+ results.clear();
+ for (auto c : shareable_cells)
+ if (c != cell && is_shareable_pair(c, cell))
+ results.push_back(c);
+ }
+
+
+ // -----------------------
+ // Create replacement cell
+ // -----------------------
+
+ RTLIL::Cell *make_supercell(RTLIL::Cell *c1, RTLIL::Cell *c2, RTLIL::SigSpec act, std::set<RTLIL::Cell*> &supercell_aux)
+ {
+ log_assert(c1->type == c2->type);
+
+ if (config.generic_uni_ops.count(c1->type))
+ {
+ if (c1->parameters.at("\\A_SIGNED").as_bool() != c2->parameters.at("\\A_SIGNED").as_bool())
+ {
+ RTLIL::Cell *unsigned_cell = c1->parameters.at("\\A_SIGNED").as_bool() ? c2 : c1;
+ if (unsigned_cell->getPort("\\A").to_sigbit_vector().back() != RTLIL::State::S0) {
+ unsigned_cell->parameters.at("\\A_WIDTH") = unsigned_cell->parameters.at("\\A_WIDTH").as_int() + 1;
+ RTLIL::SigSpec new_a = unsigned_cell->getPort("\\A");
+ new_a.append_bit(RTLIL::State::S0);
+ unsigned_cell->setPort("\\A", new_a);
+ }
+ unsigned_cell->parameters.at("\\A_SIGNED") = true;
+ unsigned_cell->check();
+ }
+
+ bool a_signed = c1->parameters.at("\\A_SIGNED").as_bool();
+ log_assert(a_signed == c2->parameters.at("\\A_SIGNED").as_bool());
+
+ RTLIL::SigSpec a1 = c1->getPort("\\A");
+ RTLIL::SigSpec y1 = c1->getPort("\\Y");
+
+ RTLIL::SigSpec a2 = c2->getPort("\\A");
+ RTLIL::SigSpec y2 = c2->getPort("\\Y");
+
+ int a_width = std::max(a1.size(), a2.size());
+ int y_width = std::max(y1.size(), y2.size());
+
+ a1.extend_u0(a_width, a_signed);
+ a2.extend_u0(a_width, a_signed);
+
+ RTLIL::SigSpec a = module->addWire(NEW_ID, a_width);
+ supercell_aux.insert(module->addMux(NEW_ID, a2, a1, act, a));
+
+ RTLIL::Wire *y = module->addWire(NEW_ID, y_width);
+
+ RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type);
+ supercell->parameters["\\A_SIGNED"] = a_signed;
+ supercell->parameters["\\A_WIDTH"] = a_width;
+ supercell->parameters["\\Y_WIDTH"] = y_width;
+ supercell->setPort("\\A", a);
+ supercell->setPort("\\Y", y);
+
+ supercell_aux.insert(module->addPos(NEW_ID, y, y1));
+ supercell_aux.insert(module->addPos(NEW_ID, y, y2));
+
+ supercell_aux.insert(supercell);
+ return supercell;
+ }
+
+ if (config.generic_bin_ops.count(c1->type) || config.generic_cbin_ops.count(c1->type))
+ {
+ bool modified_src_cells = false;
+
+ if (config.generic_cbin_ops.count(c1->type))
+ {
+ int score_unflipped = std::max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int()) +
+ std::max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int());
+
+ int score_flipped = std::max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int()) +
+ std::max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int());
+
+ if (score_flipped < score_unflipped)
+ {
+ RTLIL::SigSpec tmp = c2->getPort("\\A");
+ c2->setPort("\\A", c2->getPort("\\B"));
+ c2->setPort("\\B", tmp);
+
+ std::swap(c2->parameters.at("\\A_WIDTH"), c2->parameters.at("\\B_WIDTH"));
+ std::swap(c2->parameters.at("\\A_SIGNED"), c2->parameters.at("\\B_SIGNED"));
+ modified_src_cells = true;
+ }
+ }
+
+ if (c1->parameters.at("\\A_SIGNED").as_bool() != c2->parameters.at("\\A_SIGNED").as_bool())
+
+ {
+ RTLIL::Cell *unsigned_cell = c1->parameters.at("\\A_SIGNED").as_bool() ? c2 : c1;
+ if (unsigned_cell->getPort("\\A").to_sigbit_vector().back() != RTLIL::State::S0) {
+ unsigned_cell->parameters.at("\\A_WIDTH") = unsigned_cell->parameters.at("\\A_WIDTH").as_int() + 1;
+ RTLIL::SigSpec new_a = unsigned_cell->getPort("\\A");
+ new_a.append_bit(RTLIL::State::S0);
+ unsigned_cell->setPort("\\A", new_a);
+ }
+ unsigned_cell->parameters.at("\\A_SIGNED") = true;
+ modified_src_cells = true;
+ }
+
+ if (c1->parameters.at("\\B_SIGNED").as_bool() != c2->parameters.at("\\B_SIGNED").as_bool())
+ {
+ RTLIL::Cell *unsigned_cell = c1->parameters.at("\\B_SIGNED").as_bool() ? c2 : c1;
+ if (unsigned_cell->getPort("\\B").to_sigbit_vector().back() != RTLIL::State::S0) {
+ unsigned_cell->parameters.at("\\B_WIDTH") = unsigned_cell->parameters.at("\\B_WIDTH").as_int() + 1;
+ RTLIL::SigSpec new_b = unsigned_cell->getPort("\\B");
+ new_b.append_bit(RTLIL::State::S0);
+ unsigned_cell->setPort("\\B", new_b);
+ }
+ unsigned_cell->parameters.at("\\B_SIGNED") = true;
+ modified_src_cells = true;
+ }
+
+ if (modified_src_cells) {
+ c1->check();
+ c2->check();
+ }
+
+ bool a_signed = c1->parameters.at("\\A_SIGNED").as_bool();
+ bool b_signed = c1->parameters.at("\\B_SIGNED").as_bool();
+
+ log_assert(a_signed == c2->parameters.at("\\A_SIGNED").as_bool());
+ log_assert(b_signed == c2->parameters.at("\\B_SIGNED").as_bool());
+
+ if (c1->type == "$shl" || c1->type == "$shr" || c1->type == "$sshl" || c1->type == "$sshr")
+ b_signed = false;
+
+ RTLIL::SigSpec a1 = c1->getPort("\\A");
+ RTLIL::SigSpec b1 = c1->getPort("\\B");
+ RTLIL::SigSpec y1 = c1->getPort("\\Y");
+
+ RTLIL::SigSpec a2 = c2->getPort("\\A");
+ RTLIL::SigSpec b2 = c2->getPort("\\B");
+ RTLIL::SigSpec y2 = c2->getPort("\\Y");
+
+ int a_width = std::max(a1.size(), a2.size());
+ int b_width = std::max(b1.size(), b2.size());
+ int y_width = std::max(y1.size(), y2.size());
+
+ if (c1->type == "$shr" && a_signed)
+ {
+ a_width = std::max(y_width, a_width);
+
+ if (a1.size() < y1.size()) a1.extend_u0(y1.size(), true);
+ if (a2.size() < y2.size()) a2.extend_u0(y2.size(), true);
+
+ a1.extend_u0(a_width, false);
+ a2.extend_u0(a_width, false);
+ }
+ else
+ {
+ a1.extend_u0(a_width, a_signed);
+ a2.extend_u0(a_width, a_signed);
+ }
+
+ b1.extend_u0(b_width, b_signed);
+ b2.extend_u0(b_width, b_signed);
+
+ RTLIL::SigSpec a = module->addWire(NEW_ID, a_width);
+ RTLIL::SigSpec b = module->addWire(NEW_ID, b_width);
+
+ supercell_aux.insert(module->addMux(NEW_ID, a2, a1, act, a));
+ supercell_aux.insert(module->addMux(NEW_ID, b2, b1, act, b));
+
+ RTLIL::Wire *y = module->addWire(NEW_ID, y_width);
+
+ RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type);
+ supercell->parameters["\\A_SIGNED"] = a_signed;
+ supercell->parameters["\\B_SIGNED"] = b_signed;
+ supercell->parameters["\\A_WIDTH"] = a_width;
+ supercell->parameters["\\B_WIDTH"] = b_width;
+ supercell->parameters["\\Y_WIDTH"] = y_width;
+ supercell->setPort("\\A", a);
+ supercell->setPort("\\B", b);
+ supercell->setPort("\\Y", y);
+ supercell->check();
+
+ supercell_aux.insert(module->addPos(NEW_ID, y, y1));
+ supercell_aux.insert(module->addPos(NEW_ID, y, y2));
+
+ supercell_aux.insert(supercell);
+ return supercell;
+ }
+
+ if (c1->type == "$memrd")
+ {
+ RTLIL::Cell *supercell = module->addCell(NEW_ID, c1);
+ supercell_aux.insert(module->addPos(NEW_ID, supercell->getPort("\\DATA"), c2->getPort("\\DATA")));
+ supercell_aux.insert(supercell);
+ return supercell;
+ }
+
+ log_abort();
+ }
+
+
+ // -------------------------------------------
+ // Finding forbidden control inputs for a cell
+ // -------------------------------------------
+
+ std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> forbidden_controls_cache;
+
+ const std::set<RTLIL::SigBit> &find_forbidden_controls(RTLIL::Cell *cell)
+ {
+ if (recursion_state.count(cell)) {
+ static std::set<RTLIL::SigBit> empty_controls_set;
+ return empty_controls_set;
+ }
+
+ if (forbidden_controls_cache.count(cell))
+ return forbidden_controls_cache.at(cell);
+
+ std::set<ModWalker::PortBit> pbits;
+ std::set<RTLIL::Cell*> consumer_cells;
+
+ modwalker.get_consumers(pbits, modwalker.cell_outputs[cell]);
+
+ for (auto &bit : pbits) {
+ if ((bit.cell->type == "$mux" || bit.cell->type == "$pmux") && bit.port == "\\S")
+ forbidden_controls_cache[cell].insert(bit.cell->getPort("\\S").extract(bit.offset, 1));
+ consumer_cells.insert(bit.cell);
+ }
+
+ recursion_state.insert(cell);
+
+ for (auto c : consumer_cells)
+ if (fwd_ct.cell_known(c->type)) {
+ const std::set<RTLIL::SigBit> &bits = find_forbidden_controls(c);
+ forbidden_controls_cache[cell].insert(bits.begin(), bits.end());
+ }
+
+ log_assert(recursion_state.count(cell));
+ recursion_state.erase(cell);
+
+ return forbidden_controls_cache[cell];
+ }
+
+
+ // --------------------------------------------------------
+ // Finding control inputs and activation pattern for a cell
+ // --------------------------------------------------------
+
+ std::map<RTLIL::Cell*, std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>>> activation_patterns_cache;
+
+ bool sort_check_activation_pattern(std::pair<RTLIL::SigSpec, RTLIL::Const> &p)
+ {
+ std::map<RTLIL::SigBit, RTLIL::State> p_bits;
+
+ std::vector<RTLIL::SigBit> p_first_bits = p.first;
+ for (int i = 0; i < SIZE(p_first_bits); i++) {
+ RTLIL::SigBit b = p_first_bits[i];
+ RTLIL::State v = p.second.bits[i];
+ if (p_bits.count(b) && p_bits.at(b) != v)
+ return false;
+ p_bits[b] = v;
+ }
+
+ p.first = RTLIL::SigSpec();
+ p.second.bits.clear();
+
+ for (auto &it : p_bits) {
+ p.first.append_bit(it.first);
+ p.second.bits.push_back(it.second);
+ }
+
+ return true;
+ }
+
+ void optimize_activation_patterns(std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> & /* patterns */)
+ {
+ // TODO: Remove patterns that are contained in other patterns
+ // TODO: Consolidate pairs of patterns that only differ in the value for one signal bit
+ }
+
+ const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &find_cell_activation_patterns(RTLIL::Cell *cell, const char *indent)
+ {
+ if (recursion_state.count(cell)) {
+ static std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> empty_patterns_set;
+ return empty_patterns_set;
+ }
+
+ if (activation_patterns_cache.count(cell))
+ return activation_patterns_cache.at(cell);
+
+ const std::set<RTLIL::SigBit> &cell_out_bits = modwalker.cell_outputs[cell];
+ std::set<RTLIL::Cell*> driven_cells, driven_data_muxes;
+
+ for (auto &bit : cell_out_bits)
+ {
+ if (terminal_bits.count(bit)) {
+ // Terminal cells are always active: unconditional activation pattern
+ activation_patterns_cache[cell].insert(std::pair<RTLIL::SigSpec, RTLIL::Const>());
+ return activation_patterns_cache.at(cell);
+ }
+ for (auto &pbit : modwalker.signal_consumers[bit]) {
+ log_assert(fwd_ct.cell_known(pbit.cell->type));
+ if ((pbit.cell->type == "$mux" || pbit.cell->type == "$pmux") && (pbit.port == "\\A" || pbit.port == "\\B"))
+ driven_data_muxes.insert(pbit.cell);
+ else
+ driven_cells.insert(pbit.cell);
+ }
+ }
+
+ recursion_state.insert(cell);
+
+ for (auto c : driven_data_muxes)
+ {
+ const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &c_patterns = find_cell_activation_patterns(c, indent);
+
+ bool used_in_a = false;
+ std::set<int> used_in_b_parts;
+
+ int width = c->parameters.at("\\WIDTH").as_int();
+ std::vector<RTLIL::SigBit> sig_a = modwalker.sigmap(c->getPort("\\A"));
+ std::vector<RTLIL::SigBit> sig_b = modwalker.sigmap(c->getPort("\\B"));
+ std::vector<RTLIL::SigBit> sig_s = modwalker.sigmap(c->getPort("\\S"));
+
+ for (auto &bit : sig_a)
+ if (cell_out_bits.count(bit))
+ used_in_a = true;
+
+ for (int i = 0; i < SIZE(sig_b); i++)
+ if (cell_out_bits.count(sig_b[i]))
+ used_in_b_parts.insert(i / width);
+
+ if (used_in_a)
+ for (auto p : c_patterns) {
+ for (int i = 0; i < SIZE(sig_s); i++)
+ p.first.append_bit(sig_s[i]), p.second.bits.push_back(RTLIL::State::S0);
+ if (sort_check_activation_pattern(p))
+ activation_patterns_cache[cell].insert(p);
+ }
+
+ for (int idx : used_in_b_parts)
+ for (auto p : c_patterns) {
+ p.first.append_bit(sig_s[idx]), p.second.bits.push_back(RTLIL::State::S1);
+ if (sort_check_activation_pattern(p))
+ activation_patterns_cache[cell].insert(p);
+ }
+ }
+
+ for (auto c : driven_cells) {
+ const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &c_patterns = find_cell_activation_patterns(c, indent);
+ activation_patterns_cache[cell].insert(c_patterns.begin(), c_patterns.end());
+ }
+
+ log_assert(recursion_state.count(cell));
+ recursion_state.erase(cell);
+
+ optimize_activation_patterns(activation_patterns_cache[cell]);
+ if (activation_patterns_cache[cell].empty()) {
+ log("%sFound cell that is never activated: %s\n", indent, log_id(cell));
+ RTLIL::SigSpec cell_outputs = modwalker.cell_outputs[cell];
+ module->connect(RTLIL::SigSig(cell_outputs, RTLIL::SigSpec(RTLIL::State::Sx, cell_outputs.size())));
+ cells_to_remove.insert(cell);
+ }
+
+ return activation_patterns_cache[cell];
+ }
+
+ RTLIL::SigSpec bits_from_activation_patterns(const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &activation_patterns)
+ {
+ std::set<RTLIL::SigBit> all_bits;
+ for (auto &it : activation_patterns) {
+ std::vector<RTLIL::SigBit> bits = it.first;
+ all_bits.insert(bits.begin(), bits.end());
+ }
+
+ RTLIL::SigSpec signal;
+ for (auto &bit : all_bits)
+ signal.append_bit(bit);
+
+ return signal;
+ }
+
+ void filter_activation_patterns(std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &out,
+ const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &in, const std::set<RTLIL::SigBit> &filter_bits)
+ {
+ for (auto &p : in)
+ {
+ std::vector<RTLIL::SigBit> p_first = p.first;
+ std::pair<RTLIL::SigSpec, RTLIL::Const> new_p;
+
+ for (int i = 0; i < SIZE(p_first); i++)
+ if (filter_bits.count(p_first[i]) == 0) {
+ new_p.first.append_bit(p_first[i]);
+ new_p.second.bits.push_back(p.second.bits.at(i));
+ }
+
+ out.insert(new_p);
+ }
+ }
+
+ RTLIL::SigSpec make_cell_activation_logic(const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &activation_patterns, std::set<RTLIL::Cell*> &supercell_aux)
+ {
+ RTLIL::Wire *all_cases_wire = module->addWire(NEW_ID, 0);
+
+ for (auto &p : activation_patterns) {
+ all_cases_wire->width++;
+ supercell_aux.insert(module->addEq(NEW_ID, p.first, p.second, RTLIL::SigSpec(all_cases_wire, all_cases_wire->width - 1)));
+ }
+
+ if (all_cases_wire->width == 1)
+ return all_cases_wire;
+
+ RTLIL::Wire *result_wire = module->addWire(NEW_ID);
+ supercell_aux.insert(module->addReduceOr(NEW_ID, all_cases_wire, result_wire));
+ return result_wire;
+ }
+
+
+ // -------------------------------------------------------------------------------------
+ // Helper functions used to make sure that this pass does not introduce new logic loops.
+ // -------------------------------------------------------------------------------------
+
+ bool module_has_scc()
+ {
+ CellTypes ct;
+ ct.setup_internals();
+ ct.setup_stdcells();
+
+ TopoSort<RTLIL::Cell*> toposort;
+ toposort.analyze_loops = false;
+
+ topo_sigmap.set(module);
+ topo_bit_drivers.clear();
+
+ std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bits;
+ std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cells;
+
+ for (auto cell : module->cells())
+ if (ct.cell_known(cell->type))
+ for (auto &conn : cell->connections()) {
+ if (ct.cell_output(cell->type, conn.first))
+ for (auto bit : topo_sigmap(conn.second)) {
+ cell_to_bits[cell].insert(bit);
+ topo_bit_drivers[bit].insert(cell);
+ }
+ else
+ for (auto bit : topo_sigmap(conn.second))
+ bit_to_cells[bit].insert(cell);
+ }
+
+ for (auto &it : cell_to_bits)
+ {
+ RTLIL::Cell *c1 = it.first;
+
+ for (auto bit : it.second)
+ for (auto c2 : bit_to_cells[bit])
+ toposort.edge(c1, c2);
+ }
+
+ bool found_scc = !toposort.sort();
+ topo_cell_drivers = std::move(toposort.database);
+
+ if (found_scc && toposort.analyze_loops)
+ for (auto &loop : toposort.loops) {
+ log("### loop ###\n");
+ for (auto &c : loop)
+ log("%s (%s)\n", log_id(c), log_id(c->type));
+ }
+
+ return found_scc;
+ }
+
+ bool find_in_input_cone_worker(RTLIL::Cell *root, RTLIL::Cell *needle, std::set<RTLIL::Cell*> &stop)
+ {
+ if (root == needle)
+ return true;
+
+ if (stop.count(root))
+ return false;
+
+ stop.insert(root);
+
+ for (auto c : topo_cell_drivers[root])
+ if (find_in_input_cone_worker(c, needle, stop))
+ return true;
+ return false;
+ }
+
+ bool find_in_input_cone(RTLIL::Cell *root, RTLIL::Cell *needle)
+ {
+ std::set<RTLIL::Cell*> stop;
+ return find_in_input_cone_worker(root, needle, stop);
+ }
+
+ bool is_part_of_scc(RTLIL::Cell *cell)
+ {
+ CellTypes ct;
+ ct.setup_internals();
+ ct.setup_stdcells();
+
+ std::set<RTLIL::Cell*> queue, covered;
+ queue.insert(cell);
+
+ while (!queue.empty())
+ {
+ std::set<RTLIL::Cell*> new_queue;
+
+ for (auto c : queue) {
+ if (!ct.cell_known(c->type))
+ continue;
+ for (auto &conn : c->connections())
+ if (ct.cell_input(c->type, conn.first))
+ for (auto bit : conn.second)
+ for (auto &pi : mi.query_ports(bit))
+ if (ct.cell_known(pi.cell->type) && ct.cell_output(pi.cell->type, pi.port))
+ new_queue.insert(pi.cell);
+ covered.insert(c);
+ }
+
+ queue.clear();
+ for (auto c : new_queue) {
+ if (cells_to_remove.count(c))
+ continue;
+ if (c == cell)
+ return true;
+ if (!covered.count(c))
+ queue.insert(c);
+ }
+ }
+
+ return false;
+ }
+
+
+ // -------------
+ // Setup and run
+ // -------------
+
+ ShareWorker(ShareWorkerConfig config, RTLIL::Design *design, RTLIL::Module *module) :
+ config(config), design(design), module(module), mi(module)
+ {
+ bool before_scc = module_has_scc();
+
+ generic_ops.insert(config.generic_uni_ops.begin(), config.generic_uni_ops.end());
+ generic_ops.insert(config.generic_bin_ops.begin(), config.generic_bin_ops.end());
+ generic_ops.insert(config.generic_cbin_ops.begin(), config.generic_cbin_ops.end());
+
+ fwd_ct.setup_internals();
+
+ cone_ct.setup_internals();
+ cone_ct.cell_types.erase("$mul");
+ cone_ct.cell_types.erase("$mod");
+ cone_ct.cell_types.erase("$div");
+ cone_ct.cell_types.erase("$pow");
+ cone_ct.cell_types.erase("$shl");
+ cone_ct.cell_types.erase("$shr");
+ cone_ct.cell_types.erase("$sshl");
+ cone_ct.cell_types.erase("$sshr");
+
+ modwalker.setup(design, module);
+
+ find_terminal_bits();
+ find_shareable_cells();
+
+ if (shareable_cells.size() < 2)
+ return;
+
+ log("Found %d cells in module %s that may be considered for resource sharing.\n",
+ SIZE(shareable_cells), log_id(module));
+
+ while (!shareable_cells.empty() && config.limit != 0)
+ {
+ RTLIL::Cell *cell = *shareable_cells.begin();
+ shareable_cells.erase(cell);
+
+ log(" Analyzing resource sharing options for %s:\n", log_id(cell));
+
+ const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &cell_activation_patterns = find_cell_activation_patterns(cell, " ");
+ RTLIL::SigSpec cell_activation_signals = bits_from_activation_patterns(cell_activation_patterns);
+
+ if (cell_activation_patterns.empty()) {
+ log(" Cell is never active. Sharing is pointless, we simply remove it.\n");
+ cells_to_remove.insert(cell);
+ continue;
+ }
+
+ if (cell_activation_patterns.count(std::pair<RTLIL::SigSpec, RTLIL::Const>())) {
+ log(" Cell is always active. Therefore no sharing is possible.\n");
+ continue;
+ }
+
+ log(" Found %d activation_patterns using ctrl signal %s.\n", SIZE(cell_activation_patterns), log_signal(cell_activation_signals));
+
+ std::vector<RTLIL::Cell*> candidates;
+ find_shareable_partners(candidates, cell);
+
+ if (candidates.empty()) {
+ log(" No candidates found.\n");
+ continue;
+ }
+
+ log(" Found %d candidates:", SIZE(candidates));
+ for (auto c : candidates)
+ log(" %s", log_id(c));
+ log("\n");
+
+ for (auto other_cell : candidates)
+ {
+ log(" Analyzing resource sharing with %s:\n", log_id(other_cell));
+
+ const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &other_cell_activation_patterns = find_cell_activation_patterns(other_cell, " ");
+ RTLIL::SigSpec other_cell_activation_signals = bits_from_activation_patterns(other_cell_activation_patterns);
+
+ if (other_cell_activation_patterns.empty()) {
+ log(" Cell is never active. Sharing is pointless, we simply remove it.\n");
+ shareable_cells.erase(other_cell);
+ cells_to_remove.insert(other_cell);
+ continue;
+ }
+
+ if (other_cell_activation_patterns.count(std::pair<RTLIL::SigSpec, RTLIL::Const>())) {
+ log(" Cell is always active. Therefore no sharing is possible.\n");
+ shareable_cells.erase(other_cell);
+ continue;
+ }
+
+ log(" Found %d activation_patterns using ctrl signal %s.\n",
+ SIZE(other_cell_activation_patterns), log_signal(other_cell_activation_signals));
+
+ const std::set<RTLIL::SigBit> &cell_forbidden_controls = find_forbidden_controls(cell);
+ const std::set<RTLIL::SigBit> &other_cell_forbidden_controls = find_forbidden_controls(other_cell);
+
+ std::set<RTLIL::SigBit> union_forbidden_controls;
+ union_forbidden_controls.insert(cell_forbidden_controls.begin(), cell_forbidden_controls.end());
+ union_forbidden_controls.insert(other_cell_forbidden_controls.begin(), other_cell_forbidden_controls.end());
+
+ if (!union_forbidden_controls.empty())
+ log(" Forbidden control signals for this pair of cells: %s\n", log_signal(union_forbidden_controls));
+
+ std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> filtered_cell_activation_patterns;
+ std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> filtered_other_cell_activation_patterns;
+
+ filter_activation_patterns(filtered_cell_activation_patterns, cell_activation_patterns, union_forbidden_controls);
+ filter_activation_patterns(filtered_other_cell_activation_patterns, other_cell_activation_patterns, union_forbidden_controls);
+
+ optimize_activation_patterns(filtered_cell_activation_patterns);
+ optimize_activation_patterns(filtered_other_cell_activation_patterns);
+
+ ezDefaultSAT ez;
+ SatGen satgen(&ez, &modwalker.sigmap);
+
+ std::set<RTLIL::Cell*> sat_cells;
+ std::set<RTLIL::SigBit> bits_queue;
+
+ std::vector<int> cell_active, other_cell_active;
+ RTLIL::SigSpec all_ctrl_signals;
+
+ for (auto &p : filtered_cell_activation_patterns) {
+ log(" Activation pattern for cell %s: %s = %s\n", log_id(cell), log_signal(p.first), log_signal(p.second));
+ cell_active.push_back(ez.vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
+ all_ctrl_signals.append(p.first);
+ }
+
+ for (auto &p : filtered_other_cell_activation_patterns) {
+ log(" Activation pattern for cell %s: %s = %s\n", log_id(other_cell), log_signal(p.first), log_signal(p.second));
+ other_cell_active.push_back(ez.vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
+ all_ctrl_signals.append(p.first);
+ }
+
+ for (auto &bit : cell_activation_signals.to_sigbit_vector())
+ bits_queue.insert(bit);
+
+ for (auto &bit : other_cell_activation_signals.to_sigbit_vector())
+ bits_queue.insert(bit);
+
+ while (!bits_queue.empty())
+ {
+ std::set<ModWalker::PortBit> portbits;
+ modwalker.get_drivers(portbits, bits_queue);
+ bits_queue.clear();
+
+ for (auto &pbit : portbits)
+ if (sat_cells.count(pbit.cell) == 0 && cone_ct.cell_known(pbit.cell->type)) {
+ if (config.opt_fast && modwalker.cell_outputs[pbit.cell].size() >= 4)
+ continue;
+ // log(" Adding cell %s (%s) to SAT problem.\n", log_id(pbit.cell), log_id(pbit.cell->type));
+ bits_queue.insert(modwalker.cell_inputs[pbit.cell].begin(), modwalker.cell_inputs[pbit.cell].end());
+ satgen.importCell(pbit.cell);
+ sat_cells.insert(pbit.cell);
+ }
+
+ if (config.opt_fast && sat_cells.size() > 100)
+ break;
+ }
+
+ if (!ez.solve(ez.expression(ez.OpOr, cell_active))) {
+ log(" According to the SAT solver the cell %s is never active. Sharing is pointless, we simply remove it.\n", log_id(cell));
+ cells_to_remove.insert(cell);
+ break;
+ }
+
+ if (!ez.solve(ez.expression(ez.OpOr, other_cell_active))) {
+ log(" According to the SAT solver the cell %s is never active. Sharing is pointless, we simply remove it.\n", log_id(other_cell));
+ cells_to_remove.insert(other_cell);
+ shareable_cells.erase(other_cell);
+ continue;
+ }
+
+ ez.non_incremental();
+
+ all_ctrl_signals.sort_and_unify();
+ std::vector<int> sat_model = satgen.importSigSpec(all_ctrl_signals);
+ std::vector<bool> sat_model_values;
+
+ ez.assume(ez.AND(ez.expression(ez.OpOr, cell_active), ez.expression(ez.OpOr, other_cell_active)));
+
+ log(" Size of SAT problem: %d cells, %d variables, %d clauses\n",
+ SIZE(sat_cells), ez.numCnfVariables(), ez.numCnfClauses());
+
+ if (ez.solve(sat_model, sat_model_values)) {
+ log(" According to the SAT solver this pair of cells can not be shared.\n");
+ log(" Model from SAT solver: %s = %d'", log_signal(all_ctrl_signals), SIZE(sat_model_values));
+ for (int i = SIZE(sat_model_values)-1; i >= 0; i--)
+ log("%c", sat_model_values[i] ? '1' : '0');
+ log("\n");
+ continue;
+ }
+
+ log(" According to the SAT solver this pair of cells can be shared.\n");
+
+ if (find_in_input_cone(cell, other_cell)) {
+ log(" Sharing not possible: %s is in input cone of %s.\n", log_id(other_cell), log_id(cell));
+ continue;
+ }
+
+ if (find_in_input_cone(other_cell, cell)) {
+ log(" Sharing not possible: %s is in input cone of %s.\n", log_id(cell), log_id(other_cell));
+ continue;
+ }
+
+ shareable_cells.erase(other_cell);
+
+ int cell_select_score = 0;
+ int other_cell_select_score = 0;
+
+ for (auto &p : filtered_cell_activation_patterns)
+ cell_select_score += p.first.size();
+
+ for (auto &p : filtered_other_cell_activation_patterns)
+ other_cell_select_score += p.first.size();
+
+ RTLIL::Cell *supercell;
+ std::set<RTLIL::Cell*> supercell_aux;
+ if (cell_select_score <= other_cell_select_score) {
+ RTLIL::SigSpec act = make_cell_activation_logic(filtered_cell_activation_patterns, supercell_aux);
+ supercell = make_supercell(cell, other_cell, act, supercell_aux);
+ log(" Activation signal for %s: %s\n", log_id(cell), log_signal(act));
+ } else {
+ RTLIL::SigSpec act = make_cell_activation_logic(filtered_other_cell_activation_patterns, supercell_aux);
+ supercell = make_supercell(other_cell, cell, act, supercell_aux);
+ log(" Activation signal for %s: %s\n", log_id(other_cell), log_signal(act));
+ }
+
+ log(" New cell: %s (%s)\n", log_id(supercell), log_id(supercell->type));
+
+ cells_to_remove.insert(cell);
+ cells_to_remove.insert(other_cell);
+
+ for (auto c : supercell_aux)
+ if (is_part_of_scc(c))
+ goto do_rollback;
+
+ if (0) {
+ do_rollback:
+ log(" New topology contains loops! Rolling back..\n");
+ cells_to_remove.erase(cell);
+ cells_to_remove.erase(other_cell);
+ shareable_cells.insert(other_cell);
+ for (auto cc : supercell_aux)
+ module->remove(cc);
+ continue;
+ }
+
+ std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> supercell_activation_patterns;
+ supercell_activation_patterns.insert(filtered_cell_activation_patterns.begin(), filtered_cell_activation_patterns.end());
+ supercell_activation_patterns.insert(filtered_other_cell_activation_patterns.begin(), filtered_other_cell_activation_patterns.end());
+ optimize_activation_patterns(supercell_activation_patterns);
+ activation_patterns_cache[supercell] = supercell_activation_patterns;
+ shareable_cells.insert(supercell);
+
+ for (auto bit : topo_sigmap(all_ctrl_signals))
+ for (auto c : topo_bit_drivers[bit])
+ topo_cell_drivers[supercell].insert(c);
+
+ topo_cell_drivers[supercell].insert(topo_cell_drivers[cell].begin(), topo_cell_drivers[cell].end());
+ topo_cell_drivers[supercell].insert(topo_cell_drivers[other_cell].begin(), topo_cell_drivers[other_cell].end());
+
+ topo_cell_drivers[cell] = { supercell };
+ topo_cell_drivers[other_cell] = { supercell };
+
+ if (config.limit > 0)
+ config.limit--;
+
+ break;
+ }
+ }
+
+ if (!cells_to_remove.empty()) {
+ log("Removing %d cells in module %s:\n", SIZE(cells_to_remove), log_id(module));
+ for (auto c : cells_to_remove) {
+ log(" Removing cell %s (%s).\n", log_id(c), log_id(c->type));
+ module->remove(c);
+ }
+ }
+
+ log_assert(recursion_state.empty());
+
+ bool after_scc = before_scc || module_has_scc();
+ log_assert(before_scc == after_scc);
+ }
+};
+
+struct SharePass : public Pass {
+ SharePass() : Pass("share", "perform sat-based resource sharing") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" share [options] [selection]\n");
+ log("\n");
+ log("This pass merges shareable resources into a single resource. A SAT solver\n");
+ log("is used to determine if two resources are share-able.\n");
+ log("\n");
+ log(" -force\n");
+ log(" Per default the selection of cells that is considered for sharing is\n");
+ log(" narrowed using a list of cell types. With this option all selected\n");
+ log(" cells are considered for resource sharing.\n");
+ log("\n");
+ log(" IMPORTANT NOTE: If the -all option is used then no cells with internal\n");
+ log(" state must be selected!\n");
+ log("\n");
+ log(" -aggressive\n");
+ log(" Per default some heuristics are used to reduce the number of cells\n");
+ log(" considered for resource sharing to only large resources. This options\n");
+ log(" turns this heuristics off, resulting in much more cells being considered\n");
+ log(" for resource sharing.\n");
+ log("\n");
+ log(" -fast\n");
+ log(" Only consider the simple part of the control logic in SAT solving, resulting\n");
+ log(" in much easier SAT problems at the cost of maybe missing some oportunities\n");
+ log(" for resource sharing.\n");
+ log("\n");
+ log(" -limit N\n");
+ log(" Only perform the first N merges, then stop. This is useful for debugging.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ ShareWorkerConfig config;
+
+ config.limit = -1;
+ config.opt_force = false;
+ config.opt_aggressive = false;
+ config.opt_fast = false;
+
+ config.generic_uni_ops.insert("$not");
+ // config.generic_uni_ops.insert("$pos");
+ config.generic_uni_ops.insert("$neg");
+
+ config.generic_cbin_ops.insert("$and");
+ config.generic_cbin_ops.insert("$or");
+ config.generic_cbin_ops.insert("$xor");
+ config.generic_cbin_ops.insert("$xnor");
+
+ config.generic_bin_ops.insert("$shl");
+ config.generic_bin_ops.insert("$shr");
+ config.generic_bin_ops.insert("$sshl");
+ config.generic_bin_ops.insert("$sshr");
+
+ config.generic_bin_ops.insert("$lt");
+ config.generic_bin_ops.insert("$le");
+ config.generic_bin_ops.insert("$eq");
+ config.generic_bin_ops.insert("$ne");
+ config.generic_bin_ops.insert("$eqx");
+ config.generic_bin_ops.insert("$nex");
+ config.generic_bin_ops.insert("$ge");
+ config.generic_bin_ops.insert("$gt");
+
+ config.generic_cbin_ops.insert("$add");
+ config.generic_cbin_ops.insert("$mul");
+
+ config.generic_bin_ops.insert("$sub");
+ config.generic_bin_ops.insert("$div");
+ config.generic_bin_ops.insert("$mod");
+ // config.generic_bin_ops.insert("$pow");
+
+ config.generic_uni_ops.insert("$logic_not");
+ config.generic_cbin_ops.insert("$logic_and");
+ config.generic_cbin_ops.insert("$logic_or");
+
+ log_header("Executing SHARE pass (SAT-based resource sharing).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-force") {
+ config.opt_force = true;
+ continue;
+ }
+ if (args[argidx] == "-aggressive") {
+ config.opt_aggressive = true;
+ continue;
+ }
+ if (args[argidx] == "-fast") {
+ config.opt_fast = true;
+ continue;
+ }
+ if (args[argidx] == "-limit" && argidx+1 < args.size()) {
+ config.limit = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto &mod_it : design->modules_)
+ if (design->selected(mod_it.second))
+ ShareWorker(config, design, mod_it.second);
+ }
+} SharePass;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
new file mode 100644
index 00000000..58a6d1b0
--- /dev/null
+++ b/passes/opt/wreduce.cc
@@ -0,0 +1,350 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/modtools.h"
+
+USING_YOSYS_NAMESPACE
+using namespace RTLIL;
+
+PRIVATE_NAMESPACE_BEGIN
+
+struct WreduceConfig
+{
+ std::set<IdString> supported_cell_types;
+
+ WreduceConfig()
+ {
+ supported_cell_types = {
+ "$not", "$pos", "$neg",
+ "$and", "$or", "$xor", "$xnor",
+ "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
+ "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
+ "$add", "$sub", // "$mul", "$div", "$mod", "$pow",
+ "$mux", "$pmux"
+ };
+ }
+};
+
+struct WreduceWorker
+{
+ WreduceConfig *config;
+ Module *module;
+ ModIndex mi;
+
+ std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells;
+ std::set<SigBit> work_queue_bits;
+
+ WreduceWorker(WreduceConfig *config, Module *module) :
+ config(config), module(module), mi(module) { }
+
+ void run_cell_mux(Cell *cell)
+ {
+ // Reduce size of MUX if inputs agree on a value for a bit or a output bit is unused
+
+ SigSpec sig_a = mi.sigmap(cell->getPort("\\A"));
+ SigSpec sig_b = mi.sigmap(cell->getPort("\\B"));
+ SigSpec sig_s = mi.sigmap(cell->getPort("\\S"));
+ SigSpec sig_y = mi.sigmap(cell->getPort("\\Y"));
+ std::vector<SigBit> bits_removed;
+
+ for (int i = SIZE(sig_y)-1; i >= 0; i--)
+ {
+ auto info = mi.query(sig_y[i]);
+ if (!info->is_output && SIZE(info->ports) <= 1) {
+ bits_removed.push_back(Sx);
+ continue;
+ }
+
+ SigBit ref = sig_a[i];
+ for (int k = 0; k < SIZE(sig_s); k++) {
+ if (ref != Sx && sig_b[k*SIZE(sig_a) + i] != Sx && ref != sig_b[k*SIZE(sig_a) + i])
+ goto no_match_ab;
+ if (sig_b[k*SIZE(sig_a) + i] != Sx)
+ ref = sig_b[k*SIZE(sig_a) + i];
+ }
+ if (0)
+ no_match_ab:
+ break;
+ bits_removed.push_back(ref);
+ }
+
+ if (bits_removed.empty())
+ return;
+
+ SigSpec sig_removed;
+ for (int i = SIZE(bits_removed)-1; i >= 0; i--)
+ sig_removed.append_bit(bits_removed[i]);
+
+ if (SIZE(bits_removed) == SIZE(sig_y)) {
+ log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
+ module->connect(sig_y, sig_removed);
+ module->remove(cell);
+ return;
+ }
+
+ log("Removed top %d bits (of %d) from mux cell %s.%s (%s).\n",
+ SIZE(sig_removed), SIZE(sig_y), log_id(module), log_id(cell), log_id(cell->type));
+
+ int n_removed = SIZE(sig_removed);
+ int n_kept = SIZE(sig_y) - SIZE(sig_removed);
+
+ SigSpec new_work_queue_bits;
+ new_work_queue_bits.append(sig_a.extract(n_kept, n_removed));
+ new_work_queue_bits.append(sig_y.extract(n_kept, n_removed));
+
+ SigSpec new_sig_a = sig_a.extract(0, n_kept);
+ SigSpec new_sig_y = sig_y.extract(0, n_kept);
+ SigSpec new_sig_b;
+
+ for (int k = 0; k < SIZE(sig_s); k++) {
+ new_sig_b.append(sig_b.extract(k*SIZE(sig_a), n_kept));
+ new_work_queue_bits.append(sig_b.extract(k*SIZE(sig_a) + n_kept, n_removed));
+ }
+
+ for (auto bit : new_work_queue_bits)
+ work_queue_bits.insert(bit);
+
+ cell->setPort("\\A", new_sig_a);
+ cell->setPort("\\B", new_sig_b);
+ cell->setPort("\\Y", new_sig_y);
+ cell->fixup_parameters();
+
+ module->connect(sig_y.extract(n_kept, n_removed), sig_removed);
+ }
+
+ void run_reduce_inport(Cell *cell, char port, int max_port_size, bool &port_signed, bool &did_something)
+ {
+ port_signed = cell->getParam(stringf("\\%c_SIGNED", port)).as_bool();
+ SigSpec sig = mi.sigmap(cell->getPort(stringf("\\%c", port)));
+
+ if (port == 'B' && cell->type.in("$shl", "$shr", "$sshl", "$sshr"))
+ port_signed = false;
+
+ int bits_removed = 0;
+ if (SIZE(sig) > max_port_size) {
+ bits_removed = SIZE(sig) - max_port_size;
+ for (auto bit : sig.extract(max_port_size, bits_removed))
+ work_queue_bits.insert(bit);
+ sig = sig.extract(0, max_port_size);
+ }
+
+ if (port_signed) {
+ while (SIZE(sig) > 1 && sig[SIZE(sig)-1] == sig[SIZE(sig)-2])
+ work_queue_bits.insert(sig[SIZE(sig)-1]), sig.remove(SIZE(sig)-1), bits_removed++;
+ } else {
+ while (SIZE(sig) > 1 && sig[SIZE(sig)-1] == S0)
+ work_queue_bits.insert(sig[SIZE(sig)-1]), sig.remove(SIZE(sig)-1), bits_removed++;
+ }
+
+ if (bits_removed) {
+ log("Removed top %d bits (of %d) from port %c of cell %s.%s (%s).\n",
+ bits_removed, SIZE(sig) + bits_removed, port, log_id(module), log_id(cell), log_id(cell->type));
+ cell->setPort(stringf("\\%c", port), sig);
+ did_something = true;
+ }
+ }
+
+ void run_cell(Cell *cell)
+ {
+ bool did_something = false;
+
+ if (!cell->type.in(config->supported_cell_types))
+ return;
+
+ if (cell->type.in("$mux", "$pmux"))
+ return run_cell_mux(cell);
+
+
+ // Reduce size of ports A and B based on constant input bits and size of output port
+
+ int max_port_a_size = cell->hasPort("\\A") ? SIZE(cell->getPort("\\A")) : -1;
+ int max_port_b_size = cell->hasPort("\\B") ? SIZE(cell->getPort("\\B")) : -1;
+
+ if (cell->type.in("$not", "$pos", "$neg", "$and", "$or", "$xor", "$add", "$sub")) {
+ max_port_a_size = std::min(max_port_a_size, SIZE(cell->getPort("\\Y")));
+ max_port_b_size = std::min(max_port_b_size, SIZE(cell->getPort("\\Y")));
+ }
+
+ bool port_a_signed = false;
+ bool port_b_signed = false;
+
+ if (max_port_a_size >= 0 && cell->type != "$shiftx")
+ run_reduce_inport(cell, 'A', max_port_a_size, port_a_signed, did_something);
+
+ if (max_port_b_size >= 0)
+ run_reduce_inport(cell, 'B', max_port_b_size, port_b_signed, did_something);
+
+
+ // Reduce size of port Y based on sizes for A and B and unused bits in Y
+
+ SigSpec sig = mi.sigmap(cell->getPort("\\Y"));
+
+ int bits_removed = 0;
+ if (port_a_signed && cell->type == "$shr") {
+ // do not reduce size of output on $shr cells with signed A inputs
+ } else {
+ while (SIZE(sig) > 0)
+ {
+ auto info = mi.query(sig[SIZE(sig)-1]);
+
+ if (info->is_output || SIZE(info->ports) > 1)
+ break;
+
+ sig.remove(SIZE(sig)-1);
+ bits_removed++;
+ }
+ }
+
+ if (cell->type.in("$pos", "$add", "$mul", "$and", "$or", "$xor"))
+ {
+ bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+
+ int a_size = 0, b_size = 0;
+ if (cell->hasPort("\\A")) a_size = SIZE(cell->getPort("\\A"));
+ if (cell->hasPort("\\B")) b_size = SIZE(cell->getPort("\\B"));
+
+ int max_y_size = std::max(a_size, b_size);
+
+ if (cell->type == "$add")
+ max_y_size++;
+
+ if (cell->type == "$mul")
+ max_y_size = a_size + b_size;
+
+ while (SIZE(sig) > 1 && SIZE(sig) > max_y_size) {
+ module->connect(sig[SIZE(sig)-1], is_signed ? sig[SIZE(sig)-2] : S0);
+ sig.remove(SIZE(sig)-1);
+ bits_removed++;
+ }
+ }
+
+ if (SIZE(sig) == 0) {
+ log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
+ module->remove(cell);
+ return;
+ }
+
+ if (bits_removed) {
+ log("Removed top %d bits (of %d) from port Y of cell %s.%s (%s).\n",
+ bits_removed, SIZE(sig) + bits_removed, log_id(module), log_id(cell), log_id(cell->type));
+ cell->setPort("\\Y", sig);
+ did_something = true;
+ }
+
+ if (did_something) {
+ cell->fixup_parameters();
+ run_cell(cell);
+ }
+ }
+
+ static int count_nontrivial_wire_attrs(RTLIL::Wire *w)
+ {
+ int count = w->attributes.size();
+ count -= w->attributes.count("\\src");
+ count -= w->attributes.count("\\unused_bits");
+ return count;
+ }
+
+ void run()
+ {
+ for (auto c : module->selected_cells())
+ work_queue_cells.insert(c);
+
+ while (!work_queue_cells.empty())
+ {
+ work_queue_bits.clear();
+ for (auto c : work_queue_cells)
+ run_cell(c);
+
+ work_queue_cells.clear();
+ for (auto bit : work_queue_bits)
+ for (auto port : mi.query_ports(bit))
+ if (module->selected(port.cell))
+ work_queue_cells.insert(port.cell);
+ }
+
+ for (auto w : module->selected_wires())
+ {
+ int unused_top_bits = 0;
+
+ if (w->port_id > 0 || count_nontrivial_wire_attrs(w) > 0)
+ continue;
+
+ for (int i = SIZE(w)-1; i >= 0; i--) {
+ SigBit bit(w, i);
+ auto info = mi.query(bit);
+ if (info && (info->is_input || info->is_output || SIZE(info->ports) > 0))
+ break;
+ unused_top_bits++;
+ }
+
+ if (0 < unused_top_bits && unused_top_bits < SIZE(w)) {
+ log("Removed top %d bits (of %d) from wire %s.%s.\n", unused_top_bits, SIZE(w), log_id(module), log_id(w));
+ Wire *nw = module->addWire(NEW_ID, w);
+ nw->width = SIZE(w) - unused_top_bits;
+ module->connect(nw, SigSpec(w).extract(0, SIZE(nw)));
+ module->swap_names(w, nw);
+ }
+ }
+ }
+};
+
+struct WreducePass : public Pass {
+ WreducePass() : Pass("wreduce", "reduce the word size of operations is possible") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" wreduce [options] [selection]\n");
+ log("\n");
+ log("This command reduces the word size of operations. For example it will replace\n");
+ log("the 32 bit adders in the following code with adders of more appropriate widths:\n");
+ log("\n");
+ log(" module test(input [3:0] a, b, c, output [7:0] y);\n");
+ log(" assign y = a + b + c + 1;\n");
+ log(" endmodule\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ WreduceConfig config;
+
+ log_header("Executing WREDUCE pass (reducing word size of cells).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ if (module->has_processes_warn())
+ continue;
+
+ WreduceWorker worker(&config, module);
+ worker.run();
+ }
+ }
+} WreducePass;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
index 57194657..f11b328f 100644
--- a/passes/proc/proc_arst.cc
+++ b/passes/proc/proc_arst.cc
@@ -28,47 +28,52 @@ extern void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count
static bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSpec ref, bool &polarity)
{
- if (signal.width != 1)
+ if (signal.size() != 1)
return false;
if (signal == ref)
return true;
- for (auto &cell_it : mod->cells) {
- RTLIL::Cell *cell = cell_it.second;
- if (cell->type == "$reduce_or" && cell->connections["\\Y"] == signal)
- return check_signal(mod, cell->connections["\\A"], ref, polarity);
- if (cell->type == "$reduce_bool" && cell->connections["\\Y"] == signal)
- return check_signal(mod, cell->connections["\\A"], ref, polarity);
- if (cell->type == "$logic_not" && cell->connections["\\Y"] == signal) {
+ for (auto cell : mod->cells())
+ {
+ if (cell->type == "$reduce_or" && cell->getPort("\\Y") == signal)
+ return check_signal(mod, cell->getPort("\\A"), ref, polarity);
+
+ if (cell->type == "$reduce_bool" && cell->getPort("\\Y") == signal)
+ return check_signal(mod, cell->getPort("\\A"), ref, polarity);
+
+ if (cell->type == "$logic_not" && cell->getPort("\\Y") == signal) {
polarity = !polarity;
- return check_signal(mod, cell->connections["\\A"], ref, polarity);
+ return check_signal(mod, cell->getPort("\\A"), ref, polarity);
}
- if (cell->type == "$not" && cell->connections["\\Y"] == signal) {
+
+ if (cell->type == "$not" && cell->getPort("\\Y") == signal) {
polarity = !polarity;
- return check_signal(mod, cell->connections["\\A"], ref, polarity);
+ return check_signal(mod, cell->getPort("\\A"), ref, polarity);
}
- if ((cell->type == "$eq" || cell->type == "$eqx") && cell->connections["\\Y"] == signal) {
- if (cell->connections["\\A"].is_fully_const()) {
- if (!cell->connections["\\A"].as_bool())
+
+ if ((cell->type == "$eq" || cell->type == "$eqx") && cell->getPort("\\Y") == signal) {
+ if (cell->getPort("\\A").is_fully_const()) {
+ if (!cell->getPort("\\A").as_bool())
polarity = !polarity;
- return check_signal(mod, cell->connections["\\B"], ref, polarity);
+ return check_signal(mod, cell->getPort("\\B"), ref, polarity);
}
- if (cell->connections["\\B"].is_fully_const()) {
- if (!cell->connections["\\B"].as_bool())
+ if (cell->getPort("\\B").is_fully_const()) {
+ if (!cell->getPort("\\B").as_bool())
polarity = !polarity;
- return check_signal(mod, cell->connections["\\A"], ref, polarity);
+ return check_signal(mod, cell->getPort("\\A"), ref, polarity);
}
}
- if ((cell->type == "$ne" || cell->type == "$nex") && cell->connections["\\Y"] == signal) {
- if (cell->connections["\\A"].is_fully_const()) {
- if (cell->connections["\\A"].as_bool())
+
+ if ((cell->type == "$ne" || cell->type == "$nex") && cell->getPort("\\Y") == signal) {
+ if (cell->getPort("\\A").is_fully_const()) {
+ if (cell->getPort("\\A").as_bool())
polarity = !polarity;
- return check_signal(mod, cell->connections["\\B"], ref, polarity);
+ return check_signal(mod, cell->getPort("\\B"), ref, polarity);
}
- if (cell->connections["\\B"].is_fully_const()) {
- if (cell->connections["\\B"].as_bool())
+ if (cell->getPort("\\B").is_fully_const()) {
+ if (cell->getPort("\\B").as_bool())
polarity = !polarity;
- return check_signal(mod, cell->connections["\\A"], ref, polarity);
+ return check_signal(mod, cell->getPort("\\A"), ref, polarity);
}
}
}
@@ -80,13 +85,13 @@ static void apply_const(RTLIL::Module *mod, const RTLIL::SigSpec rspec, RTLIL::S
{
for (auto &action : cs->actions) {
if (unknown)
- rspec.replace(action.first, RTLIL::SigSpec(RTLIL::State::Sm, action.second.width), &rval);
+ rspec.replace(action.first, RTLIL::SigSpec(RTLIL::State::Sm, action.second.size()), &rval);
else
rspec.replace(action.first, action.second, &rval);
}
for (auto sw : cs->switches) {
- if (sw->signal.width == 0) {
+ if (sw->signal.size() == 0) {
for (auto cs2 : sw->cases)
apply_const(mod, rspec, rval, cs2, const_sig, polarity, unknown);
}
@@ -156,16 +161,18 @@ restart_proc_arst:
if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn) {
bool polarity = sync->type == RTLIL::SyncType::STp;
if (check_signal(mod, root_sig, sync->signal, polarity)) {
- log("Found async reset %s in `%s.%s'.\n", log_signal(sync->signal), mod->name.c_str(), proc->name.c_str());
- sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0;
+ if (proc->syncs.size() == 1) {
+ log("Found VHDL-style edge-trigger %s in `%s.%s'.\n", log_signal(sync->signal), mod->name.c_str(), proc->name.c_str());
+ } else {
+ log("Found async reset %s in `%s.%s'.\n", log_signal(sync->signal), mod->name.c_str(), proc->name.c_str());
+ sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0;
+ }
for (auto &action : sync->actions) {
RTLIL::SigSpec rspec = action.second;
- RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.width);
- rspec.expand(), rval.expand();
- for (int i = 0; i < int(rspec.chunks.size()); i++)
- if (rspec.chunks[i].wire == NULL)
- rval.chunks[i] = rspec.chunks[i];
- rspec.optimize(), rval.optimize();
+ RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size());
+ for (int i = 0; i < SIZE(rspec); i++)
+ if (rspec[i].wire == NULL)
+ rval[i] = rspec[i];
RTLIL::SigSpec last_rval;
for (int count = 0; rval != last_rval; count++) {
last_rval = rval;
@@ -234,28 +241,28 @@ struct ProcArstPass : public Pass {
extra_args(args, argidx, design);
- for (auto &mod_it : design->modules)
- if (design->selected(mod_it.second)) {
- SigMap assign_map(mod_it.second);
- for (auto &proc_it : mod_it.second->processes) {
- if (!design->selected(mod_it.second, proc_it.second))
+ for (auto mod : design->modules())
+ if (design->selected(mod)) {
+ SigMap assign_map(mod);
+ for (auto &proc_it : mod->processes) {
+ if (!design->selected(mod, proc_it.second))
continue;
- proc_arst(mod_it.second, proc_it.second, assign_map);
- if (global_arst.empty() || mod_it.second->wires.count(global_arst) == 0)
+ proc_arst(mod, proc_it.second, assign_map);
+ if (global_arst.empty() || mod->wire(global_arst) == nullptr)
continue;
std::vector<RTLIL::SigSig> arst_actions;
for (auto sync : proc_it.second->syncs)
if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn)
for (auto &act : sync->actions) {
RTLIL::SigSpec arst_sig, arst_val;
- for (auto &chunk : act.first.chunks)
+ for (auto &chunk : act.first.chunks())
if (chunk.wire && chunk.wire->attributes.count("\\init")) {
RTLIL::SigSpec value = chunk.wire->attributes.at("\\init");
value.extend(chunk.wire->width, false);
arst_sig.append(chunk);
arst_val.append(value.extract(chunk.offset, chunk.width));
}
- if (arst_sig.width) {
+ if (arst_sig.size()) {
log("Added global reset to process %s: %s <- %s\n",
proc_it.first.c_str(), log_signal(arst_sig), log_signal(arst_val));
arst_actions.push_back(RTLIL::SigSig(arst_sig, arst_val));
@@ -264,7 +271,7 @@ struct ProcArstPass : public Pass {
if (!arst_actions.empty()) {
RTLIL::SyncRule *sync = new RTLIL::SyncRule;
sync->type = global_arst_neg ? RTLIL::SyncType::ST0 : RTLIL::SyncType::ST1;
- sync->signal = mod_it.second->wires.at(global_arst);
+ sync->signal = mod->wire(global_arst);
sync->actions = arst_actions;
proc_it.second->syncs.push_back(sync);
}
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
index 83554df9..1e3dd9ce 100644
--- a/passes/proc/proc_clean.cc
+++ b/passes/proc/proc_clean.cc
@@ -27,7 +27,7 @@ extern void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count
void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did_something, int &count, int max_depth)
{
- if (sw->signal.width > 0 && sw->signal.is_fully_const())
+ if (sw->signal.size() > 0 && sw->signal.is_fully_const())
{
int found_matching_case_idx = -1;
for (int i = 0; i < int(sw->cases.size()) && found_matching_case_idx < 0; i++)
@@ -59,7 +59,8 @@ void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did
sw->signal = RTLIL::SigSpec();
}
- if (sw->cases.size() == 1 && (sw->signal.width == 0 || sw->cases[0]->compare.empty()))
+ if (parent->switches.front() == sw && sw->cases.size() == 1 &&
+ (sw->signal.size() == 0 || sw->cases[0]->compare.empty()))
{
did_something = true;
for (auto &action : sw->cases[0]->actions)
@@ -91,7 +92,7 @@ void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did
void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int max_depth)
{
for (size_t i = 0; i < cs->actions.size(); i++) {
- if (cs->actions[i].first.width == 0) {
+ if (cs->actions[i].first.size() == 0) {
did_something = true;
cs->actions.erase(cs->actions.begin() + (i--));
}
@@ -114,7 +115,7 @@ static void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_coun
bool did_something = true;
for (size_t i = 0; i < proc->syncs.size(); i++) {
for (size_t j = 0; j < proc->syncs[i]->actions.size(); j++)
- if (proc->syncs[i]->actions[j].first.width == 0)
+ if (proc->syncs[i]->actions[j].first.size() == 0)
proc->syncs[i]->actions.erase(proc->syncs[i]->actions.begin() + (j--));
if (proc->syncs[i]->actions.size() == 0) {
delete proc->syncs[i];
@@ -149,23 +150,23 @@ struct ProcCleanPass : public Pass {
extra_args(args, 1, design);
- for (auto &mod_it : design->modules) {
- std::vector<std::string> delme;
- if (!design->selected(mod_it.second))
+ for (auto mod : design->modules()) {
+ std::vector<RTLIL::IdString> delme;
+ if (!design->selected(mod))
continue;
- for (auto &proc_it : mod_it.second->processes) {
- if (!design->selected(mod_it.second, proc_it.second))
+ for (auto &proc_it : mod->processes) {
+ if (!design->selected(mod, proc_it.second))
continue;
- proc_clean(mod_it.second, proc_it.second, total_count);
+ proc_clean(mod, proc_it.second, total_count);
if (proc_it.second->syncs.size() == 0 && proc_it.second->root_case.switches.size() == 0 &&
proc_it.second->root_case.actions.size() == 0) {
- log("Removing empty process `%s.%s'.\n", mod_it.first.c_str(), proc_it.second->name.c_str());
+ log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str());
delme.push_back(proc_it.first);
}
}
for (auto &id : delme) {
- delete mod_it.second->processes[id];
- mod_it.second->processes.erase(id);
+ delete mod->processes[id];
+ mod->processes.erase(id);
}
}
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index 2ec498fb..e69e8023 100644
--- a/passes/proc/proc_dff.cc
+++ b/passes/proc/proc_dff.cc
@@ -24,7 +24,6 @@
#include <sstream>
#include <stdlib.h>
#include <stdio.h>
-#include <assert.h>
static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
{
@@ -32,7 +31,7 @@ static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
for (auto sync : proc->syncs)
for (auto &action : sync->actions)
- if (action.first.width > 0) {
+ if (action.first.size() > 0) {
lvalue = action.first;
lvalue.sort_and_unify();
break;
@@ -44,7 +43,7 @@ static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
this_lvalue.append(action.first);
this_lvalue.sort_and_unify();
RTLIL::SigSpec common_sig = this_lvalue.extract(lvalue);
- if (common_sig.width > 0)
+ if (common_sig.size() > 0)
lvalue = common_sig;
}
@@ -54,8 +53,8 @@ static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
static void gen_dffsr_complex(RTLIL::Module *mod, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, RTLIL::SigSpec clk, bool clk_polarity,
std::map<RTLIL::SigSpec, std::set<RTLIL::SyncRule*>> &async_rules, RTLIL::Process *proc)
{
- RTLIL::SigSpec sig_sr_set = RTLIL::SigSpec(0, sig_d.width);
- RTLIL::SigSpec sig_sr_clr = RTLIL::SigSpec(0, sig_d.width);
+ RTLIL::SigSpec sig_sr_set = RTLIL::SigSpec(0, sig_d.size());
+ RTLIL::SigSpec sig_sr_clr = RTLIL::SigSpec(0, sig_d.size());
for (auto &it : async_rules)
{
@@ -72,91 +71,70 @@ static void gen_dffsr_complex(RTLIL::Module *mod, RTLIL::SigSpec sig_d, RTLIL::S
else
log_abort();
- if (sync_low_signals.width > 1) {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$reduce_or";
+ if (sync_low_signals.size() > 1) {
+ RTLIL::Cell *cell = mod->addCell(NEW_ID, "$reduce_or");
cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_low_signals.width);
+ cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_low_signals.size());
cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- cell->connections["\\A"] = sync_low_signals;
- cell->connections["\\Y"] = sync_low_signals = NEW_WIRE(mod, 1);
- mod->add(cell);
+ cell->setPort("\\A", sync_low_signals);
+ cell->setPort("\\Y", sync_low_signals = mod->addWire(NEW_ID));
}
- if (sync_low_signals.width > 0) {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$not";
+ if (sync_low_signals.size() > 0) {
+ RTLIL::Cell *cell = mod->addCell(NEW_ID, "$not");
cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_low_signals.width);
+ cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_low_signals.size());
cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- cell->connections["\\A"] = sync_low_signals;
- cell->connections["\\Y"] = NEW_WIRE(mod, 1);
- sync_high_signals.append(cell->connections["\\Y"]);
- mod->add(cell);
+ cell->setPort("\\A", sync_low_signals);
+ cell->setPort("\\Y", mod->addWire(NEW_ID));
+ sync_high_signals.append(cell->getPort("\\Y"));
}
- if (sync_high_signals.width > 1) {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$reduce_or";
+ if (sync_high_signals.size() > 1) {
+ RTLIL::Cell *cell = mod->addCell(NEW_ID, "$reduce_or");
cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_high_signals.width);
+ cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_high_signals.size());
cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- cell->connections["\\A"] = sync_high_signals;
- cell->connections["\\Y"] = sync_high_signals = NEW_WIRE(mod, 1);
- mod->add(cell);
+ cell->setPort("\\A", sync_high_signals);
+ cell->setPort("\\Y", sync_high_signals = mod->addWire(NEW_ID));
}
- RTLIL::Cell *inv_cell = new RTLIL::Cell;
- inv_cell->name = NEW_ID;
- inv_cell->type = "$not";
+ RTLIL::Cell *inv_cell = mod->addCell(NEW_ID, "$not");
inv_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- inv_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig_d.width);
- inv_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(sig_d.width);
- inv_cell->connections["\\A"] = sync_value;
- inv_cell->connections["\\Y"] = sync_value_inv = NEW_WIRE(mod, sig_d.width);
- mod->add(inv_cell);
-
- RTLIL::Cell *mux_set_cell = new RTLIL::Cell;
- mux_set_cell->name = NEW_ID;
- mux_set_cell->type = "$mux";
- mux_set_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.width);
- mux_set_cell->connections["\\A"] = sig_sr_set;
- mux_set_cell->connections["\\B"] = sync_value;
- mux_set_cell->connections["\\S"] = sync_high_signals;
- mux_set_cell->connections["\\Y"] = sig_sr_set = NEW_WIRE(mod, sig_d.width);
- mod->add(mux_set_cell);
-
- RTLIL::Cell *mux_clr_cell = new RTLIL::Cell;
- mux_clr_cell->name = NEW_ID;
- mux_clr_cell->type = "$mux";
- mux_clr_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.width);
- mux_clr_cell->connections["\\A"] = sig_sr_clr;
- mux_clr_cell->connections["\\B"] = sync_value_inv;
- mux_clr_cell->connections["\\S"] = sync_high_signals;
- mux_clr_cell->connections["\\Y"] = sig_sr_clr = NEW_WIRE(mod, sig_d.width);
- mod->add(mux_clr_cell);
+ inv_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig_d.size());
+ inv_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(sig_d.size());
+ inv_cell->setPort("\\A", sync_value);
+ inv_cell->setPort("\\Y", sync_value_inv = mod->addWire(NEW_ID, sig_d.size()));
+
+ RTLIL::Cell *mux_set_cell = mod->addCell(NEW_ID, "$mux");
+ mux_set_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.size());
+ mux_set_cell->setPort("\\A", sig_sr_set);
+ mux_set_cell->setPort("\\B", sync_value);
+ mux_set_cell->setPort("\\S", sync_high_signals);
+ mux_set_cell->setPort("\\Y", sig_sr_set = mod->addWire(NEW_ID, sig_d.size()));
+
+ RTLIL::Cell *mux_clr_cell = mod->addCell(NEW_ID, "$mux");
+ mux_clr_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.size());
+ mux_clr_cell->setPort("\\A", sig_sr_clr);
+ mux_clr_cell->setPort("\\B", sync_value_inv);
+ mux_clr_cell->setPort("\\S", sync_high_signals);
+ mux_clr_cell->setPort("\\Y", sig_sr_clr = mod->addWire(NEW_ID, sig_d.size()));
}
std::stringstream sstr;
- sstr << "$procdff$" << (RTLIL::autoidx++);
+ sstr << "$procdff$" << (autoidx++);
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = sstr.str();
- cell->type = "$dffsr";
+ RTLIL::Cell *cell = mod->addCell(sstr.str(), "$dffsr");
cell->attributes = proc->attributes;
- cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.width);
+ cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.size());
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1);
cell->parameters["\\SET_POLARITY"] = RTLIL::Const(true, 1);
cell->parameters["\\CLR_POLARITY"] = RTLIL::Const(true, 1);
- cell->connections["\\D"] = sig_d;
- cell->connections["\\Q"] = sig_q;
- cell->connections["\\CLK"] = clk;
- cell->connections["\\SET"] = sig_sr_set;
- cell->connections["\\CLR"] = sig_sr_clr;
- mod->add(cell);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ cell->setPort("\\CLK", clk);
+ cell->setPort("\\SET", sig_sr_set);
+ cell->setPort("\\CLR", sig_sr_clr);
log(" created %s cell `%s' with %s edge clock and multiple level-sensitive resets.\n",
cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative");
@@ -166,56 +144,44 @@ static void gen_dffsr(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::SigSpec
bool clk_polarity, bool set_polarity, RTLIL::SigSpec clk, RTLIL::SigSpec set, RTLIL::Process *proc)
{
std::stringstream sstr;
- sstr << "$procdff$" << (RTLIL::autoidx++);
+ sstr << "$procdff$" << (autoidx++);
- RTLIL::SigSpec sig_set_inv = NEW_WIRE(mod, sig_in.width);
- RTLIL::SigSpec sig_sr_set = NEW_WIRE(mod, sig_in.width);
- RTLIL::SigSpec sig_sr_clr = NEW_WIRE(mod, sig_in.width);
+ RTLIL::SigSpec sig_set_inv = mod->addWire(NEW_ID, sig_in.size());
+ RTLIL::SigSpec sig_sr_set = mod->addWire(NEW_ID, sig_in.size());
+ RTLIL::SigSpec sig_sr_clr = mod->addWire(NEW_ID, sig_in.size());
- RTLIL::Cell *inv_set = new RTLIL::Cell;
- inv_set->name = NEW_ID;
- inv_set->type = "$not";
+ RTLIL::Cell *inv_set = mod->addCell(NEW_ID, "$not");
inv_set->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- inv_set->parameters["\\A_WIDTH"] = RTLIL::Const(sig_in.width);
- inv_set->parameters["\\Y_WIDTH"] = RTLIL::Const(sig_in.width);
- inv_set->connections["\\A"] = sig_set;
- inv_set->connections["\\Y"] = sig_set_inv;
- mod->add(inv_set);
-
- RTLIL::Cell *mux_sr_set = new RTLIL::Cell;
- mux_sr_set->name = NEW_ID;
- mux_sr_set->type = "$mux";
- mux_sr_set->parameters["\\WIDTH"] = RTLIL::Const(sig_in.width);
- mux_sr_set->connections[set_polarity ? "\\A" : "\\B"] = RTLIL::Const(0, sig_in.width);
- mux_sr_set->connections[set_polarity ? "\\B" : "\\A"] = sig_set;
- mux_sr_set->connections["\\Y"] = sig_sr_set;
- mux_sr_set->connections["\\S"] = set;
- mod->add(mux_sr_set);
-
- RTLIL::Cell *mux_sr_clr = new RTLIL::Cell;
- mux_sr_clr->name = NEW_ID;
- mux_sr_clr->type = "$mux";
- mux_sr_clr->parameters["\\WIDTH"] = RTLIL::Const(sig_in.width);
- mux_sr_clr->connections[set_polarity ? "\\A" : "\\B"] = RTLIL::Const(0, sig_in.width);
- mux_sr_clr->connections[set_polarity ? "\\B" : "\\A"] = sig_set_inv;
- mux_sr_clr->connections["\\Y"] = sig_sr_clr;
- mux_sr_clr->connections["\\S"] = set;
- mod->add(mux_sr_clr);
-
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = sstr.str();
- cell->type = "$dffsr";
+ inv_set->parameters["\\A_WIDTH"] = RTLIL::Const(sig_in.size());
+ inv_set->parameters["\\Y_WIDTH"] = RTLIL::Const(sig_in.size());
+ inv_set->setPort("\\A", sig_set);
+ inv_set->setPort("\\Y", sig_set_inv);
+
+ RTLIL::Cell *mux_sr_set = mod->addCell(NEW_ID, "$mux");
+ mux_sr_set->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size());
+ mux_sr_set->setPort(set_polarity ? "\\A" : "\\B", RTLIL::Const(0, sig_in.size()));
+ mux_sr_set->setPort(set_polarity ? "\\B" : "\\A", sig_set);
+ mux_sr_set->setPort("\\Y", sig_sr_set);
+ mux_sr_set->setPort("\\S", set);
+
+ RTLIL::Cell *mux_sr_clr = mod->addCell(NEW_ID, "$mux");
+ mux_sr_clr->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size());
+ mux_sr_clr->setPort(set_polarity ? "\\A" : "\\B", RTLIL::Const(0, sig_in.size()));
+ mux_sr_clr->setPort(set_polarity ? "\\B" : "\\A", sig_set_inv);
+ mux_sr_clr->setPort("\\Y", sig_sr_clr);
+ mux_sr_clr->setPort("\\S", set);
+
+ RTLIL::Cell *cell = mod->addCell(sstr.str(), "$dffsr");
cell->attributes = proc->attributes;
- cell->parameters["\\WIDTH"] = RTLIL::Const(sig_in.width);
+ cell->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size());
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1);
cell->parameters["\\SET_POLARITY"] = RTLIL::Const(true, 1);
cell->parameters["\\CLR_POLARITY"] = RTLIL::Const(true, 1);
- cell->connections["\\D"] = sig_in;
- cell->connections["\\Q"] = sig_out;
- cell->connections["\\CLK"] = clk;
- cell->connections["\\SET"] = sig_sr_set;
- cell->connections["\\CLR"] = sig_sr_clr;
- mod->add(cell);
+ cell->setPort("\\D", sig_in);
+ cell->setPort("\\Q", sig_out);
+ cell->setPort("\\CLK", clk);
+ cell->setPort("\\SET", sig_sr_set);
+ cell->setPort("\\CLR", sig_sr_clr);
log(" created %s cell `%s' with %s edge clock and %s level non-const reset.\n", cell->type.c_str(), cell->name.c_str(),
clk_polarity ? "positive" : "negative", set_polarity ? "positive" : "negative");
@@ -225,26 +191,23 @@ static void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_
bool clk_polarity, bool arst_polarity, RTLIL::SigSpec clk, RTLIL::SigSpec *arst, RTLIL::Process *proc)
{
std::stringstream sstr;
- sstr << "$procdff$" << (RTLIL::autoidx++);
+ sstr << "$procdff$" << (autoidx++);
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = sstr.str();
- cell->type = arst ? "$adff" : "$dff";
+ RTLIL::Cell *cell = mod->addCell(sstr.str(), arst ? "$adff" : "$dff");
cell->attributes = proc->attributes;
- mod->cells[cell->name] = cell;
- cell->parameters["\\WIDTH"] = RTLIL::Const(sig_in.width);
+ cell->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size());
if (arst) {
cell->parameters["\\ARST_POLARITY"] = RTLIL::Const(arst_polarity, 1);
cell->parameters["\\ARST_VALUE"] = val_rst;
}
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1);
- cell->connections["\\D"] = sig_in;
- cell->connections["\\Q"] = sig_out;
+ cell->setPort("\\D", sig_in);
+ cell->setPort("\\Q", sig_out);
if (arst)
- cell->connections["\\ARST"] = *arst;
- cell->connections["\\CLK"] = clk;
+ cell->setPort("\\ARST", *arst);
+ cell->setPort("\\CLK", clk);
log(" created %s cell `%s' with %s edge clock", cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative");
if (arst)
@@ -259,14 +222,14 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
RTLIL::SigSpec sig = find_any_lvalue(proc);
bool free_sync_level = false;
- if (sig.width == 0)
+ if (sig.size() == 0)
break;
log("Creating register for signal `%s.%s' using process `%s.%s'.\n",
mod->name.c_str(), log_signal(sig), mod->name.c_str(), proc->name.c_str());
- RTLIL::SigSpec insig = RTLIL::SigSpec(RTLIL::State::Sz, sig.width);
- RTLIL::SigSpec rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.width);
+ RTLIL::SigSpec insig = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
+ RTLIL::SigSpec rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
RTLIL::SyncRule *sync_level = NULL;
RTLIL::SyncRule *sync_edge = NULL;
RTLIL::SyncRule *sync_always = NULL;
@@ -276,16 +239,16 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
for (auto sync : proc->syncs)
for (auto &action : sync->actions)
{
- if (action.first.extract(sig).width == 0)
+ if (action.first.extract(sig).size() == 0)
continue;
if (sync->type == RTLIL::SyncType::ST0 || sync->type == RTLIL::SyncType::ST1) {
if (sync_level != NULL && sync_level != sync) {
// log_error("Multiple level sensitive events found for this signal!\n");
many_async_rules[rstval].insert(sync_level);
- rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.width);
+ rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
}
- rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.width);
+ rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
sig.replace(action.first, action.second, &rstval);
sync_level = sync;
}
@@ -315,7 +278,7 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
{
sync_level = new RTLIL::SyncRule;
sync_level->type = RTLIL::SyncType::ST1;
- sync_level->signal = NEW_WIRE(mod, 1);
+ sync_level->signal = mod->addWire(NEW_ID);
sync_level->actions.push_back(RTLIL::SigSig(sig, rstval));
free_sync_level = true;
@@ -324,26 +287,23 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
inputs.append(it->signal);
compare.append(it->type == RTLIL::SyncType::ST0 ? RTLIL::State::S1 : RTLIL::State::S0);
}
- assert(inputs.width == compare.width);
+ log_assert(inputs.size() == compare.size());
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$ne";
+ RTLIL::Cell *cell = mod->addCell(NEW_ID, "$ne");
cell->parameters["\\A_SIGNED"] = RTLIL::Const(false, 1);
cell->parameters["\\B_SIGNED"] = RTLIL::Const(false, 1);
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(inputs.width);
- cell->parameters["\\B_WIDTH"] = RTLIL::Const(inputs.width);
+ cell->parameters["\\A_WIDTH"] = RTLIL::Const(inputs.size());
+ cell->parameters["\\B_WIDTH"] = RTLIL::Const(inputs.size());
cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- cell->connections["\\A"] = inputs;
- cell->connections["\\B"] = compare;
- cell->connections["\\Y"] = sync_level->signal;
- mod->add(cell);
+ cell->setPort("\\A", inputs);
+ cell->setPort("\\B", compare);
+ cell->setPort("\\Y", sync_level->signal);
many_async_rules.clear();
}
else
{
- rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.width);
+ rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
sync_level = NULL;
}
}
@@ -352,15 +312,16 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
ce.assign_map.apply(rstval);
ce.assign_map.apply(sig);
- insig.optimize();
- rstval.optimize();
- sig.optimize();
+ if (rstval == sig) {
+ rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
+ sync_level = NULL;
+ }
if (sync_always) {
if (sync_edge || sync_level || many_async_rules.size() > 0)
log_error("Mixed always event with edge and/or level sensitive events!\n");
log(" created direct connection (no actual register cell created).\n");
- mod->connections.push_back(RTLIL::SigSig(sig, insig));
+ mod->connect(RTLIL::SigSig(sig, insig));
continue;
}
@@ -381,7 +342,7 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
sync_edge->signal, sync_level->signal, proc);
}
else
- gen_dff(mod, insig, rstval.chunks[0].data, sig,
+ gen_dff(mod, insig, rstval.as_const(), sig,
sync_edge->type == RTLIL::SyncType::STp,
sync_level && sync_level->type == RTLIL::SyncType::ST1,
sync_edge->signal, sync_level ? &sync_level->signal : NULL, proc);
@@ -409,12 +370,12 @@ struct ProcDffPass : public Pass {
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
- if (design->selected(mod_it.second)) {
- ConstEval ce(mod_it.second);
- for (auto &proc_it : mod_it.second->processes)
- if (design->selected(mod_it.second, proc_it.second))
- proc_dff(mod_it.second, proc_it.second, ce);
+ for (auto mod : design->modules())
+ if (design->selected(mod)) {
+ ConstEval ce(mod);
+ for (auto &proc_it : mod->processes)
+ if (design->selected(mod, proc_it.second))
+ proc_dff(mod, proc_it.second, ce);
}
}
} ProcDffPass;
diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc
index fca20fda..c72840c0 100644
--- a/passes/proc/proc_init.cc
+++ b/passes/proc/proc_init.cc
@@ -25,10 +25,9 @@
static void proc_get_const(RTLIL::SigSpec &sig, RTLIL::CaseRule &rule)
{
- assert(rule.compare.size() == 0);
+ log_assert(rule.compare.size() == 0);
while (1) {
- sig.optimize();
RTLIL::SigSpec tmp = sig;
for (auto &it : rule.actions)
tmp.replace(it.first, it.second);
@@ -53,23 +52,21 @@ static void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
RTLIL::SigSpec lhs = action.first;
RTLIL::SigSpec rhs = action.second;
- lhs.optimize();
proc_get_const(rhs, proc->root_case);
if (!rhs.is_fully_const())
log_cmd_error("Failed to get a constant init value for %s: %s\n", log_signal(lhs), log_signal(rhs));
int offset = 0;
- for (size_t i = 0; i < lhs.chunks.size(); i++) {
- if (lhs.chunks[i].wire == NULL)
- continue;
- RTLIL::Wire *wire = lhs.chunks[i].wire;
- RTLIL::SigSpec value = rhs.extract(offset, lhs.chunks[i].width);
- if (value.width != wire->width)
- log_cmd_error("Init value is not for the entire wire: %s = %s\n", log_signal(lhs.chunks[i]), log_signal(value));
- log(" Setting init value: %s = %s\n", log_signal(wire), log_signal(value));
- wire->attributes["\\init"] = value.as_const();
- offset += wire->width;
+ for (auto &lhs_c : lhs.chunks()) {
+ if (lhs_c.wire != NULL) {
+ RTLIL::SigSpec value = rhs.extract(offset, lhs_c.width);
+ if (value.size() != lhs_c.wire->width)
+ log_cmd_error("Init value is not for the entire wire: %s = %s\n", log_signal(lhs_c), log_signal(value));
+ log(" Setting init value: %s = %s\n", log_signal(lhs_c.wire), log_signal(value));
+ lhs_c.wire->attributes["\\init"] = value.as_const();
+ }
+ offset += lhs_c.width;
}
}
}
@@ -104,11 +101,11 @@ struct ProcInitPass : public Pass {
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
- if (design->selected(mod_it.second))
- for (auto &proc_it : mod_it.second->processes)
- if (design->selected(mod_it.second, proc_it.second))
- proc_init(mod_it.second, proc_it.second);
+ for (auto mod : design->modules())
+ if (design->selected(mod))
+ for (auto &proc_it : mod->processes)
+ if (design->selected(mod, proc_it.second))
+ proc_init(mod, proc_it.second);
}
} ProcInitPass;
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
index 9b2f8388..c00b00a2 100644
--- a/passes/proc/proc_mux.cc
+++ b/passes/proc/proc_mux.cc
@@ -23,19 +23,18 @@
#include <sstream>
#include <stdlib.h>
#include <stdio.h>
-#include <assert.h>
static RTLIL::SigSpec find_any_lvalue(const RTLIL::CaseRule *cs)
{
for (auto &action : cs->actions) {
- if (action.first.width)
+ if (action.first.size())
return action.first;
}
for (auto sw : cs->switches)
for (auto cs2 : sw->cases) {
RTLIL::SigSpec sig = find_any_lvalue(cs2);
- if (sig.width)
+ if (sig.size())
return sig;
}
@@ -46,7 +45,7 @@ static void extract_core_signal(const RTLIL::CaseRule *cs, RTLIL::SigSpec &sig)
{
for (auto &action : cs->actions) {
RTLIL::SigSpec lvalue = action.first.extract(sig);
- if (lvalue.width)
+ if (lvalue.size())
sig = lvalue;
}
@@ -58,56 +57,44 @@ static void extract_core_signal(const RTLIL::CaseRule *cs, RTLIL::SigSpec &sig)
static RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw)
{
std::stringstream sstr;
- sstr << "$procmux$" << (RTLIL::autoidx++);
+ sstr << "$procmux$" << (autoidx++);
- RTLIL::Wire *cmp_wire = new RTLIL::Wire;
- cmp_wire->name = sstr.str() + "_CMP";
- cmp_wire->width = 0;
- mod->wires[cmp_wire->name] = cmp_wire;
+ RTLIL::Wire *cmp_wire = mod->addWire(sstr.str() + "_CMP", 0);
for (auto comp : compare)
{
RTLIL::SigSpec sig = signal;
- sig.expand();
- comp.expand();
// get rid of don't-care bits
- assert(sig.width == comp.width);
- for (int i = 0; i < comp.width; i++)
- if (comp.chunks[i].wire == NULL && comp.chunks[i].data.bits[0] == RTLIL::State::Sa) {
- sig.remove(i, 1);
- comp.remove(i--, 1);
+ log_assert(sig.size() == comp.size());
+ for (int i = 0; i < comp.size(); i++)
+ if (comp[i] == RTLIL::State::Sa) {
+ sig.remove(i);
+ comp.remove(i--);
}
- if (comp.width == 0)
+ if (comp.size() == 0)
return RTLIL::SigSpec();
- sig.optimize();
- comp.optimize();
- if (sig.width == 1 && comp == RTLIL::SigSpec(1,1))
+ if (sig.size() == 1 && comp == RTLIL::SigSpec(1,1))
{
- mod->connections.push_back(RTLIL::SigSig(RTLIL::SigSpec(cmp_wire, 1, cmp_wire->width++), sig));
+ mod->connect(RTLIL::SigSig(RTLIL::SigSpec(cmp_wire, cmp_wire->width++), sig));
}
else
{
// create compare cell
- RTLIL::Cell *eq_cell = new RTLIL::Cell;
- std::stringstream sstr2;
- sstr2 << sstr.str() << "_CMP" << cmp_wire->width;
- eq_cell->name = sstr2.str();
- eq_cell->type = "$eq";
+ RTLIL::Cell *eq_cell = mod->addCell(stringf("%s_CMP%d", sstr.str().c_str(), cmp_wire->width), "$eq");
eq_cell->attributes = sw->attributes;
- mod->cells[eq_cell->name] = eq_cell;
eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(0);
- eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig.width);
- eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(comp.width);
+ eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig.size());
+ eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(comp.size());
eq_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- eq_cell->connections["\\A"] = sig;
- eq_cell->connections["\\B"] = comp;
- eq_cell->connections["\\Y"] = RTLIL::SigSpec(cmp_wire, 1, cmp_wire->width++);
+ eq_cell->setPort("\\A", sig);
+ eq_cell->setPort("\\B", comp);
+ eq_cell->setPort("\\Y", RTLIL::SigSpec(cmp_wire, cmp_wire->width++));
}
}
@@ -118,24 +105,18 @@ static RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal,
}
else
{
- ctrl_wire = new RTLIL::Wire;
- ctrl_wire->name = sstr.str() + "_CTRL";
- ctrl_wire->width = 1;
- mod->wires[ctrl_wire->name] = ctrl_wire;
+ ctrl_wire = mod->addWire(sstr.str() + "_CTRL");
// reduce cmp vector to one logic signal
- RTLIL::Cell *any_cell = new RTLIL::Cell;
- any_cell->name = sstr.str() + "_ANY";
- any_cell->type = "$reduce_or";
+ RTLIL::Cell *any_cell = mod->addCell(sstr.str() + "_ANY", "$reduce_or");
any_cell->attributes = sw->attributes;
- mod->cells[any_cell->name] = any_cell;
any_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
any_cell->parameters["\\A_WIDTH"] = RTLIL::Const(cmp_wire->width);
any_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- any_cell->connections["\\A"] = cmp_wire;
- any_cell->connections["\\Y"] = RTLIL::SigSpec(ctrl_wire);
+ any_cell->setPort("\\A", cmp_wire);
+ any_cell->setPort("\\Y", RTLIL::SigSpec(ctrl_wire));
}
return RTLIL::SigSpec(ctrl_wire);
@@ -143,10 +124,10 @@ static RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal,
static RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw)
{
- assert(when_signal.width == else_signal.width);
+ log_assert(when_signal.size() == else_signal.size());
std::stringstream sstr;
- sstr << "$procmux$" << (RTLIL::autoidx++);
+ sstr << "$procmux$" << (autoidx++);
// the trivial cases
if (compare.size() == 0 || when_signal == else_signal)
@@ -154,28 +135,22 @@ static RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal,
// compare results
RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw);
- if (ctrl_sig.width == 0)
+ if (ctrl_sig.size() == 0)
return when_signal;
- assert(ctrl_sig.width == 1);
+ log_assert(ctrl_sig.size() == 1);
// prepare multiplexer output signal
- RTLIL::Wire *result_wire = new RTLIL::Wire;
- result_wire->name = sstr.str() + "_Y";
- result_wire->width = when_signal.width;
- mod->wires[result_wire->name] = result_wire;
+ RTLIL::Wire *result_wire = mod->addWire(sstr.str() + "_Y", when_signal.size());
// create the multiplexer itself
- RTLIL::Cell *mux_cell = new RTLIL::Cell;
- mux_cell->name = sstr.str();
- mux_cell->type = "$mux";
+ RTLIL::Cell *mux_cell = mod->addCell(sstr.str(), "$mux");
mux_cell->attributes = sw->attributes;
- mod->cells[mux_cell->name] = mux_cell;
- mux_cell->parameters["\\WIDTH"] = RTLIL::Const(when_signal.width);
- mux_cell->connections["\\A"] = else_signal;
- mux_cell->connections["\\B"] = when_signal;
- mux_cell->connections["\\S"] = ctrl_sig;
- mux_cell->connections["\\Y"] = RTLIL::SigSpec(result_wire);
+ mux_cell->parameters["\\WIDTH"] = RTLIL::Const(when_signal.size());
+ mux_cell->setPort("\\A", else_signal);
+ mux_cell->setPort("\\B", when_signal);
+ mux_cell->setPort("\\S", ctrl_sig);
+ mux_cell->setPort("\\Y", RTLIL::SigSpec(result_wire));
last_mux_cell = mux_cell;
return RTLIL::SigSpec(result_wire);
@@ -183,15 +158,22 @@ static RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal,
static void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw)
{
- assert(last_mux_cell != NULL);
- assert(when_signal.width == last_mux_cell->connections["\\A"].width);
+ log_assert(last_mux_cell != NULL);
+ log_assert(when_signal.size() == last_mux_cell->getPort("\\A").size());
RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw);
- assert(ctrl_sig.width == 1);
+ log_assert(ctrl_sig.size() == 1);
last_mux_cell->type = "$pmux";
- last_mux_cell->connections["\\S"].append(ctrl_sig);
- last_mux_cell->connections["\\B"].append(when_signal);
- last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->connections["\\S"].width;
+
+ RTLIL::SigSpec new_s = last_mux_cell->getPort("\\S");
+ new_s.append(ctrl_sig);
+ last_mux_cell->setPort("\\S", new_s);
+
+ RTLIL::SigSpec new_b = last_mux_cell->getPort("\\B");
+ new_b.append(when_signal);
+ last_mux_cell->setPort("\\B", new_b);
+
+ last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->getPort("\\S").size();
}
static RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval)
@@ -208,7 +190,7 @@ static RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs
// detect groups of parallel cases
std::vector<int> pgroups(sw->cases.size());
if (!sw->get_bool_attribute("\\parallel_case")) {
- BitPatternPool pool(sw->signal.width);
+ BitPatternPool pool(sw->signal.size());
bool extra_group_for_next_case = false;
for (size_t i = 0; i < sw->cases.size(); i++) {
RTLIL::CaseRule *cs2 = sw->cases[i];
@@ -224,7 +206,7 @@ static RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs
if (cs2->compare.empty())
pgroups[i] = pgroups[i-1]+1;
if (pgroups[i] != pgroups[i-1])
- pool = BitPatternPool(sw->signal.width);
+ pool = BitPatternPool(sw->signal.size());
}
for (auto pat : cs2->compare)
if (!pat.is_fully_const())
@@ -258,7 +240,7 @@ static void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
{
RTLIL::SigSpec sig = find_any_lvalue(&proc->root_case);
- if (sig.width == 0)
+ if (sig.size() == 0)
break;
if (first) {
@@ -270,8 +252,8 @@ static void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
log(" creating decoder for signal `%s'.\n", log_signal(sig));
- RTLIL::SigSpec value = signal_to_mux_tree(mod, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.width));
- mod->connections.push_back(RTLIL::SigSig(sig, value));
+ RTLIL::SigSpec value = signal_to_mux_tree(mod, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.size()));
+ mod->connect(RTLIL::SigSig(sig, value));
}
}
@@ -293,11 +275,11 @@ struct ProcMuxPass : public Pass {
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
- if (design->selected(mod_it.second))
- for (auto &proc_it : mod_it.second->processes)
- if (design->selected(mod_it.second, proc_it.second))
- proc_mux(mod_it.second, proc_it.second);
+ for (auto mod : design->modules())
+ if (design->selected(mod))
+ for (auto &proc_it : mod->processes)
+ if (design->selected(mod, proc_it.second))
+ proc_mux(mod, proc_it.second);
}
} ProcMuxPass;
diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc
index d5fbef0d..fe3532da 100644
--- a/passes/proc/proc_rmdead.cc
+++ b/passes/proc/proc_rmdead.cc
@@ -23,7 +23,6 @@
#include <sstream>
#include <stdlib.h>
#include <stdio.h>
-#include <assert.h>
#include <set>
static void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
@@ -32,7 +31,7 @@ static void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
for (size_t i = 0; i < sw->cases.size(); i++)
{
- bool is_default = sw->cases[i]->compare.size() == 0 && !pool.empty();
+ bool is_default = SIZE(sw->cases[i]->compare) == 0 && (!pool.empty() || SIZE(sw->signal) == 0);
for (size_t j = 0; j < sw->cases[i]->compare.size(); j++) {
RTLIL::SigSpec sig = sw->cases[i]->compare[j];
@@ -79,18 +78,18 @@ struct ProcRmdeadPass : public Pass {
extra_args(args, 1, design);
int total_counter = 0;
- for (auto &mod_it : design->modules) {
- if (!design->selected(mod_it.second))
+ for (auto mod : design->modules()) {
+ if (!design->selected(mod))
continue;
- for (auto &proc_it : mod_it.second->processes) {
- if (!design->selected(mod_it.second, proc_it.second))
+ for (auto &proc_it : mod->processes) {
+ if (!design->selected(mod, proc_it.second))
continue;
int counter = 0;
for (auto switch_it : proc_it.second->root_case.switches)
proc_rmdead(switch_it, counter);
if (counter > 0)
log("Removed %d dead cases from process %s in module %s.\n", counter,
- proc_it.first.c_str(), mod_it.first.c_str());
+ proc_it.first.c_str(), log_id(mod));
total_counter += counter;
}
}
diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc
index 5c38cc2c..f07ad943 100644
--- a/passes/sat/eval.cc
+++ b/passes/sat/eval.cc
@@ -44,7 +44,7 @@ struct BruteForceEquivChecker
void run_checker(RTLIL::SigSpec &inputs)
{
- if (inputs.width < mod1_inputs.width) {
+ if (inputs.size() < mod1_inputs.size()) {
RTLIL::SigSpec inputs0 = inputs, inputs1 = inputs;
inputs0.append(RTLIL::Const(0, 1));
inputs1.append(RTLIL::Const(1, 1));
@@ -53,8 +53,6 @@ struct BruteForceEquivChecker
return;
}
- inputs.optimize();
-
ConstEval ce1(mod1), ce2(mod2);
ce1.set(mod1_inputs, inputs.as_const());
ce2.set(mod2_inputs, inputs.as_const());
@@ -70,11 +68,9 @@ struct BruteForceEquivChecker
log_signal(undef2), log_signal(mod1_inputs), log_signal(inputs));
if (ignore_x_mod1) {
- sig1.expand(), sig2.expand();
- for (size_t i = 0; i < sig1.chunks.size(); i++)
- if (sig1.chunks.at(i) == RTLIL::SigChunk(RTLIL::State::Sx))
- sig2.chunks.at(i) = RTLIL::SigChunk(RTLIL::State::Sx);
- sig1.optimize(), sig2.optimize();
+ for (int i = 0; i < SIZE(sig1); i++)
+ if (sig1[i] == RTLIL::State::Sx)
+ sig2[i] = RTLIL::State::Sx;
}
if (sig1 != sig2) {
@@ -91,16 +87,16 @@ struct BruteForceEquivChecker
mod1(mod1), mod2(mod2), counter(0), errors(0), ignore_x_mod1(ignore_x_mod1)
{
log("Checking for equivialence (brute-force): %s vs %s\n", mod1->name.c_str(), mod2->name.c_str());
- for (auto &w : mod1->wires)
+ for (auto &w : mod1->wires_)
{
RTLIL::Wire *wire1 = w.second;
if (wire1->port_id == 0)
continue;
- if (mod2->wires.count(wire1->name) == 0)
+ if (mod2->wires_.count(wire1->name) == 0)
log_cmd_error("Port %s in module 1 has no counterpart in module 2!\n", wire1->name.c_str());
- RTLIL::Wire *wire2 = mod2->wires.at(wire1->name);
+ RTLIL::Wire *wire2 = mod2->wires_.at(wire1->name);
if (wire1->width != wire2->width || wire1->port_input != wire2->port_input || wire1->port_output != wire2->port_output)
log_cmd_error("Port %s in module 1 does not match its counterpart in module 2!\n", wire1->name.c_str());
@@ -151,17 +147,17 @@ struct VlogHammerReporter
SatGen satgen(&ez, &sigmap);
satgen.model_undef = model_undef;
- for (auto &c : module->cells)
+ for (auto &c : module->cells_)
if (!satgen.importCell(c.second))
log_error("Failed to import cell %s (type %s) to SAT database.\n", RTLIL::id2cstr(c.first), RTLIL::id2cstr(c.second->type));
ez.assume(satgen.signals_eq(recorded_set_vars, recorded_set_vals));
- std::vector<int> y_vec = satgen.importDefSigSpec(module->wires.at("\\y"));
+ std::vector<int> y_vec = satgen.importDefSigSpec(module->wires_.at("\\y"));
std::vector<bool> y_values;
if (model_undef) {
- std::vector<int> y_undef_vec = satgen.importUndefSigSpec(module->wires.at("\\y"));
+ std::vector<int> y_undef_vec = satgen.importUndefSigSpec(module->wires_.at("\\y"));
y_vec.insert(y_vec.end(), y_undef_vec.begin(), y_undef_vec.end());
}
@@ -171,12 +167,11 @@ struct VlogHammerReporter
if (!ez.solve(y_vec, y_values))
log_error("Failed to find solution to SAT problem.\n");
- expected_y.expand();
- for (int i = 0; i < expected_y.width; i++) {
+ for (int i = 0; i < expected_y.size(); i++) {
RTLIL::State solution_bit = y_values.at(i) ? RTLIL::State::S1 : RTLIL::State::S0;
- RTLIL::State expected_bit = expected_y.chunks.at(i).data.bits.at(0);
+ RTLIL::State expected_bit = expected_y[i].data;
if (model_undef) {
- if (y_values.at(expected_y.width+i))
+ if (y_values.at(expected_y.size()+i))
solution_bit = RTLIL::State::Sx;
} else {
if (expected_bit == RTLIL::State::Sx)
@@ -184,17 +179,16 @@ struct VlogHammerReporter
}
if (solution_bit != expected_bit) {
std::string sat_bits, rtl_bits;
- for (int k = expected_y.width-1; k >= 0; k--) {
- if (model_undef && y_values.at(expected_y.width+k))
+ for (int k = expected_y.size()-1; k >= 0; k--) {
+ if (model_undef && y_values.at(expected_y.size()+k))
sat_bits += "x";
else
sat_bits += y_values.at(k) ? "1" : "0";
- rtl_bits += expected_y.chunks.at(k).data.bits.at(0) == RTLIL::State::Sx ? "x" :
- expected_y.chunks.at(k).data.bits.at(0) == RTLIL::State::S1 ? "1" : "0";
+ rtl_bits += expected_y[k] == RTLIL::State::Sx ? "x" : expected_y[k] == RTLIL::State::S1 ? "1" : "0";
}
log_error("Found error in SAT model: y[%d] = %s, should be %s:\n SAT: %s\n RTL: %s\n %*s^\n",
int(i), log_signal(solution_bit), log_signal(expected_bit),
- sat_bits.c_str(), rtl_bits.c_str(), expected_y.width-i-1, "");
+ sat_bits.c_str(), rtl_bits.c_str(), expected_y.size()-i-1, "");
}
}
@@ -203,16 +197,16 @@ struct VlogHammerReporter
std::vector<int> cmp_vars;
std::vector<bool> cmp_vals;
- std::vector<bool> y_undef(y_values.begin() + expected_y.width, y_values.end());
+ std::vector<bool> y_undef(y_values.begin() + expected_y.size(), y_values.end());
- for (int i = 0; i < expected_y.width; i++)
+ for (int i = 0; i < expected_y.size(); i++)
if (y_undef.at(i))
{
log(" Toggling undef bit %d to test undef gating.\n", i);
if (!ez.solve(y_vec, y_values, ez.IFF(y_vec.at(i), y_values.at(i) ? ez.FALSE : ez.TRUE)))
log_error("Failed to find solution with toggled bit!\n");
- cmp_vars.push_back(y_vec.at(expected_y.width + i));
+ cmp_vars.push_back(y_vec.at(expected_y.size() + i));
cmp_vals.push_back(true);
}
else
@@ -220,7 +214,7 @@ struct VlogHammerReporter
cmp_vars.push_back(y_vec.at(i));
cmp_vals.push_back(y_values.at(i));
- cmp_vars.push_back(y_vec.at(expected_y.width + i));
+ cmp_vars.push_back(y_vec.at(expected_y.size() + i));
cmp_vals.push_back(false);
}
@@ -258,10 +252,10 @@ struct VlogHammerReporter
std::vector<RTLIL::State> bits(patterns[idx].bits.begin(), patterns[idx].bits.begin() + total_input_width);
for (int i = 0; i < int(inputs.size()); i++) {
- RTLIL::Wire *wire = module->wires.at(inputs[i]);
+ RTLIL::Wire *wire = module->wires_.at(inputs[i]);
for (int j = input_widths[i]-1; j >= 0; j--) {
- ce.set(RTLIL::SigSpec(wire, 1, j), bits.back());
- recorded_set_vars.append(RTLIL::SigSpec(wire, 1, j));
+ ce.set(RTLIL::SigSpec(wire, j), bits.back());
+ recorded_set_vars.append(RTLIL::SigSpec(wire, j));
recorded_set_vals.bits.push_back(bits.back());
bits.pop_back();
}
@@ -274,32 +268,30 @@ struct VlogHammerReporter
}
}
- if (module->wires.count("\\y") == 0)
+ if (module->wires_.count("\\y") == 0)
log_error("No output wire (y) found in module %s!\n", RTLIL::id2cstr(module->name));
- RTLIL::SigSpec sig(module->wires.at("\\y"));
+ RTLIL::SigSpec sig(module->wires_.at("\\y"));
RTLIL::SigSpec undef;
while (!ce.eval(sig, undef)) {
// log_error("Evaluation of y in module %s failed: sig=%s, undef=%s\n", RTLIL::id2cstr(module->name), log_signal(sig), log_signal(undef));
log("Warning: Setting signal %s in module %s to undef.\n", log_signal(undef), RTLIL::id2cstr(module->name));
- ce.set(undef, RTLIL::Const(RTLIL::State::Sx, undef.width));
+ ce.set(undef, RTLIL::Const(RTLIL::State::Sx, undef.size()));
}
log("++VAL++ %d %s %s #\n", idx, module_name.c_str(), sig.as_const().as_string().c_str());
if (module_name == "rtl") {
rtl_sig = sig;
- rtl_sig.expand();
sat_check(module, recorded_set_vars, recorded_set_vals, sig, false);
sat_check(module, recorded_set_vars, recorded_set_vals, sig, true);
- } else if (rtl_sig.width > 0) {
- sig.expand();
- if (rtl_sig.width != sig.width)
+ } else if (rtl_sig.size() > 0) {
+ if (rtl_sig.size() != sig.size())
log_error("Output (y) has a different width in module %s compared to rtl!\n", RTLIL::id2cstr(module->name));
- for (int i = 0; i < sig.width; i++)
- if (rtl_sig.chunks.at(i).data.bits.at(0) == RTLIL::State::Sx)
- sig.chunks.at(i).data.bits.at(0) = RTLIL::State::Sx;
+ for (int i = 0; i < SIZE(sig); i++)
+ if (rtl_sig[i] == RTLIL::State::Sx)
+ sig[i] = RTLIL::State::Sx;
}
log("++RPT++ %d%s %s %s\n", idx, input_pattern_list.c_str(), sig.as_const().as_string().c_str(), module_name.c_str());
@@ -314,10 +306,10 @@ struct VlogHammerReporter
{
for (auto name : split(module_list, ",")) {
RTLIL::IdString esc_name = RTLIL::escape_id(module_prefix + name);
- if (design->modules.count(esc_name) == 0)
+ if (design->modules_.count(esc_name) == 0)
log_error("Can't find module %s in current design!\n", name.c_str());
log("Using module %s (%s).\n", esc_name.c_str(), name.c_str());
- modules.push_back(design->modules.at(esc_name));
+ modules.push_back(design->modules_.at(esc_name));
module_names.push_back(name);
}
@@ -326,9 +318,9 @@ struct VlogHammerReporter
int width = -1;
RTLIL::IdString esc_name = RTLIL::escape_id(name);
for (auto mod : modules) {
- if (mod->wires.count(esc_name) == 0)
+ if (mod->wires_.count(esc_name) == 0)
log_error("Can't find input %s in module %s!\n", name.c_str(), RTLIL::id2cstr(mod->name));
- RTLIL::Wire *port = mod->wires.at(esc_name);
+ RTLIL::Wire *port = mod->wires_.at(esc_name);
if (!port->port_input || port->port_output)
log_error("Wire %s in module %s is not an input!\n", name.c_str(), RTLIL::id2cstr(mod->name));
if (width >= 0 && width != port->width)
@@ -350,7 +342,7 @@ struct VlogHammerReporter
}
if (!RTLIL::SigSpec::parse(sig, NULL, pattern) || !sig.is_fully_const())
log_error("Failed to parse pattern %s!\n", pattern.c_str());
- if (sig.width < total_input_width)
+ if (sig.size() < total_input_width)
log_error("Pattern %s is to short!\n", pattern.c_str());
patterns.push_back(sig.as_const());
if (invert_pattern) {
@@ -424,11 +416,11 @@ struct EvalPass : public Pass {
/* this should only be used for regression testing of ConstEval -- see vloghammer */
std::string mod1_name = RTLIL::escape_id(args[++argidx]);
std::string mod2_name = RTLIL::escape_id(args[++argidx]);
- if (design->modules.count(mod1_name) == 0)
+ if (design->modules_.count(mod1_name) == 0)
log_error("Can't find module `%s'!\n", mod1_name.c_str());
- if (design->modules.count(mod2_name) == 0)
+ if (design->modules_.count(mod2_name) == 0)
log_error("Can't find module `%s'!\n", mod2_name.c_str());
- BruteForceEquivChecker checker(design->modules.at(mod1_name), design->modules.at(mod2_name), args[argidx-2] == "-brute_force_equiv_checker_x");
+ BruteForceEquivChecker checker(design->modules_.at(mod1_name), design->modules_.at(mod2_name), args[argidx-2] == "-brute_force_equiv_checker_x");
if (checker.errors > 0)
log_cmd_error("Modules are not equivialent!\n");
log("Verified %s = %s (using brute-force check on %d cases).\n",
@@ -450,7 +442,7 @@ struct EvalPass : public Pass {
extra_args(args, argidx, design);
RTLIL::Module *module = NULL;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second)) {
if (module)
log_cmd_error("Only one module must be selected for the EVAL pass! (selected: %s and %s)\n",
@@ -470,16 +462,16 @@ struct EvalPass : public Pass {
log_cmd_error("Failed to parse rhs set expression `%s'.\n", it.second.c_str());
if (!rhs.is_fully_const())
log_cmd_error("Right-hand-side set expression `%s' is not constant.\n", it.second.c_str());
- if (lhs.width != rhs.width)
+ if (lhs.size() != rhs.size())
log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- it.first.c_str(), log_signal(lhs), lhs.width, it.second.c_str(), log_signal(rhs), rhs.width);
+ it.first.c_str(), log_signal(lhs), lhs.size(), it.second.c_str(), log_signal(rhs), rhs.size());
ce.set(lhs, rhs.as_const());
}
if (shows.size() == 0) {
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->port_output)
- shows.push_back(it.second->name);
+ shows.push_back(it.second->name.str());
}
if (tables.empty())
@@ -488,12 +480,11 @@ struct EvalPass : public Pass {
RTLIL::SigSpec signal, value, undef;
if (!RTLIL::SigSpec::parse_sel(signal, design, module, it))
log_cmd_error("Failed to parse show expression `%s'.\n", it.c_str());
- signal.optimize();
value = signal;
if (set_undef) {
while (!ce.eval(value, undef)) {
log("Failed to evaluate signal %s: Missing value for %s. -> setting to undef\n", log_signal(signal), log_signal(undef));
- ce.set(undef, RTLIL::Const(RTLIL::State::Sx, undef.width));
+ ce.set(undef, RTLIL::Const(RTLIL::State::Sx, undef.size()));
undef = RTLIL::SigSpec();
}
log("Eval result: %s = %s.\n", log_signal(signal), log_signal(value));
@@ -526,15 +517,15 @@ struct EvalPass : public Pass {
}
std::vector<std::string> tab_line;
- for (auto &c : tabsigs.chunks)
+ for (auto &c : tabsigs.chunks())
tab_line.push_back(log_signal(c));
tab_sep_colidx = tab_line.size();
- for (auto &c : signal.chunks)
+ for (auto &c : signal.chunks())
tab_line.push_back(log_signal(c));
tab.push_back(tab_line);
tab_line.clear();
- RTLIL::Const tabvals(0, tabsigs.width);
+ RTLIL::Const tabvals(0, tabsigs.size());
do
{
ce.push();
@@ -548,19 +539,19 @@ struct EvalPass : public Pass {
log_signal(tabsigs), log_signal(tabvals), log_signal(this_undef));
return;
}
- ce.set(this_undef, RTLIL::Const(RTLIL::State::Sx, this_undef.width));
+ ce.set(this_undef, RTLIL::Const(RTLIL::State::Sx, this_undef.size()));
undef.append(this_undef);
this_undef = RTLIL::SigSpec();
}
int pos = 0;
- for (auto &c : tabsigs.chunks) {
+ for (auto &c : tabsigs.chunks()) {
tab_line.push_back(log_signal(RTLIL::SigSpec(tabvals).extract(pos, c.width)));
pos += c.width;
}
pos = 0;
- for (auto &c : signal.chunks) {
+ for (auto &c : signal.chunks()) {
tab_line.push_back(log_signal(value.extract(pos, c.width)));
pos += c.width;
}
@@ -602,7 +593,7 @@ struct EvalPass : public Pass {
}
log("\n");
- if (undef.width > 0) {
+ if (undef.size() > 0) {
undef.sort_and_unify();
log("Assumend undef (x) value for the following singals: %s\n\n", log_signal(undef));
}
diff --git a/passes/sat/example.ys b/passes/sat/example.ys
index 11f5b924..cc72faac 100644
--- a/passes/sat/example.ys
+++ b/passes/sat/example.ys
@@ -1,13 +1,14 @@
read_verilog example.v
proc; opt_clean
+echo on
sat -set y 1'b1 example001
sat -set y 1'b1 example002
sat -set y_sshl 8'hf0 -set y_sshr 8'hf0 -set sh 4'd3 example003
-sat -set y 1'b1 example004
+sat -set y 1'b1 -ignore_unknown_cells example004
sat -show rst,counter -set-at 3 y 1'b1 -seq 4 example004
-sat -prove y 1'b0 -show rst,counter,y example004
-sat -prove y 1'b0 -show rst,counter,y -set-at 1 rst 1'b1 -seq 1 example004
+sat -prove y 1'b0 -show rst,counter,y -ignore_unknown_cells example004
+sat -prove y 1'b0 -tempinduct -show rst,counter,y -set-at 1 rst 1'b1 -seq 1 example004
diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc
index 2ac7b35f..e856fdf7 100644
--- a/passes/sat/expose.cc
+++ b/passes/sat/expose.cc
@@ -27,7 +27,7 @@ struct dff_map_info_t {
RTLIL::SigSpec sig_d, sig_clk, sig_arst;
bool clk_polarity, arst_polarity;
RTLIL::Const arst_value;
- std::vector<std::string> cells;
+ std::vector<RTLIL::IdString> cells;
};
struct dff_map_bit_info_t {
@@ -37,7 +37,7 @@ struct dff_map_bit_info_t {
RTLIL::Cell *cell;
};
-static bool consider_wire(RTLIL::Wire *wire, std::map<std::string, dff_map_info_t> &dff_dq_map)
+static bool consider_wire(RTLIL::Wire *wire, std::map<RTLIL::IdString, dff_map_info_t> &dff_dq_map)
{
if (wire->name[0] == '$' || dff_dq_map.count(wire->name))
return false;
@@ -46,11 +46,11 @@ static bool consider_wire(RTLIL::Wire *wire, std::map<std::string, dff_map_info_
return true;
}
-static bool consider_cell(RTLIL::Design *design, std::set<std::string> &dff_cells, RTLIL::Cell *cell)
+static bool consider_cell(RTLIL::Design *design, std::set<RTLIL::IdString> &dff_cells, RTLIL::Cell *cell)
{
if (cell->name[0] == '$' || dff_cells.count(cell->name))
return false;
- if (cell->type.at(0) == '\\' && !design->modules.count(cell->type))
+ if (cell->type[0] == '\\' && !design->modules_.count(cell->type))
return false;
return true;
}
@@ -73,7 +73,7 @@ static bool compare_cells(RTLIL::Cell *cell1, RTLIL::Cell *cell2)
return true;
}
-static void find_dff_wires(std::set<std::string> &dff_wires, RTLIL::Module *module)
+static void find_dff_wires(std::set<RTLIL::IdString> &dff_wires, RTLIL::Module *module)
{
CellTypes ct;
ct.setup_internals_mem();
@@ -82,23 +82,23 @@ static void find_dff_wires(std::set<std::string> &dff_wires, RTLIL::Module *modu
SigMap sigmap(module);
SigPool dffsignals;
- for (auto &it : module->cells) {
- if (ct.cell_known(it.second->type) && it.second->connections.count("\\Q"))
- dffsignals.add(sigmap(it.second->connections.at("\\Q")));
+ for (auto &it : module->cells_) {
+ if (ct.cell_known(it.second->type) && it.second->hasPort("\\Q"))
+ dffsignals.add(sigmap(it.second->getPort("\\Q")));
}
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
if (dffsignals.check_any(it.second))
dff_wires.insert(it.first);
}
}
-static void create_dff_dq_map(std::map<std::string, dff_map_info_t> &map, RTLIL::Design *design, RTLIL::Module *module)
+static void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::Design *design, RTLIL::Module *module)
{
std::map<RTLIL::SigBit, dff_map_bit_info_t> bit_info;
SigMap sigmap(module);
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
if (!design->selected(module, it.second))
continue;
@@ -113,10 +113,10 @@ static void create_dff_dq_map(std::map<std::string, dff_map_info_t> &map, RTLIL:
info.cell = it.second;
if (info.cell->type == "$dff") {
- info.bit_clk = sigmap(info.cell->connections.at("\\CLK")).to_single_sigbit();
+ info.bit_clk = sigmap(info.cell->getPort("\\CLK")).to_single_sigbit();
info.clk_polarity = info.cell->parameters.at("\\CLK_POLARITY").as_bool();
- std::vector<RTLIL::SigBit> sig_d = sigmap(info.cell->connections.at("\\D")).to_sigbit_vector();
- std::vector<RTLIL::SigBit> sig_q = sigmap(info.cell->connections.at("\\Q")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_d = sigmap(info.cell->getPort("\\D")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_q = sigmap(info.cell->getPort("\\Q")).to_sigbit_vector();
for (size_t i = 0; i < sig_d.size(); i++) {
info.bit_d = sig_d.at(i);
bit_info[sig_q.at(i)] = info;
@@ -125,12 +125,12 @@ static void create_dff_dq_map(std::map<std::string, dff_map_info_t> &map, RTLIL:
}
if (info.cell->type == "$adff") {
- info.bit_clk = sigmap(info.cell->connections.at("\\CLK")).to_single_sigbit();
- info.bit_arst = sigmap(info.cell->connections.at("\\ARST")).to_single_sigbit();
+ info.bit_clk = sigmap(info.cell->getPort("\\CLK")).to_single_sigbit();
+ info.bit_arst = sigmap(info.cell->getPort("\\ARST")).to_single_sigbit();
info.clk_polarity = info.cell->parameters.at("\\CLK_POLARITY").as_bool();
info.arst_polarity = info.cell->parameters.at("\\ARST_POLARITY").as_bool();
- std::vector<RTLIL::SigBit> sig_d = sigmap(info.cell->connections.at("\\D")).to_sigbit_vector();
- std::vector<RTLIL::SigBit> sig_q = sigmap(info.cell->connections.at("\\Q")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_d = sigmap(info.cell->getPort("\\D")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_q = sigmap(info.cell->getPort("\\Q")).to_sigbit_vector();
std::vector<RTLIL::State> arst_value = info.cell->parameters.at("\\ARST_VALUE").bits;
for (size_t i = 0; i < sig_d.size(); i++) {
info.bit_d = sig_d.at(i);
@@ -141,27 +141,27 @@ static void create_dff_dq_map(std::map<std::string, dff_map_info_t> &map, RTLIL:
}
if (info.cell->type == "$_DFF_N_" || info.cell->type == "$_DFF_P_") {
- info.bit_clk = sigmap(info.cell->connections.at("\\C")).to_single_sigbit();
+ info.bit_clk = sigmap(info.cell->getPort("\\C")).to_single_sigbit();
info.clk_polarity = info.cell->type == "$_DFF_P_";
- info.bit_d = sigmap(info.cell->connections.at("\\D")).to_single_sigbit();
- bit_info[sigmap(info.cell->connections.at("\\Q")).to_single_sigbit()] = info;
+ info.bit_d = sigmap(info.cell->getPort("\\D")).to_single_sigbit();
+ bit_info[sigmap(info.cell->getPort("\\Q")).to_single_sigbit()] = info;
continue;
}
if (info.cell->type.size() == 10 && info.cell->type.substr(0, 6) == "$_DFF_") {
- info.bit_clk = sigmap(info.cell->connections.at("\\C")).to_single_sigbit();
- info.bit_arst = sigmap(info.cell->connections.at("\\R")).to_single_sigbit();
+ info.bit_clk = sigmap(info.cell->getPort("\\C")).to_single_sigbit();
+ info.bit_arst = sigmap(info.cell->getPort("\\R")).to_single_sigbit();
info.clk_polarity = info.cell->type[6] == 'P';
info.arst_polarity = info.cell->type[7] == 'P';
info.arst_value = info.cell->type[0] == '1' ? RTLIL::State::S1 : RTLIL::State::S0;
- info.bit_d = sigmap(info.cell->connections.at("\\D")).to_single_sigbit();
- bit_info[sigmap(info.cell->connections.at("\\Q")).to_single_sigbit()] = info;
+ info.bit_d = sigmap(info.cell->getPort("\\D")).to_single_sigbit();
+ bit_info[sigmap(info.cell->getPort("\\Q")).to_single_sigbit()] = info;
continue;
}
}
- std::map<std::string, dff_map_info_t> empty_dq_map;
- for (auto &it : module->wires)
+ std::map<RTLIL::IdString, dff_map_info_t> empty_dq_map;
+ for (auto &it : module->wires_)
{
if (!consider_wire(it.second, empty_dq_map))
continue;
@@ -208,11 +208,11 @@ static void create_dff_dq_map(std::map<std::string, dff_map_info_t> &map, RTLIL:
}
}
-static void add_new_wire(RTLIL::Module *module, RTLIL::Wire *wire)
+static RTLIL::Wire *add_new_wire(RTLIL::Module *module, RTLIL::IdString name, int width = 1)
{
- if (module->count_id(wire->name))
- log_error("Attempting to create wire %s, but a wire of this name exists already! Hint: Try another value for -sep.\n", RTLIL::id2cstr(wire->name));
- module->add(wire);
+ if (module->count_id(name))
+ log_error("Attempting to create wire %s, but a wire of this name exists already! Hint: Try another value for -sep.\n", log_id(name));
+ return module->addWire(name, width);
}
struct ExposePass : public Pass {
@@ -259,6 +259,8 @@ struct ExposePass : public Pass {
bool flag_evert_dff = false;
std::string sep = ".";
+ log_header("Executing EXPOSE pass (exposing internal signals as outputs).\n");
+
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
@@ -292,15 +294,15 @@ struct ExposePass : public Pass {
CellTypes ct(design);
- std::map<RTLIL::Module*, std::map<std::string, dff_map_info_t>> dff_dq_maps;
- std::map<RTLIL::Module*, std::set<std::string>> dff_cells;
+ std::map<RTLIL::Module*, std::map<RTLIL::IdString, dff_map_info_t>> dff_dq_maps;
+ std::map<RTLIL::Module*, std::set<RTLIL::IdString>> dff_cells;
if (flag_evert_dff)
{
RTLIL::Module *first_module = NULL;
- std::set<std::string> shared_dff_wires;
+ std::set<RTLIL::IdString> shared_dff_wires;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (!design->selected(mod_it.second))
continue;
@@ -315,11 +317,11 @@ struct ExposePass : public Pass {
shared_dff_wires.insert(it.first);
first_module = mod_it.second;
} else {
- std::set<std::string> new_shared_dff_wires;
+ std::set<RTLIL::IdString> new_shared_dff_wires;
for (auto &it : shared_dff_wires) {
if (!dff_dq_maps[mod_it.second].count(it))
continue;
- if (!compare_wires(first_module->wires.at(it), mod_it.second->wires.at(it)))
+ if (!compare_wires(first_module->wires_.at(it), mod_it.second->wires_.at(it)))
continue;
new_shared_dff_wires.insert(it);
}
@@ -330,7 +332,7 @@ struct ExposePass : public Pass {
if (flag_shared)
for (auto &map_it : dff_dq_maps)
{
- std::map<std::string, dff_map_info_t> new_map;
+ std::map<RTLIL::IdString, dff_map_info_t> new_map;
for (auto &it : map_it.second)
if (shared_dff_wires.count(it.first))
new_map[it.first] = it.second;
@@ -343,33 +345,33 @@ struct ExposePass : public Pass {
dff_cells[it1.first].insert(it3);
}
- std::set<std::string> shared_wires, shared_cells;
- std::set<std::string> used_names;
+ std::set<RTLIL::IdString> shared_wires, shared_cells;
+ std::set<RTLIL::IdString> used_names;
if (flag_shared)
{
RTLIL::Module *first_module = NULL;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
RTLIL::Module *module = mod_it.second;
if (!design->selected(module))
continue;
- std::set<std::string> dff_wires;
+ std::set<RTLIL::IdString> dff_wires;
if (flag_dff)
find_dff_wires(dff_wires, module);
if (first_module == NULL)
{
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (design->selected(module, it.second) && consider_wire(it.second, dff_dq_maps[module]))
if (!flag_dff || dff_wires.count(it.first))
shared_wires.insert(it.first);
if (flag_evert)
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
if (design->selected(module, it.second) && consider_cell(design, dff_cells[module], it.second))
shared_cells.insert(it.first);
@@ -377,22 +379,22 @@ struct ExposePass : public Pass {
}
else
{
- std::vector<std::string> delete_shared_wires, delete_shared_cells;
+ std::vector<RTLIL::IdString> delete_shared_wires, delete_shared_cells;
for (auto &it : shared_wires)
{
RTLIL::Wire *wire;
- if (module->wires.count(it) == 0)
+ if (module->wires_.count(it) == 0)
goto delete_shared_wire;
- wire = module->wires.at(it);
+ wire = module->wires_.at(it);
if (!design->selected(module, wire))
goto delete_shared_wire;
if (!consider_wire(wire, dff_dq_maps[module]))
goto delete_shared_wire;
- if (!compare_wires(first_module->wires.at(it), wire))
+ if (!compare_wires(first_module->wires_.at(it), wire))
goto delete_shared_wire;
if (flag_dff && !dff_wires.count(it))
goto delete_shared_wire;
@@ -407,16 +409,16 @@ struct ExposePass : public Pass {
{
RTLIL::Cell *cell;
- if (module->cells.count(it) == 0)
+ if (module->cells_.count(it) == 0)
goto delete_shared_cell;
- cell = module->cells.at(it);
+ cell = module->cells_.at(it);
if (!design->selected(module, cell))
goto delete_shared_cell;
if (!consider_cell(design, dff_cells[module], cell))
goto delete_shared_cell;
- if (!compare_cells(first_module->cells.at(it), cell))
+ if (!compare_cells(first_module->cells_.at(it), cell))
goto delete_shared_cell;
if (0)
@@ -432,23 +434,22 @@ struct ExposePass : public Pass {
}
}
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
RTLIL::Module *module = mod_it.second;
if (!design->selected(module))
continue;
- std::set<std::string> dff_wires;
+ std::set<RTLIL::IdString> dff_wires;
if (flag_dff && !flag_shared)
find_dff_wires(dff_wires, module);
SigMap sigmap(module);
SigMap out_to_in_map;
- std::vector<RTLIL::Wire*> new_wires;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
{
if (flag_shared) {
if (shared_wires.count(it.first) == 0)
@@ -466,29 +467,23 @@ struct ExposePass : public Pass {
}
if (flag_cut) {
- RTLIL::Wire *in_wire = new RTLIL::Wire;
- in_wire->name = it.second->name + sep + "i";
- in_wire->width = it.second->width;
+ RTLIL::Wire *in_wire = add_new_wire(module, it.second->name.str() + sep + "i", it.second->width);
in_wire->port_input = true;
out_to_in_map.add(sigmap(it.second), in_wire);
- new_wires.push_back(in_wire);
}
}
if (flag_cut)
{
- for (auto it : new_wires)
- add_new_wire(module, it);
-
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (!ct.cell_known(it.second->type))
continue;
- for (auto &conn : it.second->connections)
+ for (auto &conn : it.second->connections_)
if (ct.cell_input(it.second->type, conn.first))
conn.second = out_to_in_map(sigmap(conn.second));
}
- for (auto &conn : module->connections)
+ for (auto &conn : module->connections_)
conn.second = out_to_in_map(sigmap(conn.second));
}
@@ -496,35 +491,29 @@ struct ExposePass : public Pass {
for (auto &dq : dff_dq_maps[module])
{
- if (!module->wires.count(dq.first))
+ if (!module->wires_.count(dq.first))
continue;
- RTLIL::Wire *wire = module->wires.at(dq.first);
+ RTLIL::Wire *wire = module->wires_.at(dq.first);
std::set<RTLIL::SigBit> wire_bits_set = sigmap(wire).to_sigbit_set();
std::vector<RTLIL::SigBit> wire_bits_vec = sigmap(wire).to_sigbit_vector();
dff_map_info_t &info = dq.second;
- RTLIL::Wire *wire_dummy_q = new RTLIL::Wire;
- wire_dummy_q->name = NEW_ID;
- wire_dummy_q->width = 0;
- add_new_wire(module, wire_dummy_q);
+ RTLIL::Wire *wire_dummy_q = add_new_wire(module, NEW_ID, 0);
for (auto &cell_name : info.cells) {
- RTLIL::Cell *cell = module->cells.at(cell_name);
- std::vector<RTLIL::SigBit> cell_q_bits = sigmap(cell->connections.at("\\Q")).to_sigbit_vector();
+ RTLIL::Cell *cell = module->cells_.at(cell_name);
+ std::vector<RTLIL::SigBit> cell_q_bits = sigmap(cell->getPort("\\Q")).to_sigbit_vector();
for (auto &bit : cell_q_bits)
if (wire_bits_set.count(bit))
bit = RTLIL::SigBit(wire_dummy_q, wire_dummy_q->width++);
- cell->connections.at("\\Q") = cell_q_bits;
+ cell->setPort("\\Q", cell_q_bits);
}
- RTLIL::Wire *wire_q = new RTLIL::Wire;
- wire_q->name = wire->name + sep + "q";
- wire_q->width = wire->width;
+ RTLIL::Wire *wire_q = add_new_wire(module, wire->name.str() + sep + "q", wire->width);
wire_q->port_input = true;
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_q->name));
- add_new_wire(module, wire_q);
RTLIL::SigSig connect_q;
for (size_t i = 0; i < wire_bits_vec.size(); i++) {
@@ -534,71 +523,55 @@ struct ExposePass : public Pass {
connect_q.second.append(RTLIL::SigBit(wire_q, i));
set_q_bits.insert(wire_bits_vec[i]);
}
- module->connections.push_back(connect_q);
+ module->connect(connect_q);
- RTLIL::Wire *wire_d = new RTLIL::Wire;
- wire_d->name = wire->name + sep + "d";
- wire_d->width = wire->width;
+ RTLIL::Wire *wire_d = add_new_wire(module, wire->name.str() + sep + "d", wire->width);
wire_d->port_output = true;
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_d->name));
- add_new_wire(module, wire_d);
- module->connections.push_back(RTLIL::SigSig(wire_d, info.sig_d));
+ module->connect(RTLIL::SigSig(wire_d, info.sig_d));
- RTLIL::Wire *wire_c = new RTLIL::Wire;
- wire_c->name = wire->name + sep + "c";
+ RTLIL::Wire *wire_c = add_new_wire(module, wire->name.str() + sep + "c");
wire_c->port_output = true;
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_c->name));
- add_new_wire(module, wire_c);
if (info.clk_polarity) {
- module->connections.push_back(RTLIL::SigSig(wire_c, info.sig_clk));
+ module->connect(RTLIL::SigSig(wire_c, info.sig_clk));
} else {
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = NEW_ID;
- c->type = "$not";
+ RTLIL::Cell *c = module->addCell(NEW_ID, "$not");
c->parameters["\\A_SIGNED"] = 0;
c->parameters["\\A_WIDTH"] = 1;
c->parameters["\\Y_WIDTH"] = 1;
- c->connections["\\A"] = info.sig_clk;
- c->connections["\\Y"] = wire_c;
- module->add(c);
+ c->setPort("\\A", info.sig_clk);
+ c->setPort("\\Y", wire_c);
}
if (info.sig_arst != RTLIL::State::Sm)
{
- RTLIL::Wire *wire_r = new RTLIL::Wire;
- wire_r->name = wire->name + sep + "r";
+ RTLIL::Wire *wire_r = add_new_wire(module, wire->name.str() + sep + "r");
wire_r->port_output = true;
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_r->name));
- add_new_wire(module, wire_r);
if (info.arst_polarity) {
- module->connections.push_back(RTLIL::SigSig(wire_r, info.sig_arst));
+ module->connect(RTLIL::SigSig(wire_r, info.sig_arst));
} else {
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = NEW_ID;
- c->type = "$not";
+ RTLIL::Cell *c = module->addCell(NEW_ID, "$not");
c->parameters["\\A_SIGNED"] = 0;
c->parameters["\\A_WIDTH"] = 1;
c->parameters["\\Y_WIDTH"] = 1;
- c->connections["\\A"] = info.sig_arst;
- c->connections["\\Y"] = wire_r;
- module->add(c);
+ c->setPort("\\A", info.sig_arst);
+ c->setPort("\\Y", wire_r);
}
- RTLIL::Wire *wire_v = new RTLIL::Wire;
- wire_v->name = wire->name + sep + "v";
- wire_v->width = wire->width;
+ RTLIL::Wire *wire_v = add_new_wire(module, wire->name.str() + sep + "v", wire->width);
wire_v->port_output = true;
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_v->name));
- add_new_wire(module, wire_v);
- module->connections.push_back(RTLIL::SigSig(wire_v, info.arst_value));
+ module->connect(RTLIL::SigSig(wire_v, info.arst_value));
}
}
if (flag_evert)
{
- std::vector<std::string> delete_cells;
+ std::vector<RTLIL::Cell*> delete_cells;
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
if (flag_shared) {
if (shared_cells.count(it.first) == 0)
@@ -610,66 +583,59 @@ struct ExposePass : public Pass {
RTLIL::Cell *cell = it.second;
- if (design->modules.count(cell->type))
+ if (design->modules_.count(cell->type))
{
- RTLIL::Module *mod = design->modules.at(cell->type);
+ RTLIL::Module *mod = design->modules_.at(cell->type);
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
{
RTLIL::Wire *p = it.second;
if (!p->port_input && !p->port_output)
continue;
- RTLIL::Wire *w = new RTLIL::Wire;
- w->name = cell->name + sep + RTLIL::unescape_id(p->name);
- w->width = p->width;
+ RTLIL::Wire *w = add_new_wire(module, cell->name.str() + sep + RTLIL::unescape_id(p->name), p->width);
if (p->port_input)
w->port_output = true;
if (p->port_output)
w->port_input = true;
- add_new_wire(module, w);
- log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name));
+ log("New module port: %s/%s (%s)\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name), RTLIL::id2cstr(cell->type));
RTLIL::SigSpec sig;
- if (cell->connections.count(p->name) != 0)
- sig = cell->connections.at(p->name);
+ if (cell->hasPort(p->name))
+ sig = cell->getPort(p->name);
sig.extend(w->width);
if (w->port_input)
- module->connections.push_back(RTLIL::SigSig(sig, w));
+ module->connect(RTLIL::SigSig(sig, w));
else
- module->connections.push_back(RTLIL::SigSig(w, sig));
+ module->connect(RTLIL::SigSig(w, sig));
}
}
else
{
- for (auto &it : cell->connections)
+ for (auto &it : cell->connections())
{
- RTLIL::Wire *w = new RTLIL::Wire;
- w->name = cell->name + sep + RTLIL::unescape_id(it.first);
- w->width = it.second.width;
+ RTLIL::Wire *w = add_new_wire(module, cell->name.str() + sep + RTLIL::unescape_id(it.first), it.second.size());
if (ct.cell_input(cell->type, it.first))
w->port_output = true;
if (ct.cell_output(cell->type, it.first))
w->port_input = true;
- add_new_wire(module, w);
- log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name));
+ log("New module port: %s/%s (%s)\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name), RTLIL::id2cstr(cell->type));
if (w->port_input)
- module->connections.push_back(RTLIL::SigSig(it.second, w));
+ module->connect(RTLIL::SigSig(it.second, w));
else
- module->connections.push_back(RTLIL::SigSig(w, it.second));
+ module->connect(RTLIL::SigSig(w, it.second));
}
}
- delete_cells.push_back(cell->name);
+ delete_cells.push_back(cell);
}
- for (auto &it : delete_cells) {
- log("Removing cell: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it));
- delete module->cells.at(it);
- module->cells.erase(it);
+ for (auto cell : delete_cells) {
+ log("Removing cell: %s/%s (%s)\n", log_id(module), log_id(cell), log_id(cell->type));
+ module->remove(cell);
}
}
diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc
index 81250b00..bfed0005 100644
--- a/passes/sat/freduce.cc
+++ b/passes/sat/freduce.cc
@@ -31,8 +31,9 @@
namespace {
bool inv_mode;
-int verbose_level;
+int verbose_level, reduce_counter, reduce_stop_at;
typedef std::map<RTLIL::SigBit, std::pair<RTLIL::Cell*, std::set<RTLIL::SigBit>>> drivers_t;
+std::string dump_prefix;
struct equiv_bit_t
{
@@ -112,13 +113,13 @@ struct FindReducedInputs
size_t idx_bits = get_bits(idx);
if (sat_pi_uniq_bitvec.size() != idx_bits) {
- sat_pi_uniq_bitvec.push_back(ez.literal(stringf("uniq_%d", int(idx_bits)-1)));
+ sat_pi_uniq_bitvec.push_back(ez.frozen_literal(stringf("uniq_%d", int(idx_bits)-1)));
for (auto &it : sat_pi)
ez.assume(ez.OR(ez.NOT(it.second), ez.NOT(sat_pi_uniq_bitvec.back())));
}
log_assert(sat_pi_uniq_bitvec.size() == idx_bits);
- sat_pi[bit] = ez.literal(stringf("pi_%s", log_signal(bit)));
+ sat_pi[bit] = ez.frozen_literal(stringf("p, falsei_%s", log_signal(bit)));
ez.assume(ez.IFF(ez.XOR(sat_a, sat_b), sat_pi[bit]));
for (size_t i = 0; i < idx_bits; i++)
@@ -243,7 +244,6 @@ struct PerformReduction
return 0;
if (sigdepth.count(out) != 0)
return sigdepth.at(out);
- sigdepth[out] = 0;
if (drivers.count(out) != 0) {
std::pair<RTLIL::Cell*, std::set<RTLIL::SigBit>> &drv = drivers.at(out);
@@ -252,17 +252,18 @@ struct PerformReduction
log_error("Can't create SAT model for cell %s (%s)!\n", RTLIL::id2cstr(drv.first->name), RTLIL::id2cstr(drv.first->type));
celldone.insert(drv.first);
}
- int max_child_dept = 0;
+ int max_child_depth = 0;
for (auto &bit : drv.second)
- max_child_dept = std::max(register_cone_worker(celldone, sigdepth, bit), max_child_dept);
- sigdepth[out] = max_child_dept + 1;
+ max_child_depth = std::max(register_cone_worker(celldone, sigdepth, bit), max_child_depth);
+ sigdepth[out] = max_child_depth + 1;
} else {
pi_bits.push_back(out);
sat_pi.push_back(satgen.importSigSpec(out).front());
ez.assume(ez.NOT(satgen.importUndefSigSpec(out).front()));
+ sigdepth[out] = 0;
}
- return sigdepth[out];
+ return sigdepth.at(out);
}
PerformReduction(SigMap &sigmap, drivers_t &drivers, std::set<std::pair<RTLIL::SigBit, RTLIL::SigBit>> &inv_pairs, std::vector<RTLIL::SigBit> &bits, int cone_size) :
@@ -348,7 +349,7 @@ struct PerformReduction
std::vector<RTLIL::SigBit> bucket_sigbits;
for (int idx : bucket)
bucket_sigbits.push_back(out_bits[idx]);
- log("%s Trying to shatter bucket with %d signals: %s\n", indt, int(bucket.size()), log_signal(RTLIL::SigSpec(bucket_sigbits).optimized()));
+ log("%s Trying to shatter bucket with %d signals: %s\n", indt, int(bucket.size()), log_signal(bucket_sigbits));
}
std::vector<int> sat_set_list, sat_clr_list;
@@ -493,7 +494,7 @@ struct PerformReduction
std::vector<RTLIL::SigBit> r_sigbits;
for (int idx : r)
r_sigbits.push_back(out_bits[idx]);
- log(" Found group of %d equivialent signals: %s\n", int(r.size()), log_signal(RTLIL::SigSpec(r_sigbits).optimized()));
+ log(" Found group of %d equivialent signals: %s\n", int(r.size()), log_signal(r_sigbits));
}
std::vector<int> undef_slaves;
@@ -559,6 +560,38 @@ struct FreduceWorker
{
}
+ bool find_bit_in_cone(std::set<RTLIL::Cell*> &celldone, RTLIL::SigBit needle, RTLIL::SigBit haystack)
+ {
+ if (needle == haystack)
+ return true;
+ if (haystack.wire == NULL || needle.wire == NULL || drivers.count(haystack) == 0)
+ return false;
+
+ std::pair<RTLIL::Cell*, std::set<RTLIL::SigBit>> &drv = drivers.at(haystack);
+
+ if (celldone.count(drv.first))
+ return false;
+ celldone.insert(drv.first);
+
+ for (auto &bit : drv.second)
+ if (find_bit_in_cone(celldone, needle, bit))
+ return true;
+ return false;
+ }
+
+ bool find_bit_in_cone(RTLIL::SigBit needle, RTLIL::SigBit haystack)
+ {
+ std::set<RTLIL::Cell*> celldone;
+ return find_bit_in_cone(celldone, needle, haystack);
+ }
+
+ void dump()
+ {
+ std::string filename = stringf("%s_%s_%05d.il", dump_prefix.c_str(), RTLIL::id2cstr(module->name), reduce_counter);
+ log("%s Writing dump file `%s'.\n", reduce_counter ? " " : "", filename.c_str());
+ Pass::call(design, stringf("dump -outfile %s %s", filename.c_str(), design->selected_active_module.empty() ? module->name.c_str() : ""));
+ }
+
int run()
{
log("Running functional reduction on module %s:\n", RTLIL::id2cstr(module->name));
@@ -569,15 +602,15 @@ struct FreduceWorker
int bits_full_total = 0;
std::vector<std::set<RTLIL::SigBit>> batches;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->port_input) {
batches.push_back(sigmap(it.second).to_sigbit_set());
bits_full_total += it.second->width;
}
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (ct.cell_known(it.second->type)) {
std::set<RTLIL::SigBit> inputs, outputs;
- for (auto &port : it.second->connections) {
+ for (auto &port : it.second->connections()) {
std::vector<RTLIL::SigBit> bits = sigmap(port.second).to_sigbit_vector();
if (ct.cell_output(it.second->type, port.first))
outputs.insert(bits.begin(), bits.end());
@@ -590,8 +623,8 @@ struct FreduceWorker
batches.push_back(outputs);
bits_full_total += outputs.size();
}
- if (inv_mode && it.second->type == "$_INV_")
- inv_pairs.insert(std::pair<RTLIL::SigBit, RTLIL::SigBit>(sigmap(it.second->connections.at("\\A")), sigmap(it.second->connections.at("\\Y"))));
+ if (inv_mode && it.second->type == "$_NOT_")
+ inv_pairs.insert(std::pair<RTLIL::SigBit, RTLIL::SigBit>(sigmap(it.second->getPort("\\A")), sigmap(it.second->getPort("\\Y"))));
}
int bits_count = 0;
@@ -607,7 +640,7 @@ struct FreduceWorker
found_selected_wire:
log(" Finding reduced input cone for signal batch %s%c\n",
- log_signal(RTLIL::SigSpec(std::vector<RTLIL::SigBit>(batch.begin(), batch.end())).optimized()), verbose_level ? ':' : '.');
+ log_signal(batch), verbose_level ? ':' : '.');
FindReducedInputs infinder(sigmap, drivers);
for (auto &bit : batch) {
@@ -630,12 +663,12 @@ struct FreduceWorker
continue;
if (bucket.first.size() == 0) {
- log(" Finding const values for bucket %s%c\n", log_signal(RTLIL::SigSpec(bucket.second).optimized()), verbose_level ? ':' : '.');
+ log(" Finding const values for bucket %s%c\n", log_signal(bucket.second), verbose_level ? ':' : '.');
PerformReduction worker(sigmap, drivers, inv_pairs, bucket.second, bucket.first.size());
for (size_t idx = 0; idx < bucket.second.size(); idx++)
worker.analyze_const(equiv, idx);
} else {
- log(" Trying to shatter bucket %s%c\n", log_signal(RTLIL::SigSpec(bucket.second).optimized()), verbose_level ? ':' : '.');
+ log(" Trying to shatter bucket %s%c\n", log_signal(bucket.second), verbose_level ? ':' : '.');
PerformReduction worker(sigmap, drivers, inv_pairs, bucket.second, bucket.first.size());
worker.analyze(equiv, 100 * bucket_count / (buckets.size() + 1));
}
@@ -644,11 +677,14 @@ struct FreduceWorker
std::map<RTLIL::SigBit, int> bitusage;
module->rewrite_sigspecs(CountBitUsage(sigmap, bitusage));
+ if (!dump_prefix.empty())
+ dump();
+
log(" Rewiring %d equivialent groups:\n", int(equiv.size()));
int rewired_sigbits = 0;
for (auto &grp : equiv)
{
- log(" Using as master for group: %s\n", log_signal(grp.front().bit));
+ log(" [%05d] Using as master for group: %s\n", ++reduce_counter, log_signal(grp.front().bit));
RTLIL::SigSpec inv_sig;
for (size_t i = 1; i < grp.size(); i++)
@@ -663,35 +699,45 @@ struct FreduceWorker
continue;
}
+ if (find_bit_in_cone(grp[i].bit, grp.front().bit)) {
+ log(" Skipping dependency of master: %s\n", log_signal(grp[i].bit));
+ continue;
+ }
+
log(" Connect slave%s: %s\n", grp[i].inverted ? " using inverter" : "", log_signal(grp[i].bit));
RTLIL::Cell *drv = drivers.at(grp[i].bit).first;
- RTLIL::Wire *dummy_wire = module->new_wire(1, NEW_ID);
- for (auto &port : drv->connections)
+ RTLIL::Wire *dummy_wire = module->addWire(NEW_ID);
+ for (auto &port : drv->connections_)
if (ct.cell_output(drv->type, port.first))
sigmap(port.second).replace(grp[i].bit, dummy_wire, &port.second);
if (grp[i].inverted)
{
- if (inv_sig.width == 0)
+ if (inv_sig.size() == 0)
{
- inv_sig = module->new_wire(1, NEW_ID);
-
- RTLIL::Cell *inv_cell = new RTLIL::Cell;
- inv_cell->name = NEW_ID;
- inv_cell->type = "$_INV_";
- inv_cell->connections["\\A"] = grp[0].bit;
- inv_cell->connections["\\Y"] = inv_sig;
- module->add(inv_cell);
+ inv_sig = module->addWire(NEW_ID);
+
+ RTLIL::Cell *inv_cell = module->addCell(NEW_ID, "$_NOT_");
+ inv_cell->setPort("\\A", grp[0].bit);
+ inv_cell->setPort("\\Y", inv_sig);
}
- module->connections.push_back(RTLIL::SigSig(grp[i].bit, inv_sig));
+ module->connect(RTLIL::SigSig(grp[i].bit, inv_sig));
}
else
- module->connections.push_back(RTLIL::SigSig(grp[i].bit, grp[0].bit));
+ module->connect(RTLIL::SigSig(grp[i].bit, grp[0].bit));
rewired_sigbits++;
}
+
+ if (!dump_prefix.empty())
+ dump();
+
+ if (reduce_counter == reduce_stop_at) {
+ log(" Reached limit passed using -stop option. Skipping all further reductions.\n");
+ break;
+ }
}
log(" Rewired a total of %d signal bits in module %s.\n", rewired_sigbits, RTLIL::id2cstr(module->name));
@@ -711,7 +757,7 @@ struct FreducePass : public Pass {
log("\n");
log("This pass performs functional reduction in the circuit. I.e. if two nodes are\n");
log("equivialent, they are merged to one node and one of the redundant drivers is\n");
- log("unconnected. A subsequent call to 'clean' will remove the redundant drivers.\n");
+ log("disconnected. A subsequent call to 'clean' will remove the redundant drivers.\n");
log("\n");
log(" -v, -vv\n");
log(" enable verbose or very verbose output\n");
@@ -719,6 +765,14 @@ struct FreducePass : public Pass {
log(" -inv\n");
log(" enable explicit handling of inverted signals\n");
log("\n");
+ log(" -stop <n>\n");
+ log(" stop after <n> reduction operations. this is mostly used for\n");
+ log(" debugging the freduce command itself.\n");
+ log("\n");
+ log(" -dump <prefix>\n");
+ log(" dump the design to <prefix>_<module>_<num>.il after each reduction\n");
+ log(" operation. this is mostly used for debugging the freduce command.\n");
+ log("\n");
log("This pass is undef-aware, i.e. it considers don't-care values for detecting\n");
log("equivialent nodes.\n");
log("\n");
@@ -728,8 +782,11 @@ struct FreducePass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
+ reduce_counter = 0;
+ reduce_stop_at = 0;
verbose_level = 0;
inv_mode = false;
+ dump_prefix = std::string();
log_header("Executing FREDUCE pass (perform functional reduction).\n");
@@ -747,12 +804,20 @@ struct FreducePass : public Pass {
inv_mode = true;
continue;
}
+ if (args[argidx] == "-stop" && argidx+1 < args.size()) {
+ reduce_stop_at = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-dump" && argidx+1 < args.size()) {
+ dump_prefix = args[++argidx];
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
int bitcount = 0;
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
RTLIL::Module *module = mod_it.second;
if (design->selected(module))
bitcount += FreduceWorker(design, module).run();
diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc
index db12cb57..b3adefb9 100644
--- a/passes/sat/miter.cc
+++ b/passes/sat/miter.cc
@@ -27,6 +27,9 @@ static void create_miter_equiv(struct Pass *that, std::vector<std::string> args,
bool flag_make_outputs = false;
bool flag_make_outcmp = false;
bool flag_make_assert = false;
+ bool flag_flatten = false;
+
+ log_header("Executing MITER pass (creating miter circuit).\n");
size_t argidx;
for (argidx = 2; argidx < args.size(); argidx++)
@@ -47,32 +50,36 @@ static void create_miter_equiv(struct Pass *that, std::vector<std::string> args,
flag_make_assert = true;
continue;
}
+ if (args[argidx] == "-flatten") {
+ flag_flatten = true;
+ continue;
+ }
break;
}
if (argidx+3 != args.size() || args[argidx].substr(0, 1) == "-")
that->cmd_error(args, argidx, "command argument error");
- std::string gold_name = RTLIL::escape_id(args[argidx++]);
- std::string gate_name = RTLIL::escape_id(args[argidx++]);
- std::string miter_name = RTLIL::escape_id(args[argidx++]);
+ RTLIL::IdString gold_name = RTLIL::escape_id(args[argidx++]);
+ RTLIL::IdString gate_name = RTLIL::escape_id(args[argidx++]);
+ RTLIL::IdString miter_name = RTLIL::escape_id(args[argidx++]);
- if (design->modules.count(gold_name) == 0)
+ if (design->modules_.count(gold_name) == 0)
log_cmd_error("Can't find gold module %s!\n", gold_name.c_str());
- if (design->modules.count(gate_name) == 0)
+ if (design->modules_.count(gate_name) == 0)
log_cmd_error("Can't find gate module %s!\n", gate_name.c_str());
- if (design->modules.count(miter_name) != 0)
+ if (design->modules_.count(miter_name) != 0)
log_cmd_error("There is already a module %s!\n", gate_name.c_str());
- RTLIL::Module *gold_module = design->modules.at(gold_name);
- RTLIL::Module *gate_module = design->modules.at(gate_name);
+ RTLIL::Module *gold_module = design->modules_.at(gold_name);
+ RTLIL::Module *gate_module = design->modules_.at(gate_name);
- for (auto &it : gold_module->wires) {
+ for (auto &it : gold_module->wires_) {
RTLIL::Wire *w1 = it.second, *w2;
if (w1->port_id == 0)
continue;
- if (gate_module->wires.count(it.second->name) == 0)
+ if (gate_module->wires_.count(it.second->name) == 0)
goto match_gold_port_error;
- w2 = gate_module->wires.at(it.second->name);
+ w2 = gate_module->wires_.at(it.second->name);
if (w1->port_input != w2->port_input)
goto match_gold_port_error;
if (w1->port_output != w2->port_output)
@@ -84,13 +91,13 @@ static void create_miter_equiv(struct Pass *that, std::vector<std::string> args,
log_cmd_error("No matching port in gate module was found for %s!\n", it.second->name.c_str());
}
- for (auto &it : gate_module->wires) {
+ for (auto &it : gate_module->wires_) {
RTLIL::Wire *w1 = it.second, *w2;
if (w1->port_id == 0)
continue;
- if (gold_module->wires.count(it.second->name) == 0)
+ if (gold_module->wires_.count(it.second->name) == 0)
goto match_gate_port_error;
- w2 = gold_module->wires.at(it.second->name);
+ w2 = gold_module->wires_.at(it.second->name);
if (w1->port_input != w2->port_input)
goto match_gate_port_error;
if (w1->port_output != w2->port_output)
@@ -102,187 +109,151 @@ static void create_miter_equiv(struct Pass *that, std::vector<std::string> args,
log_cmd_error("No matching port in gold module was found for %s!\n", it.second->name.c_str());
}
+ log("Creating miter cell \"%s\" with gold cell \"%s\" and gate cell \"%s\".\n", RTLIL::id2cstr(miter_name), RTLIL::id2cstr(gold_name), RTLIL::id2cstr(gate_name));
+
RTLIL::Module *miter_module = new RTLIL::Module;
miter_module->name = miter_name;
- design->modules[miter_name] = miter_module;
-
- RTLIL::Cell *gold_cell = new RTLIL::Cell;
- gold_cell->name = "\\gold";
- gold_cell->type = gold_name;
- miter_module->add(gold_cell);
+ design->add(miter_module);
- RTLIL::Cell *gate_cell = new RTLIL::Cell;
- gate_cell->name = "\\gate";
- gate_cell->type = gate_name;
- miter_module->add(gate_cell);
+ RTLIL::Cell *gold_cell = miter_module->addCell("\\gold", gold_name);
+ RTLIL::Cell *gate_cell = miter_module->addCell("\\gate", gate_name);
RTLIL::SigSpec all_conditions;
- for (auto &it : gold_module->wires)
+ for (auto &it : gold_module->wires_)
{
RTLIL::Wire *w1 = it.second;
if (w1->port_input)
{
- RTLIL::Wire *w2 = new RTLIL::Wire;
- w2->name = "\\in_" + RTLIL::unescape_id(w1->name);
+ RTLIL::Wire *w2 = miter_module->addWire("\\in_" + RTLIL::unescape_id(w1->name), w1->width);
w2->port_input = true;
- w2->width = w1->width;
- miter_module->add(w2);
- gold_cell->connections[w1->name] = w2;
- gate_cell->connections[w1->name] = w2;
+ gold_cell->setPort(w1->name, w2);
+ gate_cell->setPort(w1->name, w2);
}
if (w1->port_output)
{
- RTLIL::Wire *w2_gold = new RTLIL::Wire;
- w2_gold->name = "\\gold_" + RTLIL::unescape_id(w1->name);
+ RTLIL::Wire *w2_gold = miter_module->addWire("\\gold_" + RTLIL::unescape_id(w1->name), w1->width);
w2_gold->port_output = flag_make_outputs;
- w2_gold->width = w1->width;
- miter_module->add(w2_gold);
- RTLIL::Wire *w2_gate = new RTLIL::Wire;
- w2_gate->name = "\\gate_" + RTLIL::unescape_id(w1->name);
+ RTLIL::Wire *w2_gate = miter_module->addWire("\\gate_" + RTLIL::unescape_id(w1->name), w1->width);
w2_gate->port_output = flag_make_outputs;
- w2_gate->width = w1->width;
- miter_module->add(w2_gate);
- gold_cell->connections[w1->name] = w2_gold;
- gate_cell->connections[w1->name] = w2_gate;
+ gold_cell->setPort(w1->name, w2_gold);
+ gate_cell->setPort(w1->name, w2_gate);
RTLIL::SigSpec this_condition;
if (flag_ignore_gold_x)
{
- RTLIL::SigSpec gold_x = miter_module->new_wire(w2_gold->width, NEW_ID);
+ RTLIL::SigSpec gold_x = miter_module->addWire(NEW_ID, w2_gold->width);
for (int i = 0; i < w2_gold->width; i++) {
- RTLIL::Cell *eqx_cell = new RTLIL::Cell;
- eqx_cell->name = NEW_ID;
- eqx_cell->type = "$eqx";
+ RTLIL::Cell *eqx_cell = miter_module->addCell(NEW_ID, "$eqx");
eqx_cell->parameters["\\A_WIDTH"] = 1;
eqx_cell->parameters["\\B_WIDTH"] = 1;
eqx_cell->parameters["\\Y_WIDTH"] = 1;
eqx_cell->parameters["\\A_SIGNED"] = 0;
eqx_cell->parameters["\\B_SIGNED"] = 0;
- eqx_cell->connections["\\A"] = RTLIL::SigSpec(w2_gold, 1, i);
- eqx_cell->connections["\\B"] = RTLIL::State::Sx;
- eqx_cell->connections["\\Y"] = gold_x.extract(i, 1);
- miter_module->add(eqx_cell);
+ eqx_cell->setPort("\\A", RTLIL::SigSpec(w2_gold, i));
+ eqx_cell->setPort("\\B", RTLIL::State::Sx);
+ eqx_cell->setPort("\\Y", gold_x.extract(i, 1));
}
- RTLIL::SigSpec gold_masked = miter_module->new_wire(w2_gold->width, NEW_ID);
- RTLIL::SigSpec gate_masked = miter_module->new_wire(w2_gate->width, NEW_ID);
+ RTLIL::SigSpec gold_masked = miter_module->addWire(NEW_ID, w2_gold->width);
+ RTLIL::SigSpec gate_masked = miter_module->addWire(NEW_ID, w2_gate->width);
- RTLIL::Cell *or_gold_cell = new RTLIL::Cell;
- or_gold_cell->name = NEW_ID;
- or_gold_cell->type = "$or";
+ RTLIL::Cell *or_gold_cell = miter_module->addCell(NEW_ID, "$or");
or_gold_cell->parameters["\\A_WIDTH"] = w2_gold->width;
or_gold_cell->parameters["\\B_WIDTH"] = w2_gold->width;
or_gold_cell->parameters["\\Y_WIDTH"] = w2_gold->width;
or_gold_cell->parameters["\\A_SIGNED"] = 0;
or_gold_cell->parameters["\\B_SIGNED"] = 0;
- or_gold_cell->connections["\\A"] = w2_gold;
- or_gold_cell->connections["\\B"] = gold_x;
- or_gold_cell->connections["\\Y"] = gold_masked;
- miter_module->add(or_gold_cell);
-
- RTLIL::Cell *or_gate_cell = new RTLIL::Cell;
- or_gate_cell->name = NEW_ID;
- or_gate_cell->type = "$or";
+ or_gold_cell->setPort("\\A", w2_gold);
+ or_gold_cell->setPort("\\B", gold_x);
+ or_gold_cell->setPort("\\Y", gold_masked);
+
+ RTLIL::Cell *or_gate_cell = miter_module->addCell(NEW_ID, "$or");
or_gate_cell->parameters["\\A_WIDTH"] = w2_gate->width;
or_gate_cell->parameters["\\B_WIDTH"] = w2_gate->width;
or_gate_cell->parameters["\\Y_WIDTH"] = w2_gate->width;
or_gate_cell->parameters["\\A_SIGNED"] = 0;
or_gate_cell->parameters["\\B_SIGNED"] = 0;
- or_gate_cell->connections["\\A"] = w2_gate;
- or_gate_cell->connections["\\B"] = gold_x;
- or_gate_cell->connections["\\Y"] = gate_masked;
- miter_module->add(or_gate_cell);
-
- RTLIL::Cell *eq_cell = new RTLIL::Cell;
- eq_cell->name = NEW_ID;
- eq_cell->type = "$eqx";
+ or_gate_cell->setPort("\\A", w2_gate);
+ or_gate_cell->setPort("\\B", gold_x);
+ or_gate_cell->setPort("\\Y", gate_masked);
+
+ RTLIL::Cell *eq_cell = miter_module->addCell(NEW_ID, "$eqx");
eq_cell->parameters["\\A_WIDTH"] = w2_gold->width;
eq_cell->parameters["\\B_WIDTH"] = w2_gate->width;
eq_cell->parameters["\\Y_WIDTH"] = 1;
eq_cell->parameters["\\A_SIGNED"] = 0;
eq_cell->parameters["\\B_SIGNED"] = 0;
- eq_cell->connections["\\A"] = gold_masked;
- eq_cell->connections["\\B"] = gate_masked;
- eq_cell->connections["\\Y"] = miter_module->new_wire(1, NEW_ID);
- this_condition = eq_cell->connections["\\Y"];
- miter_module->add(eq_cell);
+ eq_cell->setPort("\\A", gold_masked);
+ eq_cell->setPort("\\B", gate_masked);
+ eq_cell->setPort("\\Y", miter_module->addWire(NEW_ID));
+ this_condition = eq_cell->getPort("\\Y");
}
else
{
- RTLIL::Cell *eq_cell = new RTLIL::Cell;
- eq_cell->name = NEW_ID;
- eq_cell->type = "$eqx";
+ RTLIL::Cell *eq_cell = miter_module->addCell(NEW_ID, "$eqx");
eq_cell->parameters["\\A_WIDTH"] = w2_gold->width;
eq_cell->parameters["\\B_WIDTH"] = w2_gate->width;
eq_cell->parameters["\\Y_WIDTH"] = 1;
eq_cell->parameters["\\A_SIGNED"] = 0;
eq_cell->parameters["\\B_SIGNED"] = 0;
- eq_cell->connections["\\A"] = w2_gold;
- eq_cell->connections["\\B"] = w2_gate;
- eq_cell->connections["\\Y"] = miter_module->new_wire(1, NEW_ID);
- this_condition = eq_cell->connections["\\Y"];
- miter_module->add(eq_cell);
+ eq_cell->setPort("\\A", w2_gold);
+ eq_cell->setPort("\\B", w2_gate);
+ eq_cell->setPort("\\Y", miter_module->addWire(NEW_ID));
+ this_condition = eq_cell->getPort("\\Y");
}
if (flag_make_outcmp)
{
- RTLIL::Wire *w_cmp = new RTLIL::Wire;
- w_cmp->name = "\\cmp_" + RTLIL::unescape_id(w1->name);
+ RTLIL::Wire *w_cmp = miter_module->addWire("\\cmp_" + RTLIL::unescape_id(w1->name));
w_cmp->port_output = true;
- miter_module->add(w_cmp);
- miter_module->connections.push_back(RTLIL::SigSig(w_cmp, this_condition));
+ miter_module->connect(RTLIL::SigSig(w_cmp, this_condition));
}
all_conditions.append(this_condition);
}
}
- if (all_conditions.width != 1) {
- RTLIL::Cell *reduce_cell = new RTLIL::Cell;
- reduce_cell->name = NEW_ID;
- reduce_cell->type = "$reduce_and";
- reduce_cell->parameters["\\A_WIDTH"] = all_conditions.width;
+ if (all_conditions.size() != 1) {
+ RTLIL::Cell *reduce_cell = miter_module->addCell(NEW_ID, "$reduce_and");
+ reduce_cell->parameters["\\A_WIDTH"] = all_conditions.size();
reduce_cell->parameters["\\Y_WIDTH"] = 1;
reduce_cell->parameters["\\A_SIGNED"] = 0;
- reduce_cell->connections["\\A"] = all_conditions;
- reduce_cell->connections["\\Y"] = miter_module->new_wire(1, NEW_ID);
- all_conditions = reduce_cell->connections["\\Y"];
- miter_module->add(reduce_cell);
+ reduce_cell->setPort("\\A", all_conditions);
+ reduce_cell->setPort("\\Y", miter_module->addWire(NEW_ID));
+ all_conditions = reduce_cell->getPort("\\Y");
}
if (flag_make_assert) {
- RTLIL::Cell *assert_cell = new RTLIL::Cell;
- assert_cell->name = NEW_ID;
- assert_cell->type = "$assert";
- assert_cell->connections["\\A"] = all_conditions;
- assert_cell->connections["\\EN"] = RTLIL::SigSpec(1, 1);
- miter_module->add(assert_cell);
+ RTLIL::Cell *assert_cell = miter_module->addCell(NEW_ID, "$assert");
+ assert_cell->setPort("\\A", all_conditions);
+ assert_cell->setPort("\\EN", RTLIL::SigSpec(1, 1));
}
- RTLIL::Wire *w_trigger = new RTLIL::Wire;
- w_trigger->name = "\\trigger";
+ RTLIL::Wire *w_trigger = miter_module->addWire("\\trigger");
w_trigger->port_output = true;
- miter_module->add(w_trigger);
- RTLIL::Cell *not_cell = new RTLIL::Cell;
- not_cell->name = NEW_ID;
- not_cell->type = "$not";
- not_cell->parameters["\\A_WIDTH"] = all_conditions.width;
- not_cell->parameters["\\A_WIDTH"] = all_conditions.width;
+ RTLIL::Cell *not_cell = miter_module->addCell(NEW_ID, "$not");
+ not_cell->parameters["\\A_WIDTH"] = all_conditions.size();
+ not_cell->parameters["\\A_WIDTH"] = all_conditions.size();
not_cell->parameters["\\Y_WIDTH"] = w_trigger->width;
not_cell->parameters["\\A_SIGNED"] = 0;
- not_cell->connections["\\A"] = all_conditions;
- not_cell->connections["\\Y"] = w_trigger;
- miter_module->add(not_cell);
+ not_cell->setPort("\\A", all_conditions);
+ not_cell->setPort("\\Y", w_trigger);
miter_module->fixup_ports();
+
+ if (flag_flatten) {
+ log_push();
+ Pass::call_on_module(design, miter_module, "flatten; opt_const -keepdc -undriven;;");
+ log_pop();
+ }
}
struct MiterPass : public Pass {
@@ -313,6 +284,9 @@ struct MiterPass : public Pass {
log(" -make_assert\n");
log(" also create an 'assert' cell that checks if trigger is always low.\n");
log("\n");
+ log(" -flatten\n");
+ log(" call 'flatten; opt_const -keepdc -undriven;;' on the miter circuit.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index c0827159..fd0abf4a 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -30,6 +30,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
+#include <errno.h>
+#include <string.h>
namespace {
@@ -92,19 +94,35 @@ struct SatHelper
RTLIL::SigSpec big_lhs, big_rhs;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
{
if (it.second->attributes.count("\\init") == 0)
continue;
RTLIL::SigSpec lhs = sigmap(it.second);
RTLIL::SigSpec rhs = it.second->attributes.at("\\init");
- log_assert(lhs.width == rhs.width);
+ log_assert(lhs.size() == rhs.size());
+
+ RTLIL::SigSpec removed_bits;
+ for (int i = 0; i < lhs.size(); i++) {
+ RTLIL::SigSpec bit = lhs.extract(i, 1);
+ if (!satgen.initial_state.check_all(bit)) {
+ removed_bits.append(bit);
+ lhs.remove(i, 1);
+ rhs.remove(i, 1);
+ i--;
+ }
+ }
- log("Import set-constraint from init attribute: %s = %s\n", log_signal(lhs), log_signal(rhs));
- big_lhs.remove2(lhs, &big_rhs);
- big_lhs.append(lhs);
- big_rhs.append(rhs);
+ if (removed_bits.size())
+ log("Warning: ignoring initial value on non-register: %s\n", log_signal(removed_bits));
+
+ if (lhs.size()) {
+ log("Import set-constraint from init attribute: %s = %s\n", log_signal(lhs), log_signal(rhs));
+ big_lhs.remove2(lhs, &big_rhs);
+ big_lhs.append(lhs);
+ big_rhs.append(rhs);
+ }
}
for (auto &s : sets_init)
@@ -118,9 +136,9 @@ struct SatHelper
show_signal_pool.add(sigmap(lhs));
show_signal_pool.add(sigmap(rhs));
- if (lhs.width != rhs.width)
+ if (lhs.size() != rhs.size())
log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- s.first.c_str(), log_signal(lhs), lhs.width, s.second.c_str(), log_signal(rhs), rhs.width);
+ s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
log("Import set-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs));
big_lhs.remove2(lhs, &big_rhs);
@@ -130,7 +148,6 @@ struct SatHelper
if (!satgen.initial_state.check_all(big_lhs)) {
RTLIL::SigSpec rem = satgen.initial_state.remove(big_lhs);
- rem.optimize();
log_cmd_error("Found -set-init bits that are not part of the initial_state: %s\n", log_signal(rem));
}
@@ -144,17 +161,17 @@ struct SatHelper
RTLIL::SigSpec rem = satgen.initial_state.export_all();
rem.remove(big_lhs);
big_lhs.append(rem);
- big_rhs.append(RTLIL::SigSpec(RTLIL::State::Sx, rem.width));
+ big_rhs.append(RTLIL::SigSpec(RTLIL::State::Sx, rem.size()));
}
if (set_init_zero) {
RTLIL::SigSpec rem = satgen.initial_state.export_all();
rem.remove(big_lhs);
big_lhs.append(rem);
- big_rhs.append(RTLIL::SigSpec(RTLIL::State::S0, rem.width));
+ big_rhs.append(RTLIL::SigSpec(RTLIL::State::S0, rem.size()));
}
- if (big_lhs.width == 0) {
+ if (big_lhs.size() == 0) {
log("No constraints for initial state found.\n\n");
return;
}
@@ -187,9 +204,9 @@ struct SatHelper
show_signal_pool.add(sigmap(lhs));
show_signal_pool.add(sigmap(rhs));
- if (lhs.width != rhs.width)
+ if (lhs.size() != rhs.size())
log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- s.first.c_str(), log_signal(lhs), lhs.width, s.second.c_str(), log_signal(rhs), rhs.width);
+ s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
log("Import set-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs));
big_lhs.remove2(lhs, &big_rhs);
@@ -208,11 +225,11 @@ struct SatHelper
show_signal_pool.add(sigmap(lhs));
show_signal_pool.add(sigmap(rhs));
- if (lhs.width != rhs.width)
+ if (lhs.size() != rhs.size())
log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- s.first.c_str(), log_signal(lhs), lhs.width, s.second.c_str(), log_signal(rhs), rhs.width);
+ s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
- log("Import set-constraint for timestep: %s = %s\n", log_signal(lhs), log_signal(rhs));
+ log("Import set-constraint for this timestep: %s = %s\n", log_signal(lhs), log_signal(rhs));
big_lhs.remove2(lhs, &big_rhs);
big_lhs.append(lhs);
big_rhs.append(rhs);
@@ -226,7 +243,7 @@ struct SatHelper
log_cmd_error("Failed to parse lhs set expression `%s'.\n", s.c_str());
show_signal_pool.add(sigmap(lhs));
- log("Import unset-constraint for timestep: %s\n", log_signal(lhs));
+ log("Import unset-constraint for this timestep: %s\n", log_signal(lhs));
big_lhs.remove2(lhs, &big_rhs);
}
@@ -289,7 +306,7 @@ struct SatHelper
for (int t = 0; t < 3; t++)
for (auto &sig : sets_def_undef[t]) {
- log("Import %s constraint for timestep: %s\n", t == 0 ? "def" : t == 1 ? "any_undef" : "all_undef", log_signal(sig));
+ log("Import %s constraint for this timestep: %s\n", t == 0 ? "def" : t == 1 ? "any_undef" : "all_undef", log_signal(sig));
std::vector<int> undef_sig = satgen.importUndefSigSpec(sig, timestep);
if (t == 0)
ez.assume(ez.NOT(ez.expression(ezSAT::OpOr, undef_sig)));
@@ -300,11 +317,11 @@ struct SatHelper
}
int import_cell_counter = 0;
- for (auto &c : module->cells)
+ for (auto &c : module->cells_)
if (design->selected(module, c.second)) {
// log("Import cell: %s\n", RTLIL::id2cstr(c.first));
if (satgen.importCell(c.second, timestep)) {
- for (auto &p : c.second->connections)
+ for (auto &p : c.second->connections())
if (ct.cell_output(c.second->type, p.first))
show_drivers.insert(sigmap(p.second), c.second);
import_cell_counter++;
@@ -318,7 +335,7 @@ struct SatHelper
int setup_proof(int timestep = -1)
{
- assert(prove.size() || prove_x.size() || prove_asserts);
+ log_assert(prove.size() || prove_x.size() || prove_asserts);
RTLIL::SigSpec big_lhs, big_rhs;
std::vector<int> prove_bits;
@@ -336,9 +353,9 @@ struct SatHelper
show_signal_pool.add(sigmap(lhs));
show_signal_pool.add(sigmap(rhs));
- if (lhs.width != rhs.width)
+ if (lhs.size() != rhs.size())
log_cmd_error("Proof expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- s.first.c_str(), log_signal(lhs), lhs.width, s.second.c_str(), log_signal(rhs), rhs.width);
+ s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
log("Import proof-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs));
big_lhs.remove2(lhs, &big_rhs);
@@ -364,9 +381,9 @@ struct SatHelper
show_signal_pool.add(sigmap(lhs));
show_signal_pool.add(sigmap(rhs));
- if (lhs.width != rhs.width)
+ if (lhs.size() != rhs.size())
log_cmd_error("Proof-x expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- s.first.c_str(), log_signal(lhs), lhs.width, s.second.c_str(), log_signal(rhs), rhs.width);
+ s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
log("Import proof-x-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs));
big_lhs.remove2(lhs, &big_rhs);
@@ -389,10 +406,8 @@ struct SatHelper
if (prove_asserts) {
RTLIL::SigSpec asserts_a, asserts_en;
satgen.getAsserts(asserts_a, asserts_en, timestep);
- asserts_a.expand();
- asserts_en.expand();
- for (size_t i = 0; i < asserts_a.chunks.size(); i++)
- log("Import proof for assert: %s when %s.\n", log_signal(asserts_a.chunks[i]), log_signal(asserts_en.chunks[i]));
+ for (int i = 0; i < SIZE(asserts_a); i++)
+ log("Import proof for assert: %s when %s.\n", log_signal(asserts_a[i]), log_signal(asserts_en[i]));
prove_bits.push_back(satgen.importAsserts(timestep));
}
@@ -490,7 +505,7 @@ struct SatHelper
final_signals.add(sig);
} else {
for (auto &d : drivers)
- for (auto &p : d->connections) {
+ for (auto &p : d->connections()) {
if (d->type == "$dff" && p.first == "\\CLK")
continue;
if (d->type.substr(0, 6) == "$_DFF_" && p.first == "\\C")
@@ -521,12 +536,12 @@ struct SatHelper
std::vector<int> modelUndefExpressions;
- for (auto &c : modelSig.chunks)
+ for (auto &c : modelSig.chunks())
if (c.wire != NULL)
{
ModelBlockInfo info;
RTLIL::SigSpec chunksig = c;
- info.width = chunksig.width;
+ info.width = chunksig.size();
info.description = log_signal(chunksig);
for (int timestep = -1; timestep <= max_timestep; timestep++)
@@ -551,7 +566,7 @@ struct SatHelper
// Add initial state signals as collected by satgen
//
modelSig = satgen.initial_state.export_all();
- for (auto &c : modelSig.chunks)
+ for (auto &c : modelSig.chunks())
if (c.wire != NULL)
{
ModelBlockInfo info;
@@ -559,7 +574,7 @@ struct SatHelper
info.timestep = 0;
info.offset = modelExpressions.size();
- info.width = chunksig.width;
+ info.width = chunksig.size();
info.description = log_signal(chunksig);
modelInfo.insert(info);
@@ -631,6 +646,109 @@ struct SatHelper
log(" no model variables selected for display.\n");
}
+ void dump_model_to_vcd(std::string vcd_file_name)
+ {
+ FILE *f = fopen(vcd_file_name.c_str(), "w");
+ if (!f)
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", vcd_file_name.c_str(), strerror(errno));
+
+ log("Dumping SAT model to VCD file %s\n", vcd_file_name.c_str());
+
+ time_t timestamp;
+ struct tm* now;
+ char stime[128] = {};
+ time(&timestamp);
+ now = localtime(&timestamp);
+ strftime(stime, sizeof(stime), "%c", now);
+
+ std::string module_fname = "unknown";
+ auto apos = module->attributes.find("\\src");
+ if(apos != module->attributes.end())
+ module_fname = module->attributes["\\src"].decode_string();
+
+ fprintf(f, "$date\n");
+ fprintf(f, " %s\n", stime);
+ fprintf(f, "$end\n");
+ fprintf(f, "$version\n");
+ fprintf(f, " Generated by %s\n", yosys_version_str);
+ fprintf(f, "$end\n");
+ fprintf(f, "$comment\n");
+ fprintf(f, " Generated from SAT problem in module %s (declared at %s)\n",
+ module->name.c_str(), module_fname.c_str());
+ fprintf(f, "$end\n");
+
+ // VCD has some limits on internal (non-display) identifier names, so make legal ones
+ std::map<std::string, std::string> vcdnames;
+
+ fprintf(f, "$timescale 1ns\n"); // arbitrary time scale since actual clock period is unknown/unimportant
+ fprintf(f, "$scope module %s $end\n", module->name.c_str());
+ for (auto &info : modelInfo)
+ {
+ if (vcdnames.find(info.description) != vcdnames.end())
+ continue;
+
+ char namebuf[16];
+ snprintf(namebuf, sizeof(namebuf), "v%d", static_cast<int>(vcdnames.size()));
+ vcdnames[info.description] = namebuf;
+
+ // Even display identifiers can't use some special characters
+ std::string legal_desc = info.description.c_str();
+ for (auto &c : legal_desc) {
+ if(c == '$')
+ c = '_';
+ if(c == ':')
+ c = '_';
+ }
+
+ fprintf(f, "$var wire %d %s %s $end\n", info.width, namebuf, legal_desc.c_str());
+
+ // Need to look at first *two* cycles!
+ // We need to put a name on all variables but those without an initialization clause
+ // have no value at timestep 0
+ if(info.timestep > 1)
+ break;
+ }
+ fprintf(f, "$upscope $end\n");
+ fprintf(f, "$enddefinitions $end\n");
+ fprintf(f, "$dumpvars\n");
+
+ static const char bitvals[] = "01xzxx";
+
+ int last_timestep = -2;
+ for (auto &info : modelInfo)
+ {
+ RTLIL::Const value;
+
+ for (int i = 0; i < info.width; i++) {
+ value.bits.push_back(modelValues.at(info.offset+i) ? RTLIL::State::S1 : RTLIL::State::S0);
+ if (enable_undef && modelValues.at(modelExpressions.size()/2 + info.offset + i))
+ value.bits.back() = RTLIL::State::Sx;
+ }
+
+ if (info.timestep != last_timestep) {
+ if(last_timestep == 0)
+ fprintf(f, "$end\n");
+ else
+ fprintf(f, "#%d\n", info.timestep);
+ last_timestep = info.timestep;
+ }
+
+ if(info.width == 1) {
+ fprintf(f, "%c%s\n", bitvals[value.bits[0]], vcdnames[info.description].c_str());
+ } else {
+ fprintf(f, "b");
+ for(int k=info.width-1; k >= 0; k --) //need to flip bit ordering for VCD
+ fprintf(f, "%c", bitvals[value.bits[k]]);
+ fprintf(f, " %s\n", vcdnames[info.description].c_str());
+ }
+ }
+
+ if (last_timestep == -2)
+ log(" no model variables selected for display.\n");
+
+ fclose(f);
+ }
+
void invalidate_model(bool max_undef)
{
std::vector<int> clause;
@@ -756,7 +874,7 @@ struct SatPass : public Pass {
log(" -set-def-at <N> <signal>\n");
log(" -set-any-undef-at <N> <signal>\n");
log(" -set-all-undef-at <N> <signal>\n");
- log(" add undef contraints in the given timestep.\n");
+ log(" add undef constraints in the given timestep.\n");
log("\n");
log(" -set-init <signal> <value>\n");
log(" set the initial value for the register driving the signal to the value\n");
@@ -770,6 +888,13 @@ struct SatPass : public Pass {
log(" -set-init-zero\n");
log(" set all initial states (not set using -set-init) to zero\n");
log("\n");
+ log(" -dump_vcd <vcd-file-name>\n");
+ log(" dump SAT model (counter example in proof) to VCD file\n");
+ log("\n");
+ log(" -dump_cnf <cnf-file-name>\n");
+ log(" dump CNF of SAT problem (in DIMACS format). in temporal induction\n");
+ log(" proofs this is the CNF of the first induction step.\n");
+ log("\n");
log("The following additional options can be used to set up a proof. If also -seq\n");
log("is passed, a temporal induction proof is performed.\n");
log("\n");
@@ -792,9 +917,15 @@ struct SatPass : public Pass {
log(" -prove-asserts\n");
log(" Prove that all asserts in the design hold.\n");
log("\n");
+ log(" -prove-skip <N>\n");
+ log(" Do not enforce the prove-condition for the first <N> time steps.\n");
+ log("\n");
log(" -maxsteps <N>\n");
log(" Set a maximum length for the induction.\n");
log("\n");
+ log(" -initsteps <N>\n");
+ log(" Set initial length for the induction.\n");
+ log("\n");
log(" -timeout <N>\n");
log(" Maximum number of seconds a single SAT instance may take.\n");
log("\n");
@@ -817,11 +948,12 @@ struct SatPass : public Pass {
std::map<int, std::vector<std::pair<std::string, std::string>>> sets_at;
std::map<int, std::vector<std::string>> unsets_at, sets_def_at, sets_any_undef_at, sets_all_undef_at;
std::vector<std::string> shows, sets_def, sets_any_undef, sets_all_undef;
- int loopcount = 0, seq_len = 0, maxsteps = 0, timeout = 0;
+ int loopcount = 0, seq_len = 0, maxsteps = 0, initsteps = 0, timeout = 0, prove_skip = 0;
bool verify = false, fail_on_timeout = false, enable_undef = false, set_def_inputs = false;
bool ignore_div_by_zero = false, set_init_undef = false, set_init_zero = false, max_undef = false;
bool tempinduct = false, prove_asserts = false, show_inputs = false, show_outputs = false;
bool ignore_unknown_cells = false, falsify = false, tempinduct_def = false, set_init_def = false;
+ std::string vcd_file_name, cnf_file_name;
log_header("Executing SAT pass (solving SAT problems in the circuit).\n");
@@ -861,6 +993,10 @@ struct SatPass : public Pass {
maxsteps = atoi(args[++argidx].c_str());
continue;
}
+ if (args[argidx] == "-initsteps" && argidx+1 < args.size()) {
+ initsteps = atoi(args[++argidx].c_str());
+ continue;
+ }
if (args[argidx] == "-ignore_div_by_zero") {
ignore_div_by_zero = true;
continue;
@@ -926,6 +1062,10 @@ struct SatPass : public Pass {
prove_asserts = true;
continue;
}
+ if (args[argidx] == "-prove-skip" && argidx+1 < args.size()) {
+ prove_skip = atoi(args[++argidx].c_str());
+ continue;
+ }
if (args[argidx] == "-seq" && argidx+1 < args.size()) {
seq_len = atoi(args[++argidx].c_str());
continue;
@@ -995,12 +1135,20 @@ struct SatPass : public Pass {
ignore_unknown_cells = true;
continue;
}
+ if (args[argidx] == "-dump_vcd" && argidx+1 < args.size()) {
+ vcd_file_name = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-dump_cnf" && argidx+1 < args.size()) {
+ cnf_file_name = args[++argidx];
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
RTLIL::Module *module = NULL;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second)) {
if (module)
log_cmd_error("Only one module must be selected for the SAT pass! (selected: %s and %s)\n",
@@ -1013,25 +1161,31 @@ struct SatPass : public Pass {
if (!prove.size() && !prove_x.size() && !prove_asserts && tempinduct)
log_cmd_error("Got -tempinduct but nothing to prove!\n");
+ if (prove_skip && tempinduct)
+ log_cmd_error("Options -prove-skip and -tempinduct don't work with each other.\n");
+
+ if (prove_skip >= seq_len && prove_skip > 0)
+ log_cmd_error("The value of -prove-skip must be smaller than the one of -seq.\n");
+
if (set_init_undef + set_init_zero + set_init_def > 1)
log_cmd_error("The options -set-init-undef, -set-init-def, and -set-init-zero are exclusive!\n");
if (set_def_inputs) {
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->port_input)
- sets_def.push_back(it.second->name);
+ sets_def.push_back(it.second->name.str());
}
if (show_inputs) {
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->port_input)
- shows.push_back(it.second->name);
+ shows.push_back(it.second->name.str());
}
if (show_outputs) {
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->port_output)
- shows.push_back(it.second->name);
+ shows.push_back(it.second->name.str());
}
if (tempinduct)
@@ -1107,6 +1261,8 @@ struct SatPass : public Pass {
log("SAT temporal induction proof finished - model found for base case: FAIL!\n");
print_proof_failed();
basecase.print_model();
+ if(!vcd_file_name.empty())
+ basecase.dump_model_to_vcd(vcd_file_name);
goto tip_failed;
}
@@ -1125,24 +1281,47 @@ struct SatPass : public Pass {
if (inductlen > 1)
inductstep.force_unique_state(1, inductlen + 1);
- log("\n[induction step] Solving problem with %d variables and %d clauses..\n",
- inductstep.ez.numCnfVariables(), inductstep.ez.numCnfClauses());
-
- if (!inductstep.solve(inductstep.ez.NOT(property))) {
- if (inductstep.gotTimeout)
- goto timeout;
- log("Induction step proven: SUCCESS!\n");
- print_qed();
- goto tip_success;
+ if (inductlen < initsteps)
+ {
+ log("\n[induction step] Skipping problem with %d variables and %d clauses (below initsteps).\n",
+ inductstep.ez.numCnfVariables(), inductstep.ez.numCnfClauses());
+ inductstep.ez.assume(property);
}
+ else
+ {
+ if (!cnf_file_name.empty())
+ {
+ FILE *f = fopen(cnf_file_name.c_str(), "w");
+ if (!f)
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno));
- log("Induction step failed. Incrementing induction length.\n");
- inductstep.ez.assume(property);
+ log("Dumping CNF to file `%s'.\n", cnf_file_name.c_str());
+ cnf_file_name.clear();
+
+ inductstep.ez.printDIMACS(f, false);
+ fclose(f);
+ }
- inductstep.print_model();
+ log("\n[induction step] Solving problem with %d variables and %d clauses..\n",
+ inductstep.ez.numCnfVariables(), inductstep.ez.numCnfClauses());
+
+ if (!inductstep.solve(inductstep.ez.NOT(property))) {
+ if (inductstep.gotTimeout)
+ goto timeout;
+ log("Induction step proven: SUCCESS!\n");
+ print_qed();
+ goto tip_success;
+ }
+
+ log("Induction step failed. Incrementing induction length.\n");
+ inductstep.ez.assume(property);
+ inductstep.print_model();
+ }
}
log("\nReached maximum number of time steps -> proof failed.\n");
+ if(!vcd_file_name.empty())
+ inductstep.dump_model_to_vcd(vcd_file_name);
print_proof_failed();
tip_failed:
@@ -1195,7 +1374,8 @@ struct SatPass : public Pass {
for (int timestep = 1; timestep <= seq_len; timestep++) {
sathelper.setup(timestep);
if (sathelper.prove.size() || sathelper.prove_x.size() || sathelper.prove_asserts)
- prove_bits.push_back(sathelper.setup_proof(timestep));
+ if (timestep > prove_skip)
+ prove_bits.push_back(sathelper.setup_proof(timestep));
}
if (sathelper.prove.size() || sathelper.prove_x.size() || sathelper.prove_asserts)
sathelper.ez.assume(sathelper.ez.NOT(sathelper.ez.expression(ezSAT::OpAnd, prove_bits)));
@@ -1203,10 +1383,18 @@ struct SatPass : public Pass {
}
sathelper.generate_model();
-#if 0
- // print CNF for debugging
- sathelper.ez.printDIMACS(stdout, true);
-#endif
+ if (!cnf_file_name.empty())
+ {
+ FILE *f = fopen(cnf_file_name.c_str(), "w");
+ if (!f)
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno));
+
+ log("Dumping CNF to file `%s'.\n", cnf_file_name.c_str());
+ cnf_file_name.clear();
+
+ sathelper.ez.printDIMACS(f, false);
+ fclose(f);
+ }
int rerun_counter = 0;
@@ -1230,6 +1418,9 @@ struct SatPass : public Pass {
sathelper.print_model();
+ if(!vcd_file_name.empty())
+ sathelper.dump_model_to_vcd(vcd_file_name);
+
if (loopcount != 0) {
loopcount--, rerun_counter++;
sathelper.invalidate_model(max_undef);
diff --git a/passes/techmap/.gitignore b/passes/techmap/.gitignore
index ca9d3942..e6dcc6bc 100644
--- a/passes/techmap/.gitignore
+++ b/passes/techmap/.gitignore
@@ -1 +1 @@
-stdcells.inc
+techmap.inc
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index ae1ebbb5..72998f87 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -2,24 +2,30 @@
OBJS += passes/techmap/techmap.o
OBJS += passes/techmap/simplemap.o
OBJS += passes/techmap/dfflibmap.o
+OBJS += passes/techmap/libparse.o
+
+ifneq ($(SMALL),1)
OBJS += passes/techmap/iopadmap.o
OBJS += passes/techmap/hilomap.o
-OBJS += passes/techmap/libparse.o
OBJS += passes/techmap/extract.o
+OBJS += passes/techmap/maccmap.o
+OBJS += passes/techmap/alumacc.o
+endif
-GENFILES += passes/techmap/stdcells.inc
+GENFILES += passes/techmap/techmap.inc
-passes/techmap/stdcells.inc: techlibs/common/stdcells.v
- echo "// autogenerated from $<" > $@.new
- od -v -td1 -w1 $< | awk 'BEGIN { print "static char stdcells_code[] = {"; } $$2 != "" { print $$2 ","; } \
- END { print 0 "};"; }' | fmt >> $@.new
- mv $@.new $@
+passes/techmap/techmap.inc: techlibs/common/techmap.v
+ $(P) echo "// autogenerated from $<" > $@.new
+ $(Q) echo "static char stdcells_code[] = {" >> $@.new
+ $(Q) od -v -td1 -An $< | $(SED) -e 's/[0-9][0-9]*/&,/g' >> $@.new
+ $(Q) echo "0};" >> $@.new
+ $(Q) mv $@.new $@
-passes/techmap/techmap.o: passes/techmap/stdcells.inc
+passes/techmap/techmap.o: passes/techmap/techmap.inc
TARGETS += yosys-filterlib
GENFILES += passes/techmap/filterlib.o
yosys-filterlib: passes/techmap/filterlib.o
- $(CXX) -o yosys-filterlib $(LDFLAGS) $^ $(LDLIBS)
+ $(P) $(CXX) -o yosys-filterlib $(LDFLAGS) $^ $(LDLIBS)
diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc
new file mode 100644
index 00000000..1115eead
--- /dev/null
+++ b/passes/techmap/alumacc.cc
@@ -0,0 +1,563 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/macc.h"
+
+struct AlumaccWorker
+{
+ RTLIL::Module *module;
+ SigMap sigmap;
+
+ struct maccnode_t {
+ Macc macc;
+ RTLIL::Cell *cell;
+ RTLIL::SigSpec y;
+ int users;
+ };
+
+ struct alunode_t
+ {
+ std::vector<RTLIL::Cell*> cells;
+ RTLIL::SigSpec a, b, c, y;
+ std::vector<std::tuple<bool, bool, bool, bool, RTLIL::SigSpec>> cmp;
+ bool is_signed, invert_b;
+
+ RTLIL::Cell *alu_cell;
+ RTLIL::SigSpec cached_lt, cached_gt, cached_eq, cached_ne;
+ RTLIL::SigSpec cached_cf, cached_of, cached_sf;
+
+ RTLIL::SigSpec get_lt() {
+ if (SIZE(cached_lt) == 0)
+ cached_lt = is_signed ? alu_cell->module->Xor(NEW_ID, get_of(), get_sf()) : get_cf();
+ return cached_lt;
+ }
+
+ RTLIL::SigSpec get_gt() {
+ if (SIZE(cached_gt) == 0)
+ cached_gt = alu_cell->module->Not(NEW_ID, alu_cell->module->Or(NEW_ID, get_lt(), get_eq()));
+ return cached_gt;
+ }
+
+ RTLIL::SigSpec get_eq() {
+ if (SIZE(cached_eq) == 0)
+ cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort("\\X"));
+ return cached_eq;
+ }
+
+ RTLIL::SigSpec get_ne() {
+ if (SIZE(cached_ne) == 0)
+ cached_ne = alu_cell->module->Not(NEW_ID, get_eq());
+ return cached_ne;
+ }
+
+ RTLIL::SigSpec get_cf() {
+ if (SIZE(cached_cf) == 0) {
+ cached_cf = alu_cell->getPort("\\CO");
+ log_assert(SIZE(cached_cf) >= 1);
+ cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[SIZE(cached_cf)-1]);
+ }
+ return cached_cf;
+ }
+
+ RTLIL::SigSpec get_of() {
+ if (SIZE(cached_of) == 0) {
+ cached_of = {alu_cell->getPort("\\CO"), alu_cell->getPort("\\CI")};
+ log_assert(SIZE(cached_of) >= 2);
+ cached_of = alu_cell->module->Xor(NEW_ID, cached_of[SIZE(cached_of)-1], cached_of[SIZE(cached_of)-2]);
+ }
+ return cached_of;
+ }
+
+ RTLIL::SigSpec get_sf() {
+ if (SIZE(cached_sf) == 0) {
+ cached_sf = alu_cell->getPort("\\Y");
+ cached_sf = cached_sf[SIZE(cached_sf)-1];
+ }
+ return cached_sf;
+ }
+ };
+
+ std::map<RTLIL::SigBit, int> bit_users;
+ std::map<RTLIL::SigSpec, maccnode_t*> sig_macc;
+ std::map<RTLIL::SigSig, std::set<alunode_t*>> sig_alu;
+ int macc_counter, alu_counter;
+
+ AlumaccWorker(RTLIL::Module *module) : module(module), sigmap(module)
+ {
+ macc_counter = 0;
+ alu_counter = 0;
+ }
+
+ void count_bit_users()
+ {
+ for (auto port : module->ports)
+ for (auto bit : sigmap(module->wire(port)))
+ bit_users[bit]++;
+
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections())
+ for (auto bit : sigmap(conn.second))
+ bit_users[bit]++;
+ }
+
+ void extract_macc()
+ {
+ for (auto cell : module->selected_cells())
+ {
+ if (!cell->type.in("$pos", "$neg", "$add", "$sub", "$mul"))
+ continue;
+
+ log(" creating $macc model for %s (%s).\n", log_id(cell), log_id(cell->type));
+
+ maccnode_t *n = new maccnode_t;
+ Macc::port_t new_port;
+
+ n->cell = cell;
+ n->y = sigmap(cell->getPort("\\Y"));
+ n->users = 0;
+
+ for (auto bit : n->y)
+ n->users = std::max(n->users, bit_users.at(bit) - 1);
+
+ if (cell->type.in("$pos", "$neg"))
+ {
+ new_port.in_a = sigmap(cell->getPort("\\A"));
+ new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ new_port.do_subtract = cell->type == "$neg";
+ n->macc.ports.push_back(new_port);
+ }
+
+ if (cell->type.in("$add", "$sub"))
+ {
+ new_port.in_a = sigmap(cell->getPort("\\A"));
+ new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ new_port.do_subtract = false;
+ n->macc.ports.push_back(new_port);
+
+ new_port.in_a = sigmap(cell->getPort("\\B"));
+ new_port.is_signed = cell->getParam("\\B_SIGNED").as_bool();
+ new_port.do_subtract = cell->type == "$sub";
+ n->macc.ports.push_back(new_port);
+ }
+
+ if (cell->type.in("$mul"))
+ {
+ new_port.in_a = sigmap(cell->getPort("\\A"));
+ new_port.in_b = sigmap(cell->getPort("\\B"));
+ new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ new_port.do_subtract = false;
+ n->macc.ports.push_back(new_port);
+ }
+
+ log_assert(sig_macc.count(n->y) == 0);
+ sig_macc[n->y] = n;
+ }
+ }
+
+ static bool macc_may_overflow(Macc &macc, int width, bool is_signed)
+ {
+ std::vector<int> port_sizes;
+
+ for (auto &port : macc.ports) {
+ if (port.is_signed != is_signed)
+ return true;
+ if (!port.is_signed && port.do_subtract)
+ return true;
+ if (SIZE(port.in_b))
+ port_sizes.push_back(SIZE(port.in_a) + SIZE(port.in_b));
+ else
+ port_sizes.push_back(SIZE(port.in_a));
+ }
+
+ std::sort(port_sizes.begin(), port_sizes.end());
+
+ int acc_sum = 0, acc_shift = 0;
+ for (int sz : port_sizes) {
+ while ((sz - acc_shift) > 20) {
+ if (acc_sum & 1)
+ acc_sum++;
+ acc_sum = acc_sum >> 1;
+ acc_shift++;
+ }
+ acc_sum += (1 << (sz - acc_shift)) - 1;
+ }
+
+ while (acc_sum) {
+ acc_sum = acc_sum >> 1;
+ acc_shift++;
+ }
+
+ return acc_shift > width;
+ }
+
+ void merge_macc()
+ {
+ while (1)
+ {
+ std::set<maccnode_t*> delete_nodes;
+
+ for (auto &it : sig_macc)
+ {
+ auto n = it.second;
+
+ if (delete_nodes.count(n))
+ continue;
+
+ for (int i = 0; i < SIZE(n->macc.ports); i++)
+ {
+ auto &port = n->macc.ports[i];
+
+ if (SIZE(port.in_b) > 0 || sig_macc.count(port.in_a) == 0)
+ continue;
+
+ auto other_n = sig_macc.at(port.in_a);
+
+ if (other_n->users > 1)
+ continue;
+
+ if (SIZE(other_n->y) != SIZE(n->y) && macc_may_overflow(other_n->macc, SIZE(other_n->y), port.is_signed))
+ continue;
+
+ log(" merging $macc model for %s into %s.\n", log_id(other_n->cell), log_id(n->cell));
+
+ bool do_subtract = port.do_subtract;
+ for (int j = 0; j < SIZE(other_n->macc.ports); j++) {
+ if (do_subtract)
+ other_n->macc.ports[j].do_subtract = !other_n->macc.ports[j].do_subtract;
+ if (j == 0)
+ n->macc.ports[i--] = other_n->macc.ports[j];
+ else
+ n->macc.ports.push_back(other_n->macc.ports[j]);
+ }
+
+ delete_nodes.insert(other_n);
+ }
+ }
+
+ if (delete_nodes.empty())
+ break;
+
+ for (auto n : delete_nodes) {
+ sig_macc.erase(n->y);
+ delete n;
+ }
+ }
+ }
+
+ void macc_to_alu()
+ {
+ std::set<maccnode_t*> delete_nodes;
+
+ for (auto &it : sig_macc)
+ {
+ auto n = it.second;
+ RTLIL::SigSpec A, B, C = n->macc.bit_ports;
+ bool a_signed = false, b_signed = false;
+ bool subtract_b = false;
+ alunode_t *alunode;
+
+ for (auto &port : n->macc.ports)
+ if (SIZE(port.in_b) > 0) {
+ goto next_macc;
+ } else if (SIZE(port.in_a) == 1 && !port.is_signed && !port.do_subtract) {
+ C.append(port.in_a);
+ } else if (SIZE(A) || port.do_subtract) {
+ if (SIZE(B))
+ goto next_macc;
+ B = port.in_a;
+ b_signed = port.is_signed;
+ subtract_b = port.do_subtract;
+ } else {
+ if (SIZE(A))
+ goto next_macc;
+ A = port.in_a;
+ a_signed = port.is_signed;
+ }
+
+ if (!a_signed || !b_signed) {
+ if (SIZE(A) == SIZE(n->y))
+ a_signed = false;
+ if (SIZE(B) == SIZE(n->y))
+ b_signed = false;
+ if (a_signed != b_signed)
+ goto next_macc;
+ }
+
+ if (SIZE(A) == 0 && SIZE(C) > 0) {
+ A = C[0];
+ C.remove(0);
+ }
+
+ if (SIZE(B) == 0 && SIZE(C) > 0) {
+ B = C[0];
+ C.remove(0);
+ }
+
+ if (subtract_b)
+ C.append(RTLIL::S1);
+
+ if (SIZE(C) > 1)
+ goto next_macc;
+
+ if (!subtract_b && B < A && SIZE(B))
+ std::swap(A, B);
+
+ log(" creating $alu model for $macc %s.\n", log_id(n->cell));
+
+ alunode = new alunode_t;
+ alunode->cells.push_back(n->cell);
+ alunode->is_signed = a_signed;
+ alunode->invert_b = subtract_b;
+
+ alunode->a = A;
+ alunode->b = B;
+ alunode->c = C;
+ alunode->y = n->y;
+
+ sig_alu[RTLIL::SigSig(A, B)].insert(alunode);
+ delete_nodes.insert(n);
+ next_macc:;
+ }
+
+ for (auto n : delete_nodes) {
+ sig_macc.erase(n->y);
+ delete n;
+ }
+ }
+
+ void replace_macc()
+ {
+ for (auto &it : sig_macc)
+ {
+ auto n = it.second;
+ auto cell = module->addCell(NEW_ID, "$macc");
+ macc_counter++;
+
+ log(" creating $macc cell for %s: %s\n", log_id(n->cell), log_id(cell));
+
+ n->macc.optimize(SIZE(n->y));
+ n->macc.to_cell(cell);
+ cell->setPort("\\Y", n->y);
+ cell->fixup_parameters();
+ module->remove(n->cell);
+ delete n;
+ }
+
+ sig_macc.clear();
+ }
+
+ void extract_cmp_alu()
+ {
+ std::vector<RTLIL::Cell*> lge_cells, eq_cells;
+
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type.in("$lt", "$le", "$ge", "$gt"))
+ lge_cells.push_back(cell);
+ if (cell->type.in("$eq", "$eqx", "$ne", "$nex"))
+ eq_cells.push_back(cell);
+ }
+
+ for (auto cell : lge_cells)
+ {
+ log(" creating $alu model for %s (%s):", log_id(cell), log_id(cell->type));
+
+ bool cmp_less = cell->type.in("$lt", "$le");
+ bool cmp_equal = cell->type.in("$le", "$ge");
+ bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+
+ RTLIL::SigSpec A = sigmap(cell->getPort("\\A"));
+ RTLIL::SigSpec B = sigmap(cell->getPort("\\B"));
+ RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y"));
+
+ if (B < A && SIZE(B)) {
+ cmp_less = !cmp_less;
+ std::swap(A, B);
+ }
+
+ alunode_t *n = nullptr;
+
+ for (auto node : sig_alu[RTLIL::SigSig(A, B)])
+ if (node->is_signed == is_signed && node->invert_b && node->c == RTLIL::S1) {
+ n = node;
+ break;
+ }
+
+ if (n == nullptr) {
+ n = new alunode_t;
+ n->a = A;
+ n->b = B;
+ n->c = RTLIL::S1;
+ n->y = module->addWire(NEW_ID, std::max(SIZE(A), SIZE(B)));
+ n->is_signed = is_signed;
+ n->invert_b = true;
+ sig_alu[RTLIL::SigSig(A, B)].insert(n);
+ log(" new $alu\n");
+ } else {
+ log(" merged with %s.\n", log_id(n->cells.front()));
+ }
+
+ n->cells.push_back(cell);
+ n->cmp.push_back(std::make_tuple(cmp_less, !cmp_less, cmp_equal, false, Y));
+ }
+
+ for (auto cell : eq_cells)
+ {
+ bool cmp_equal = cell->type.in("$eq", "$eqx");
+ bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+
+ RTLIL::SigSpec A = sigmap(cell->getPort("\\A"));
+ RTLIL::SigSpec B = sigmap(cell->getPort("\\B"));
+ RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y"));
+
+ if (B < A && SIZE(B))
+ std::swap(A, B);
+
+ alunode_t *n = nullptr;
+
+ for (auto node : sig_alu[RTLIL::SigSig(A, B)])
+ if (node->is_signed == is_signed && node->invert_b && node->c == RTLIL::S1) {
+ n = node;
+ break;
+ }
+
+ if (n != nullptr) {
+ log(" creating $alu model for %s (%s): merged with %s.\n", log_id(cell), log_id(cell->type), log_id(n->cells.front()));
+ n->cells.push_back(cell);
+ n->cmp.push_back(std::make_tuple(false, false, cmp_equal, !cmp_equal, Y));
+ }
+ }
+ }
+
+ void replace_alu()
+ {
+ for (auto &it1 : sig_alu)
+ for (auto n : it1.second)
+ {
+ if (SIZE(n->b) == 0 && SIZE(n->c) == 0 && SIZE(n->cmp) == 0)
+ {
+ n->alu_cell = module->addPos(NEW_ID, n->a, n->y, n->is_signed);
+
+ log(" creating $pos cell for ");
+ for (int i = 0; i < SIZE(n->cells); i++)
+ log("%s%s", i ? ", ": "", log_id(n->cells[i]));
+ log(": %s\n", log_id(n->alu_cell));
+
+ goto delete_node;
+ }
+
+ n->alu_cell = module->addCell(NEW_ID, "$alu");
+ alu_counter++;
+
+ log(" creating $alu cell for ");
+ for (int i = 0; i < SIZE(n->cells); i++)
+ log("%s%s", i ? ", ": "", log_id(n->cells[i]));
+ log(": %s\n", log_id(n->alu_cell));
+
+ n->alu_cell->setPort("\\A", n->a);
+ n->alu_cell->setPort("\\B", n->b);
+ n->alu_cell->setPort("\\CI", SIZE(n->c) ? n->c : RTLIL::S0);
+ n->alu_cell->setPort("\\BI", n->invert_b ? RTLIL::S1 : RTLIL::S0);
+ n->alu_cell->setPort("\\Y", n->y);
+ n->alu_cell->setPort("\\X", module->addWire(NEW_ID, SIZE(n->y)));
+ n->alu_cell->setPort("\\CO", module->addWire(NEW_ID, SIZE(n->y)));
+ n->alu_cell->fixup_parameters(n->is_signed, n->is_signed);
+
+ for (auto &it : n->cmp)
+ {
+ bool cmp_lt = std::get<0>(it);
+ bool cmp_gt = std::get<1>(it);
+ bool cmp_eq = std::get<2>(it);
+ bool cmp_ne = std::get<3>(it);
+ RTLIL::SigSpec cmp_y = std::get<4>(it);
+
+ RTLIL::SigSpec sig;
+ if (cmp_lt) sig.append(n->get_lt());
+ if (cmp_gt) sig.append(n->get_gt());
+ if (cmp_eq) sig.append(n->get_eq());
+ if (cmp_ne) sig.append(n->get_ne());
+
+ if (SIZE(sig) > 1)
+ sig = module->ReduceOr(NEW_ID, sig);
+
+ sig.extend(SIZE(cmp_y));
+ module->connect(cmp_y, sig);
+ }
+
+ delete_node:
+ for (auto c : n->cells)
+ module->remove(c);
+ delete n;
+ }
+
+ sig_alu.clear();
+ }
+
+ void run()
+ {
+ log("Extracting $alu and $macc cells in module %s:\n", log_id(module));
+
+ count_bit_users();
+ extract_macc();
+ merge_macc();
+ macc_to_alu();
+ replace_macc();
+ extract_cmp_alu();
+ replace_alu();
+
+ log(" created %d $alu and %d $macc cells.\n", alu_counter, macc_counter);
+ }
+};
+
+struct AlumaccPass : public Pass {
+ AlumaccPass() : Pass("alumacc", "extract ALU and MACC cells") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" alumacc [selection]\n");
+ log("\n");
+ log("This pass translates arithmetic operations $add, $mul, $lt, etc. to $alu and\n");
+ log("$macc cells.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Executing ALUMACC pass (create $alu and $macc cells).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ // if (args[argidx] == "-foobar") {
+ // foobar_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto mod : design->selected_modules())
+ if (!mod->has_processes_warn()) {
+ AlumaccWorker worker(mod);
+ worker.run();
+ }
+ }
+} AlumaccPass;
+
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index 23d93353..07993b86 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -21,6 +21,7 @@
#include "kernel/log.h"
#include "libparse.h"
#include <string.h>
+#include <errno.h>
using namespace PASS_DFFLIBMAP;
@@ -28,7 +29,7 @@ struct cell_mapping {
std::string cell_name;
std::map<std::string, char> ports;
};
-static std::map<std::string, cell_mapping> cell_mappings;
+static std::map<RTLIL::IdString, cell_mapping> cell_mappings;
static void logmap(std::string dff)
{
@@ -318,7 +319,7 @@ static bool expand_cellmap(std::string pattern, std::string inv)
bool return_status = false;
for (auto &it : cell_mappings) {
- std::string from = it.first, to = it.first;
+ std::string from = it.first.str(), to = it.first.str();
if (from.size() != pattern.size())
continue;
for (size_t i = 0; i < from.size(); i++) {
@@ -342,7 +343,7 @@ static bool expand_cellmap(std::string pattern, std::string inv)
static void map_sr_to_arst(const char *from, const char *to)
{
- if (cell_mappings.count(to) > 0)
+ if (!cell_mappings.count(from) || cell_mappings.count(to) > 0)
return;
char from_clk_pol = from[8], from_set_pol = from[9], from_clr_pol = from[10];
@@ -387,45 +388,45 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module)
log("Mapping DFF cells in module `%s':\n", module->name.c_str());
std::vector<RTLIL::Cell*> cell_list;
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (design->selected(module, it.second) && cell_mappings.count(it.second->type) > 0)
cell_list.push_back(it.second);
}
std::map<std::string, int> stats;
- for (auto cell : cell_list) {
- cell_mapping &cm = cell_mappings[cell->type];
- RTLIL::Cell *new_cell = new RTLIL::Cell;
- new_cell->name = cell->name;
- new_cell->type = "\\" + cm.cell_name;
+ for (auto cell : cell_list)
+ {
+ auto cell_type = cell->type;
+ auto cell_name = cell->name;
+ auto cell_connections = cell->connections();
+ module->remove(cell);
+
+ cell_mapping &cm = cell_mappings[cell_type];
+ RTLIL::Cell *new_cell = module->addCell(cell_name, "\\" + cm.cell_name);
+
for (auto &port : cm.ports) {
RTLIL::SigSpec sig;
if ('A' <= port.second && port.second <= 'Z') {
- sig = cell->connections[std::string("\\") + port.second];
+ sig = cell_connections[std::string("\\") + port.second];
+ } else
+ if (port.second == 'q') {
+ RTLIL::SigSpec old_sig = cell_connections[std::string("\\") + char(port.second - ('a' - 'A'))];
+ sig = module->addWire(NEW_ID, SIZE(old_sig));
+ module->addNotGate(NEW_ID, sig, old_sig);
} else
if ('a' <= port.second && port.second <= 'z') {
- sig = cell->connections[std::string("\\") + char(port.second - ('a' - 'A'))];
- RTLIL::Cell *inv_cell = new RTLIL::Cell;
- RTLIL::Wire *inv_wire = new RTLIL::Wire;
- inv_cell->name = stringf("$dfflibmap$inv$%d", RTLIL::autoidx);
- inv_wire->name = stringf("$dfflibmap$sig$%d", RTLIL::autoidx++);
- inv_cell->type = "$_INV_";
- inv_cell->connections[port.second == 'q' ? "\\Y" : "\\A"] = sig;
- sig = RTLIL::SigSpec(inv_wire);
- inv_cell->connections[port.second == 'q' ? "\\A" : "\\Y"] = sig;
- module->cells[inv_cell->name] = inv_cell;
- module->wires[inv_wire->name] = inv_wire;
+ sig = cell_connections[std::string("\\") + char(port.second - ('a' - 'A'))];
+ sig = module->NotGate(NEW_ID, sig);
} else
if (port.second == '0' || port.second == '1') {
sig = RTLIL::SigSpec(port.second == '0' ? 0 : 1, 1);
} else
if (port.second != 0)
log_abort();
- new_cell->connections["\\" + port.first] = sig;
+ new_cell->setPort("\\" + port.first, sig);
}
- stats[stringf(" mapped %%d %s cells to %s cells.\n", cell->type.c_str(), new_cell->type.c_str())]++;
- module->cells[cell->name] = new_cell;
- delete cell;
+
+ stats[stringf(" mapped %%d %s cells to %s cells.\n", cell_type.c_str(), new_cell->type.c_str())]++;
}
for (auto &stat: stats)
@@ -467,11 +468,12 @@ struct DfflibmapPass : public Pass {
if (liberty_file.empty())
log_cmd_error("Missing `-liberty liberty_file' option!\n");
- FILE *f = fopen(liberty_file.c_str(), "r");
- if (f == NULL)
+ std::ifstream f;
+ f.open(liberty_file.c_str());
+ if (f.fail())
log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno));
LibertyParser libparser(f);
- fclose(f);
+ f.close();
find_cell(libparser.ast, "$_DFF_N_", false, false, false, false);
find_cell(libparser.ast, "$_DFF_P_", true, false, false, false);
@@ -528,7 +530,7 @@ struct DfflibmapPass : public Pass {
log(" final dff cell mappings:\n");
logmap_all();
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox"))
dfflibmap(design, it.second);
diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc
index eff14ff0..221e9e49 100644
--- a/passes/techmap/extract.cc
+++ b/passes/techmap/extract.cc
@@ -23,7 +23,6 @@
#include "libs/subcircuit/subcircuit.h"
#include <algorithm>
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -34,8 +33,14 @@ namespace
class SubCircuitSolver : public SubCircuit::Solver
{
public:
+ bool ignore_parameters;
+ std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> ignored_parameters;
std::set<RTLIL::IdString> cell_attr, wire_attr;
+ SubCircuitSolver() : ignore_parameters(false)
+ {
+ }
+
bool compareAttributes(const std::set<RTLIL::IdString> &attr, const std::map<RTLIL::IdString, RTLIL::Const> &needleAttr, const std::map<RTLIL::IdString, RTLIL::Const> &haystackAttr)
{
for (auto &it : attr) {
@@ -46,12 +51,70 @@ namespace
return true;
}
+ RTLIL::Const unified_param(RTLIL::IdString cell_type, RTLIL::IdString param, RTLIL::Const value)
+ {
+ if (cell_type.substr(0, 1) != "$" || cell_type.substr(0, 2) == "$_")
+ return value;
+
+ #define param_bool(_n) if (param == _n) return value.as_bool();
+ param_bool("\\ARST_POLARITY");
+ param_bool("\\A_SIGNED");
+ param_bool("\\B_SIGNED");
+ param_bool("\\CLK_ENABLE");
+ param_bool("\\CLK_POLARITY");
+ param_bool("\\CLR_POLARITY");
+ param_bool("\\EN_POLARITY");
+ param_bool("\\SET_POLARITY");
+ param_bool("\\TRANSPARENT");
+ #undef param_bool
+
+ #define param_int(_n) if (param == _n) return value.as_int();
+ param_int("\\ABITS")
+ param_int("\\A_WIDTH")
+ param_int("\\B_WIDTH")
+ param_int("\\CTRL_IN_WIDTH")
+ param_int("\\CTRL_OUT_WIDTH")
+ param_int("\\OFFSET")
+ param_int("\\PRIORITY")
+ param_int("\\RD_PORTS")
+ param_int("\\SIZE")
+ param_int("\\STATE_BITS")
+ param_int("\\STATE_NUM")
+ param_int("\\STATE_NUM_LOG2")
+ param_int("\\STATE_RST")
+ param_int("\\S_WIDTH")
+ param_int("\\TRANS_NUM")
+ param_int("\\WIDTH")
+ param_int("\\WR_PORTS")
+ param_int("\\Y_WIDTH")
+ #undef param_int
+
+ return value;
+ }
+
virtual bool userCompareNodes(const std::string &, const std::string &, void *needleUserData,
const std::string &, const std::string &, void *haystackUserData, const std::map<std::string, std::string> &portMapping)
{
RTLIL::Cell *needleCell = (RTLIL::Cell*) needleUserData;
RTLIL::Cell *haystackCell = (RTLIL::Cell*) haystackUserData;
+ if (!needleCell || !haystackCell) {
+ log_assert(!needleCell && !haystackCell);
+ return true;
+ }
+
+ if (!ignore_parameters) {
+ std::map<RTLIL::IdString, RTLIL::Const> needle_param, haystack_param;
+ for (auto &it : needleCell->parameters)
+ if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(needleCell->type, it.first)))
+ needle_param[it.first] = unified_param(needleCell->type, it.first, it.second);
+ for (auto &it : haystackCell->parameters)
+ if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(haystackCell->type, it.first)))
+ haystack_param[it.first] = unified_param(haystackCell->type, it.first, it.second);
+ if (needle_param != haystack_param)
+ return false;
+ }
+
if (cell_attr.size() > 0 && !compareAttributes(cell_attr, needleCell->attributes, haystackCell->attributes))
return false;
@@ -61,16 +124,13 @@ namespace
RTLIL::Wire *lastHaystackWire = NULL;
std::map<RTLIL::IdString, RTLIL::Const> emptyAttr;
- for (auto &conn : needleCell->connections)
+ for (auto &conn : needleCell->connections())
{
RTLIL::SigSpec needleSig = conn.second;
- RTLIL::SigSpec haystackSig = haystackCell->connections.at(portMapping.at(conn.first));
-
- needleSig.expand();
- haystackSig.expand();
+ RTLIL::SigSpec haystackSig = haystackCell->getPort(portMapping.at(conn.first.str()));
- for (int i = 0; i < std::min(needleSig.width, haystackSig.width); i++) {
- RTLIL::Wire *needleWire = needleSig.chunks.at(i).wire, *haystackWire = haystackSig.chunks.at(i).wire;
+ for (int i = 0; i < std::min(needleSig.size(), haystackSig.size()); i++) {
+ RTLIL::Wire *needleWire = needleSig[i].wire, *haystackWire = haystackSig[i].wire;
if (needleWire != lastNeedleWire || haystackWire != lastHaystackWire)
if (!compareAttributes(wire_attr, needleWire ? needleWire->attributes : emptyAttr, haystackWire ? haystackWire->attributes : emptyAttr))
return false;
@@ -92,7 +152,7 @@ namespace
int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = NULL)
{
SigMap sigmap(mod);
- std::map<RTLIL::SigChunk, bit_ref_t> sig_bit_ref;
+ std::map<RTLIL::SigBit, bit_ref_t> sig_bit_ref;
if (sel && !sel->selected(mod)) {
log(" Skipping module %s as it is not selected.\n", id2cstr(mod->name));
@@ -121,111 +181,106 @@ namespace
std::map<std::pair<RTLIL::Wire*, int>, int> sig_use_count;
if (max_fanout > 0)
- for (auto &cell_it : mod->cells)
+ for (auto &cell_it : mod->cells_)
{
RTLIL::Cell *cell = cell_it.second;
if (!sel || sel->selected(mod, cell))
- for (auto &conn : cell->connections) {
+ for (auto &conn : cell->connections()) {
RTLIL::SigSpec conn_sig = conn.second;
sigmap.apply(conn_sig);
- conn_sig.expand();
- for (auto &chunk : conn_sig.chunks)
- if (chunk.wire != NULL)
- sig_use_count[std::pair<RTLIL::Wire*, int>(chunk.wire, chunk.offset)]++;
+ for (auto &bit : conn_sig)
+ if (bit.wire != NULL)
+ sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)]++;
}
}
// create graph nodes from cells
- for (auto &cell_it : mod->cells)
+ for (auto &cell_it : mod->cells_)
{
RTLIL::Cell *cell = cell_it.second;
if (sel && !sel->selected(mod, cell))
continue;
- std::string type = cell->type;
+ std::string type = cell->type.str();
if (sel == NULL && type.substr(0, 2) == "\\$")
type = type.substr(1);
- graph.createNode(cell->name, type, (void*)cell);
+ graph.createNode(cell->name.str(), type, (void*)cell);
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
{
- graph.createPort(cell->name, conn.first, conn.second.width);
+ graph.createPort(cell->name.str(), conn.first.str(), conn.second.size());
if (split && split->count(std::pair<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0)
continue;
RTLIL::SigSpec conn_sig = conn.second;
sigmap.apply(conn_sig);
- conn_sig.expand();
- for (size_t i = 0; i < conn_sig.chunks.size(); i++)
+ for (int i = 0; i < conn_sig.size(); i++)
{
- auto &chunk = conn_sig.chunks[i];
- assert(chunk.width == 1);
+ auto &bit = conn_sig[i];
- if (chunk.wire == NULL) {
+ if (bit.wire == NULL) {
if (constports) {
std::string node = "$const$x";
- if (chunk.data.bits[0] == RTLIL::State::S0) node = "$const$0";
- if (chunk.data.bits[0] == RTLIL::State::S1) node = "$const$1";
- if (chunk.data.bits[0] == RTLIL::State::Sz) node = "$const$z";
- graph.createConnection(cell->name, conn.first, i, node, "\\Y", 0);
+ if (bit == RTLIL::State::S0) node = "$const$0";
+ if (bit == RTLIL::State::S1) node = "$const$1";
+ if (bit == RTLIL::State::Sz) node = "$const$z";
+ graph.createConnection(cell->name.str(), conn.first.str(), i, node, "\\Y", 0);
} else
- graph.createConstant(cell->name, conn.first, i, int(chunk.data.bits[0]));
+ graph.createConstant(cell->name.str(), conn.first.str(), i, int(bit.data));
continue;
}
- if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(chunk.wire, chunk.offset)] > max_fanout)
+ if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)] > max_fanout)
continue;
- if (sel && !sel->selected(mod, chunk.wire))
+ if (sel && !sel->selected(mod, bit.wire))
continue;
- if (sig_bit_ref.count(chunk) == 0) {
- bit_ref_t &bit_ref = sig_bit_ref[chunk];
- bit_ref.cell = cell->name;
- bit_ref.port = conn.first;
+ if (sig_bit_ref.count(bit) == 0) {
+ bit_ref_t &bit_ref = sig_bit_ref[bit];
+ bit_ref.cell = cell->name.str();
+ bit_ref.port = conn.first.str();
bit_ref.bit = i;
}
- bit_ref_t &bit_ref = sig_bit_ref[chunk];
- graph.createConnection(bit_ref.cell, bit_ref.port, bit_ref.bit, cell->name, conn.first, i);
+ bit_ref_t &bit_ref = sig_bit_ref[bit];
+ graph.createConnection(bit_ref.cell, bit_ref.port, bit_ref.bit, cell->name.str(), conn.first.str(), i);
}
}
}
// mark external signals (used in non-selected cells)
- for (auto &cell_it : mod->cells)
+ for (auto &cell_it : mod->cells_)
{
RTLIL::Cell *cell = cell_it.second;
if (sel && !sel->selected(mod, cell))
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
{
RTLIL::SigSpec conn_sig = conn.second;
sigmap.apply(conn_sig);
- conn_sig.expand();
- for (auto &chunk : conn_sig.chunks)
- if (sig_bit_ref.count(chunk) != 0) {
- bit_ref_t &bit_ref = sig_bit_ref[chunk];
+ for (auto &bit : conn_sig)
+ if (sig_bit_ref.count(bit) != 0) {
+ bit_ref_t &bit_ref = sig_bit_ref[bit];
graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
}
}
}
// mark external signals (used in module ports)
- for (auto &wire_it : mod->wires)
+ for (auto &wire_it : mod->wires_)
{
RTLIL::Wire *wire = wire_it.second;
if (wire->port_id > 0)
{
RTLIL::SigSpec conn_sig(wire);
sigmap.apply(conn_sig);
- conn_sig.expand();
- for (auto &chunk : conn_sig.chunks)
- if (sig_bit_ref.count(chunk) != 0) {
- bit_ref_t &bit_ref = sig_bit_ref[chunk];
+ for (auto &bit : conn_sig)
+ if (sig_bit_ref.count(bit) != 0) {
+ bit_ref_t &bit_ref = sig_bit_ref[bit];
graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
}
}
@@ -238,21 +293,18 @@ namespace
RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match)
{
SigMap sigmap(needle);
- SigSet<std::pair<std::string, int>> sig2port;
+ SigSet<std::pair<RTLIL::IdString, int>> sig2port;
// create new cell
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = stringf("$extract$%s$%d", needle->name.c_str(), RTLIL::autoidx++);
- cell->type = needle->name;
- haystack->add(cell);
+ RTLIL::Cell *cell = haystack->addCell(stringf("$extract$%s$%d", needle->name.c_str(), autoidx++), needle->name);
// create cell ports
- for (auto &it : needle->wires) {
+ for (auto &it : needle->wires_) {
RTLIL::Wire *wire = it.second;
if (wire->port_id > 0) {
for (int i = 0; i < wire->width; i++)
- sig2port.insert(sigmap(RTLIL::SigSpec(wire, 1, i)), std::pair<std::string, int>(wire->name, i));
- cell->connections[wire->name] = RTLIL::SigSpec(RTLIL::State::Sz, wire->width);
+ sig2port.insert(sigmap(RTLIL::SigSpec(wire, i)), std::pair<RTLIL::IdString, int>(wire->name, i));
+ cell->setPort(wire->name, RTLIL::SigSpec(RTLIL::State::Sz, wire->width));
}
}
@@ -266,20 +318,20 @@ namespace
if (needle_cell == NULL)
continue;
- for (auto &conn : needle_cell->connections) {
+ for (auto &conn : needle_cell->connections()) {
RTLIL::SigSpec sig = sigmap(conn.second);
- if (mapping.portMapping.count(conn.first) > 0 && sig2port.has(sigmap(sig))) {
- sig.expand();
- for (int i = 0; i < sig.width; i++)
- for (auto &port : sig2port.find(sig.chunks[i])) {
- RTLIL::SigSpec bitsig = haystack_cell->connections.at(mapping.portMapping[conn.first]).extract(i, 1);
- cell->connections.at(port.first).replace(port.second, bitsig);
+ if (mapping.portMapping.count(conn.first.str()) > 0 && sig2port.has(sigmap(sig))) {
+ for (int i = 0; i < sig.size(); i++)
+ for (auto &port : sig2port.find(sig[i])) {
+ RTLIL::SigSpec bitsig = haystack_cell->getPort(mapping.portMapping[conn.first.str()]).extract(i, 1);
+ RTLIL::SigSpec new_sig = cell->getPort(port.first);
+ new_sig.replace(port.second, bitsig);
+ cell->setPort(port.first, new_sig);
}
}
}
- haystack->cells.erase(haystack_cell->name);
- delete haystack_cell;
+ haystack->remove(haystack_cell);
}
return cell;
@@ -315,6 +367,10 @@ struct ExtractPass : public Pass {
log(" use the modules in this file as reference. This option can be used\n");
log(" multiple times.\n");
log("\n");
+ log(" -map %%<design-name>\n");
+ log(" use the modules in this in-memory design as reference. This option can\n");
+ log(" be used multiple times.\n");
+ log("\n");
log(" -verbose\n");
log(" print debug output while analyzing\n");
log("\n");
@@ -347,6 +403,12 @@ struct ExtractPass : public Pass {
log(" -wire_attr <attribute_name>\n");
log(" Attributes on wires with the given name must match.\n");
log("\n");
+ log(" -ignore_parameters\n");
+ log(" Do not use parameters when matching cells.\n");
+ log("\n");
+ log(" -ignore_param <cell_type> <parameter_name>\n");
+ log(" Do not use this parameter when matching cells.\n");
+ log("\n");
log("This pass does not operate on modules with uprocessed processes in it.\n");
log("(I.e. the 'proc' pass should be used first to convert processes to netlists.)\n");
log("\n");
@@ -494,6 +556,15 @@ struct ExtractPass : public Pass {
solver.wire_attr.insert(RTLIL::escape_id(args[++argidx]));
continue;
}
+ if (args[argidx] == "-ignore_parameters") {
+ solver.ignore_parameters = true;
+ continue;
+ }
+ if (args[argidx] == "-ignore_param" && argidx+2 < args.size()) {
+ solver.ignored_parameters.insert(std::pair<RTLIL::IdString, RTLIL::IdString>(RTLIL::escape_id(args[argidx+1]), RTLIL::escape_id(args[argidx+2])));
+ argidx += 2;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -524,16 +595,33 @@ struct ExtractPass : public Pass {
if (!mine_mode)
{
map = new RTLIL::Design;
- for (auto &filename : map_filenames) {
- FILE *f = fopen(filename.c_str(), "rt");
- if (f == NULL)
- log_cmd_error("Can't open map file `%s'.\n", filename.c_str());
- Frontend::frontend_call(map, f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
- fclose(f);
-
- if (filename.size() <= 3 || filename.substr(filename.size()-3) != ".il") {
- Pass::call(map, "proc");
- Pass::call(map, "opt_clean");
+ for (auto &filename : map_filenames)
+ {
+ if (filename.substr(0, 1) == "%")
+ {
+ if (!saved_designs.count(filename.substr(1))) {
+ delete map;
+ log_cmd_error("Can't saved design `%s'.\n", filename.c_str()+1);
+ }
+ for (auto mod : saved_designs.at(filename.substr(1))->modules())
+ if (!map->has(mod->name))
+ map->add(mod->clone());
+ }
+ else
+ {
+ std::ifstream f;
+ f.open(filename.c_str());
+ if (f.fail()) {
+ delete map;
+ log_cmd_error("Can't open map file `%s'.\n", filename.c_str());
+ }
+ Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
+ f.close();
+
+ if (filename.size() <= 3 || filename.substr(filename.size()-3) != ".il") {
+ Pass::call(map, "proc");
+ Pass::call(map, "opt_clean");
+ }
}
}
}
@@ -544,7 +632,7 @@ struct ExtractPass : public Pass {
log_header("Creating graphs for SubCircuit library.\n");
if (!mine_mode)
- for (auto &mod_it : map->modules) {
+ for (auto &mod_it : map->modules_) {
SubCircuit::Graph mod_graph;
std::string graph_name = "needle_" + RTLIL::unescape_id(mod_it.first);
log("Creating needle graph %s.\n", graph_name.c_str());
@@ -555,7 +643,7 @@ struct ExtractPass : public Pass {
}
}
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
SubCircuit::Graph mod_graph;
std::string graph_name = "haystack_" + RTLIL::unescape_id(mod_it.first);
log("Creating haystack graph %s.\n", graph_name.c_str());
@@ -613,7 +701,7 @@ struct ExtractPass : public Pass {
log("\nFrequent SubCircuit with %d nodes and %d matches:\n", int(result.nodes.size()), result.totalMatchesAfterLimits);
log(" primary match in %s:", id2cstr(haystack_map.at(result.graphId)->name));
for (auto &node : result.nodes)
- log(" %s", id2cstr(node.nodeId));
+ log(" %s", RTLIL::unescape_id(node.nodeId).c_str());
log("\n");
for (auto &it : result.matchesPerGraph)
log(" matches in %s: %d\n", id2cstr(haystack_map.at(it.first)->name), it.second);
@@ -628,49 +716,44 @@ struct ExtractPass : public Pass {
cells.insert((RTLIL::Cell*)node.userData);
for (auto cell : cells)
- for (auto &conn : cell->connections) {
+ for (auto &conn : cell->connections()) {
RTLIL::SigSpec sig = sigmap(conn.second);
- for (auto &chunk : sig.chunks)
+ for (auto &chunk : sig.chunks())
if (chunk.wire != NULL)
wires.insert(chunk.wire);
}
RTLIL::Module *newMod = new RTLIL::Module;
newMod->name = stringf("\\needle%05d_%s_%dx", needleCounter++, id2cstr(haystack_map.at(result.graphId)->name), result.totalMatchesAfterLimits);
- map->modules[newMod->name] = newMod;
+ map->add(newMod);
- int portCounter = 1;
for (auto wire : wires) {
- RTLIL::Wire *newWire = new RTLIL::Wire;
- newWire->name = wire->name;
- newWire->width = wire->width;
- newWire->port_id = portCounter++;
+ RTLIL::Wire *newWire = newMod->addWire(wire->name, wire->width);
newWire->port_input = true;
newWire->port_output = true;
- newMod->add(newWire);
}
+ newMod->fixup_ports();
+
for (auto cell : cells) {
- RTLIL::Cell *newCell = new RTLIL::Cell;
- newCell->name = cell->name;
- newCell->type = cell->type;
+ RTLIL::Cell *newCell = newMod->addCell(cell->name, cell->type);
newCell->parameters = cell->parameters;
- for (auto &conn : cell->connections) {
- RTLIL::SigSpec sig = sigmap(conn.second);
- for (auto &chunk : sig.chunks)
+ for (auto &conn : cell->connections()) {
+ std::vector<RTLIL::SigChunk> chunks = sigmap(conn.second);
+ for (auto &chunk : chunks)
if (chunk.wire != NULL)
- chunk.wire = newMod->wires.at(chunk.wire->name);
- newCell->connections[conn.first] = sig;
+ chunk.wire = newMod->wires_.at(chunk.wire->name);
+ newCell->setPort(conn.first, chunks);
}
- newMod->add(newCell);
}
}
- FILE *f = fopen(mine_outfile.c_str(), "wt");
- if (f == NULL)
+ std::ofstream f;
+ f.open(mine_outfile.c_str(), std::ofstream::trunc);
+ if (f.fail())
log_error("Can't open output file `%s'.\n", mine_outfile.c_str());
- Backend::backend_call(map, f, mine_outfile, "ilang");
- fclose(f);
+ Backend::backend_call(map, &f, mine_outfile, "ilang");
+ f.close();
}
delete map;
diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc
index bc5caa38..784c4cf3 100644
--- a/passes/techmap/hilomap.cc
+++ b/passes/techmap/hilomap.cc
@@ -26,36 +26,28 @@ static std::string locell_celltype, locell_portname;
static bool singleton_mode;
static RTLIL::Module *module;
-static RTLIL::SigChunk last_hi, last_lo;
+static RTLIL::SigBit last_hi, last_lo;
void hilomap_worker(RTLIL::SigSpec &sig)
{
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL && (c.data.bits.at(0) == RTLIL::State::S1) && !hicell_celltype.empty()) {
- if (!singleton_mode || last_hi.width == 0) {
- last_hi = RTLIL::SigChunk(NEW_WIRE(module, 1));
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = RTLIL::escape_id(hicell_celltype);
- cell->connections[RTLIL::escape_id(hicell_portname)] = last_hi;
- module->add(cell);
+ for (auto &bit : sig) {
+ if (bit == RTLIL::State::S1 && !hicell_celltype.empty()) {
+ if (!singleton_mode || last_hi == RTLIL::State::Sm) {
+ last_hi = module->addWire(NEW_ID);
+ RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(hicell_celltype));
+ cell->setPort(RTLIL::escape_id(hicell_portname), last_hi);
}
- c = last_hi;
+ bit = last_hi;
}
- if (c.wire == NULL && (c.data.bits.at(0) == RTLIL::State::S0) && !locell_celltype.empty()) {
- if (!singleton_mode || last_lo.width == 0) {
- last_lo = RTLIL::SigChunk(NEW_WIRE(module, 1));
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = RTLIL::escape_id(locell_celltype);
- cell->connections[RTLIL::escape_id(locell_portname)] = last_lo;
- module->add(cell);
+ if (bit == RTLIL::State::S0 && !locell_celltype.empty()) {
+ if (!singleton_mode || last_lo == RTLIL::State::Sm) {
+ last_lo = module->addWire(NEW_ID);
+ RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(locell_celltype));
+ cell->setPort(RTLIL::escape_id(locell_portname), last_lo);
}
- c = last_lo;
+ bit = last_lo;
}
}
- sig.optimize();
}
struct HilomapPass : public Pass {
@@ -112,15 +104,15 @@ struct HilomapPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
{
module = it.second;
if (!design->selected(module))
continue;
- last_hi = RTLIL::SigChunk();
- last_lo = RTLIL::SigChunk();
+ last_hi = RTLIL::State::Sm;
+ last_lo = RTLIL::State::Sm;
module->rewrite_sigspecs(hilomap_worker);
}
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index b9821497..9cd23ce6 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -57,6 +57,11 @@ struct IopadmapPass : public Pass {
log(" -nameparam <param_name>\n");
log(" Use the specified parameter to set the port name.\n");
log("\n");
+ log(" -bits\n");
+ log(" create individual bit-wide buffers even for ports that\n");
+ log(" are wider. (the default behavio is to create word-wide\n");
+ log(" buffers use -widthparam to set the word size on the cell.)\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
@@ -66,6 +71,7 @@ struct IopadmapPass : public Pass {
std::string outpad_celltype, outpad_portname, outpad_portname2;
std::string inoutpad_celltype, inoutpad_portname, inoutpad_portname2;
std::string widthparam, nameparam;
+ bool flag_bits = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -97,18 +103,22 @@ struct IopadmapPass : public Pass {
nameparam = args[++argidx];
continue;
}
+ if (arg == "-bits") {
+ flag_bits = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
{
RTLIL::Module *module = it.second;
- if (!design->selected(module))
+ if (!design->selected(module) || module->get_bool_attribute("\\blackbox"))
continue;
- for (auto &it2 : module->wires)
+ for (auto &it2 : module->wires_)
{
RTLIL::Wire *wire = it2.second;
@@ -146,31 +156,46 @@ struct IopadmapPass : public Pass {
} else
log_abort();
- if (wire->width != 1 && widthparam.empty()) {
- log("Don't map multi-bit port %s.%s: Missing option -widthparam.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
+ if (!flag_bits && wire->width != 1 && widthparam.empty()) {
+ log("Don't map multi-bit port %s.%s: Missing option -widthparam or -bits.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
continue;
}
log("Mapping port %s.%s using %s.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name), celltype.c_str());
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = RTLIL::escape_id(celltype);
- cell->connections[RTLIL::escape_id(portname)] = RTLIL::SigSpec(wire);
+ RTLIL::Wire *new_wire = NULL;
if (!portname2.empty()) {
- RTLIL::Wire *new_wire = new RTLIL::Wire;
- *new_wire = *wire;
- wire->name = NEW_ID;
- module->wires[wire->name] = wire;
- module->wires[new_wire->name] = new_wire;
- cell->connections[RTLIL::escape_id(portname2)] = RTLIL::SigSpec(new_wire);
+ new_wire = module->addWire(NEW_ID, wire);
+ module->swap_names(new_wire, wire);
+ }
+
+ if (flag_bits)
+ {
+ for (int i = 0; i < wire->width; i++)
+ {
+ RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype));
+ cell->setPort(RTLIL::escape_id(portname), RTLIL::SigSpec(wire, i));
+ if (!portname2.empty())
+ cell->setPort(RTLIL::escape_id(portname2), RTLIL::SigSpec(new_wire, i));
+ if (!widthparam.empty())
+ cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(1);
+ if (!nameparam.empty())
+ cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(stringf("%s[%d]", RTLIL::id2cstr(wire->name), i));
+ cell->attributes["\\keep"] = RTLIL::Const(1);
+ }
+ }
+ else
+ {
+ RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype));
+ cell->setPort(RTLIL::escape_id(portname), RTLIL::SigSpec(wire));
+ if (!portname2.empty())
+ cell->setPort(RTLIL::escape_id(portname2), RTLIL::SigSpec(new_wire));
+ if (!widthparam.empty())
+ cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(wire->width);
+ if (!nameparam.empty())
+ cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(RTLIL::id2cstr(wire->name));
+ cell->attributes["\\keep"] = RTLIL::Const(1);
}
- if (!widthparam.empty())
- cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(wire->width);
- if (!nameparam.empty())
- cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(RTLIL::id2cstr(wire->name));
- cell->attributes["\\keep"] = RTLIL::Const(1);
- module->add(cell);
wire->port_id = 0;
wire->port_input = false;
diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index 8cbb8e2b..612fa111 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -21,6 +21,10 @@
#include <stdlib.h>
#include <string.h>
+#include <istream>
+#include <fstream>
+#include <iostream>
+
#ifndef FILTERLIB
#include "kernel/log.h"
#endif
@@ -63,9 +67,10 @@ void LibertyAst::dump(FILE *f, std::string indent, std::string path, bool path_o
}
fprintf(f, "%s%s", indent.c_str(), id.c_str());
- if (!args.empty()) {
+ if (!args.empty() || !children.empty()) {
+ fprintf(f, "(");
for (size_t i = 0; i < args.size(); i++)
- fprintf(f, "%s%s", i > 0 ? ", " : "(", args[i].c_str());
+ fprintf(f, "%s%s", i > 0 ? ", " : "", args[i].c_str());
fprintf(f, ")");
}
if (!value.empty())
@@ -84,19 +89,19 @@ int LibertyParser::lexer(std::string &str)
int c;
do {
- c = fgetc(f);
+ c = f.get();
} while (c == ' ' || c == '\t' || c == '\r');
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
str = c;
while (1) {
- c = fgetc(f);
+ c = f.get();
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
str += c;
else
break;
}
- ungetc(c, f);
+ f.unget();
// fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str());
return 'v';
}
@@ -104,7 +109,7 @@ int LibertyParser::lexer(std::string &str)
if (c == '"') {
str = c;
while (1) {
- c = fgetc(f);
+ c = f.get();
if (c == '\n')
line++;
str += c;
@@ -116,34 +121,34 @@ int LibertyParser::lexer(std::string &str)
}
if (c == '/') {
- c = fgetc(f);
+ c = f.get();
if (c == '*') {
int last_c = 0;
while (c > 0 && (last_c != '*' || c != '/')) {
last_c = c;
- c = fgetc(f);
+ c = f.get();
if (c == '\n')
line++;
}
return lexer(str);
} else if (c == '/') {
while (c > 0 && c != '\n')
- c = fgetc(f);
+ c = f.get();
line++;
return lexer(str);
}
- ungetc(c, f);
+ f.unget();
// fprintf(stderr, "LEX: char >>/<<\n");
return '/';
}
if (c == '\\') {
- c = fgetc(f);
+ c = f.get();
if (c == '\r')
- c = fgetc(f);
+ c = f.get();
if (c == '\n')
return lexer(str);
- ungetc(c, f);
+ f.unget();
return '\\';
}
@@ -607,16 +612,20 @@ int main(int argc, char **argv)
}
}
- FILE *f = stdin;
+ std::istream *f = &std::cin;
+
if (argc == 3) {
- f = fopen(argv[2], "r");
- if (f == NULL) {
+ std::ifstream *ff = new std::ifstream;
+ ff->open(argv[2]);
+ if (ff->fail()) {
+ delete ff;
fprintf(stderr, "Can't open liberty file `%s'.\n", argv[2]);
usage();
}
+ f = ff;
}
- LibertyParser parser(f);
+ LibertyParser parser(*f);
if (parser.ast) {
if (flag_verilogsim)
gen_verilogsim(parser.ast);
@@ -625,7 +634,7 @@ int main(int argc, char **argv)
}
if (argc == 3)
- fclose(f);
+ delete f;
return 0;
}
diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h
index eff268bb..24748742 100644
--- a/passes/techmap/libparse.h
+++ b/passes/techmap/libparse.h
@@ -41,10 +41,10 @@ namespace PASS_DFFLIBMAP
struct LibertyParser
{
- FILE *f;
+ std::istream &f;
int line;
LibertyAst *ast;
- LibertyParser(FILE *f) : f(f), line(1), ast(parse()) {}
+ LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
~LibertyParser() { if (ast) delete ast; }
int lexer(std::string &str);
LibertyAst *parse();
diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc
new file mode 100644
index 00000000..2d625eef
--- /dev/null
+++ b/passes/techmap/maccmap.cc
@@ -0,0 +1,394 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/macc.h"
+
+extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false);
+
+struct MaccmapWorker
+{
+ std::vector<std::set<RTLIL::SigBit>> bits;
+ RTLIL::Module *module;
+ int width;
+
+ MaccmapWorker(RTLIL::Module *module, int width) : module(module), width(width)
+ {
+ bits.resize(width);
+ }
+
+ void add(RTLIL::SigBit bit, int position)
+ {
+ if (position >= width || bit == RTLIL::S0)
+ return;
+
+ if (bits.at(position).count(bit)) {
+ bits.at(position).erase(bit);
+ add(bit, position+1);
+ } else {
+ bits.at(position).insert(bit);
+ }
+ }
+
+ void add(RTLIL::SigSpec a, bool is_signed, bool do_subtract)
+ {
+ a.extend(width, is_signed);
+
+ if (do_subtract) {
+ a = module->Not(NEW_ID, a);
+ add(RTLIL::S1, 0);
+ }
+
+ for (int i = 0; i < width; i++)
+ add(a[i], i);
+ }
+
+ void add(RTLIL::SigSpec a, RTLIL::SigSpec b, bool is_signed, bool do_subtract)
+ {
+ if (SIZE(a) < SIZE(b))
+ std::swap(a, b);
+
+ a.extend(width, is_signed);
+
+ if (SIZE(b) > width)
+ b.extend(width, is_signed);
+
+ for (int i = 0; i < SIZE(b); i++)
+ if (is_signed && i+1 == SIZE(b))
+ {
+ a = {module->Not(NEW_ID, a.extract(i, width-i)), RTLIL::SigSpec(0, i)};
+ add(module->And(NEW_ID, a, RTLIL::SigSpec(b[i], width)), false, do_subtract);
+ add({b[i], RTLIL::SigSpec(0, i)}, false, do_subtract);
+ }
+ else
+ {
+ add(module->And(NEW_ID, a, RTLIL::SigSpec(b[i], width)), false, do_subtract);
+ a = {a.extract(0, width-1), RTLIL::S0};
+ }
+ }
+
+ void fulladd(RTLIL::SigSpec &in1, RTLIL::SigSpec &in2, RTLIL::SigSpec &in3, RTLIL::SigSpec &out1, RTLIL::SigSpec &out2)
+ {
+ int start_index = 0, stop_index = SIZE(in1);
+
+ while (start_index < stop_index && in1[start_index] == RTLIL::S0 && in2[start_index] == RTLIL::S0 && in3[start_index] == RTLIL::S0)
+ start_index++;
+
+ while (start_index < stop_index && in1[stop_index-1] == RTLIL::S0 && in2[stop_index-1] == RTLIL::S0 && in3[stop_index-1] == RTLIL::S0)
+ stop_index--;
+
+ if (start_index == stop_index)
+ {
+ out1 = RTLIL::SigSpec(0, SIZE(in1));
+ out2 = RTLIL::SigSpec(0, SIZE(in1));
+ }
+ else
+ {
+ RTLIL::SigSpec out_zeros_lsb(0, start_index), out_zeros_msb(0, SIZE(in1)-stop_index);
+
+ in1 = in1.extract(start_index, stop_index-start_index);
+ in2 = in2.extract(start_index, stop_index-start_index);
+ in3 = in3.extract(start_index, stop_index-start_index);
+
+ int width = SIZE(in1);
+ RTLIL::Wire *w1 = module->addWire(NEW_ID, width);
+ RTLIL::Wire *w2 = module->addWire(NEW_ID, width);
+
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$fa");
+ cell->setParam("\\WIDTH", width);
+ cell->setPort("\\A", in1);
+ cell->setPort("\\B", in2);
+ cell->setPort("\\C", in3);
+ cell->setPort("\\Y", w1);
+ cell->setPort("\\X", w2);
+
+ out1 = {out_zeros_msb, w1, out_zeros_lsb};
+ out2 = {out_zeros_msb, w2, out_zeros_lsb};
+ }
+ }
+
+ int tree_bit_slots(int n)
+ {
+ #if 0
+ int retval = 1;
+ while (n > 2) {
+ retval += n / 3;
+ n = 2*(n / 3) + (n % 3);
+ }
+ return retval;
+ #else
+ return std::max(n - 1, 0);
+ #endif
+ }
+
+ RTLIL::SigSpec synth()
+ {
+ std::vector<RTLIL::SigSpec> summands;
+ std::vector<RTLIL::SigBit> tree_sum_bits;
+ int unique_tree_bits = 0;
+ int count_tree_words = 0;
+
+ while (1)
+ {
+ RTLIL::SigSpec summand(0, width);
+ bool got_data_bits = false;
+
+ for (int i = 0; i < width; i++)
+ if (!bits.at(i).empty()) {
+ auto it = bits.at(i).begin();
+ summand[i] = *it;
+ bits.at(i).erase(it);
+ got_data_bits = true;
+ }
+
+ if (!got_data_bits)
+ break;
+
+ summands.push_back(summand);
+
+ while (1)
+ {
+ int free_bit_slots = tree_bit_slots(SIZE(summands)) - SIZE(tree_sum_bits);
+
+ int max_depth = 0, max_position = 0;
+ for (int i = 0; i < width; i++)
+ if (max_depth <= SIZE(bits.at(i))) {
+ max_depth = SIZE(bits.at(i));
+ max_position = i;
+ }
+
+ if (max_depth == 0 || max_position > 4)
+ break;
+
+ int required_bits = 0;
+ for (int i = 0; i <= max_position; i++)
+ if (SIZE(bits.at(i)) == max_depth)
+ required_bits += 1 << i;
+
+ if (required_bits > free_bit_slots)
+ break;
+
+ for (int i = 0; i <= max_position; i++)
+ if (SIZE(bits.at(i)) == max_depth) {
+ auto it = bits.at(i).begin();
+ RTLIL::SigBit bit = *it;
+ for (int k = 0; k < (1 << i); k++, free_bit_slots--)
+ tree_sum_bits.push_back(bit);
+ bits.at(i).erase(it);
+ unique_tree_bits++;
+ }
+
+ count_tree_words++;
+ }
+ }
+
+ if (!tree_sum_bits.empty())
+ log(" packed %d (%d) bits / %d words into adder tree\n", SIZE(tree_sum_bits), unique_tree_bits, count_tree_words);
+
+ if (SIZE(summands) == 0) {
+ log_assert(tree_sum_bits.empty());
+ return RTLIL::SigSpec(0, width);
+ }
+
+ if (SIZE(summands) == 1) {
+ log_assert(tree_sum_bits.empty());
+ return summands.front();
+ }
+
+ while (SIZE(summands) > 2)
+ {
+ std::vector<RTLIL::SigSpec> new_summands;
+ for (int i = 0; i < SIZE(summands); i += 3)
+ if (i+2 < SIZE(summands)) {
+ RTLIL::SigSpec in1 = summands[i];
+ RTLIL::SigSpec in2 = summands[i+1];
+ RTLIL::SigSpec in3 = summands[i+2];
+ RTLIL::SigSpec out1, out2;
+ fulladd(in1, in2, in3, out1, out2);
+ RTLIL::SigBit extra_bit = RTLIL::S0;
+ if (!tree_sum_bits.empty()) {
+ extra_bit = tree_sum_bits.back();
+ tree_sum_bits.pop_back();
+ }
+ new_summands.push_back(out1);
+ new_summands.push_back({out2.extract(0, width-1), extra_bit});
+ } else {
+ new_summands.push_back(summands[i]);
+ i -= 2;
+ }
+ summands.swap(new_summands);
+ }
+
+
+ RTLIL::Cell *c = module->addCell(NEW_ID, "$alu");
+ c->setPort("\\A", summands.front());
+ c->setPort("\\B", summands.back());
+ c->setPort("\\CI", RTLIL::S0);
+ c->setPort("\\BI", RTLIL::S0);
+ c->setPort("\\Y", module->addWire(NEW_ID, width));
+ c->setPort("\\X", module->addWire(NEW_ID, width));
+ c->setPort("\\CO", module->addWire(NEW_ID, width));
+ c->fixup_parameters();
+
+ if (!tree_sum_bits.empty()) {
+ c->setPort("\\CI", tree_sum_bits.back());
+ tree_sum_bits.pop_back();
+ }
+ log_assert(tree_sum_bits.empty());
+
+ return c->getPort("\\Y");
+ }
+};
+
+void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
+{
+ int width = SIZE(cell->getPort("\\Y"));
+
+ Macc macc;
+ macc.from_cell(cell);
+
+ RTLIL::SigSpec all_input_bits;
+ all_input_bits.append(cell->getPort("\\A"));
+ all_input_bits.append(cell->getPort("\\B"));
+
+ if (all_input_bits.to_sigbit_set().count(RTLIL::Sx)) {
+ module->connect(cell->getPort("\\Y"), RTLIL::SigSpec(RTLIL::Sx, width));
+ return;
+ }
+
+ for (auto &port : macc.ports)
+ if (SIZE(port.in_b) == 0)
+ log(" %s %s (%d bits, %s)\n", port.do_subtract ? "sub" : "add", log_signal(port.in_a),
+ SIZE(port.in_a), port.is_signed ? "signed" : "unsigned");
+ else
+ log(" %s %s * %s (%dx%d bits, %s)\n", port.do_subtract ? "sub" : "add", log_signal(port.in_a), log_signal(port.in_b),
+ SIZE(port.in_a), SIZE(port.in_b), port.is_signed ? "signed" : "unsigned");
+
+ if (SIZE(macc.bit_ports) != 0)
+ log(" add bits %s (%d bits)\n", log_signal(macc.bit_ports), SIZE(macc.bit_ports));
+
+ if (unmap)
+ {
+ typedef std::pair<RTLIL::SigSpec, bool> summand_t;
+ std::vector<summand_t> summands;
+
+ for (auto &port : macc.ports) {
+ summand_t this_summand;
+ if (SIZE(port.in_b)) {
+ this_summand.first = module->addWire(NEW_ID, width);
+ module->addMul(NEW_ID, port.in_a, port.in_b, this_summand.first, port.is_signed);
+ } else if (SIZE(port.in_a) != width) {
+ this_summand.first = module->addWire(NEW_ID, width);
+ module->addPos(NEW_ID, port.in_a, this_summand.first, port.is_signed);
+ } else {
+ this_summand.first = port.in_a;
+ }
+ this_summand.second = port.do_subtract;
+ summands.push_back(this_summand);
+ }
+
+ for (auto &bit : macc.bit_ports)
+ summands.push_back(summand_t(bit, false));
+
+ if (SIZE(summands) == 0)
+ summands.push_back(summand_t(RTLIL::SigSpec(0, width), false));
+
+ while (SIZE(summands) > 1)
+ {
+ std::vector<summand_t> new_summands;
+ for (int i = 0; i < SIZE(summands); i += 2) {
+ if (i+1 < SIZE(summands)) {
+ summand_t this_summand;
+ this_summand.first = module->addWire(NEW_ID, width);
+ this_summand.second = summands[i].second && summands[i+1].second;
+ if (summands[i].second == summands[i+1].second)
+ module->addAdd(NEW_ID, summands[i].first, summands[i+1].first, this_summand.first);
+ else if (summands[i].second)
+ module->addSub(NEW_ID, summands[i+1].first, summands[i].first, this_summand.first);
+ else if (summands[i+1].second)
+ module->addSub(NEW_ID, summands[i].first, summands[i+1].first, this_summand.first);
+ else
+ log_abort();
+ new_summands.push_back(this_summand);
+ } else
+ new_summands.push_back(summands[i]);
+ }
+ summands.swap(new_summands);
+ }
+
+ if (summands.front().second)
+ module->addNeg(NEW_ID, summands.front().first, cell->getPort("\\Y"));
+ else
+ module->connect(cell->getPort("\\Y"), summands.front().first);
+ }
+ else
+ {
+ MaccmapWorker worker(module, width);
+
+ for (auto &port : macc.ports)
+ if (SIZE(port.in_b) == 0)
+ worker.add(port.in_a, port.is_signed, port.do_subtract);
+ else
+ worker.add(port.in_a, port.in_b, port.is_signed, port.do_subtract);
+
+ for (auto &bit : macc.bit_ports)
+ worker.add(bit, 0);
+
+ module->connect(cell->getPort("\\Y"), worker.synth());
+ }
+}
+
+struct MaccmapPass : public Pass {
+ MaccmapPass() : Pass("maccmap", "mapping macc cells") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" maccmap [-unmap] [selection]\n");
+ log("\n");
+ log("This pass maps $macc cells to yosys gate primitives. When the -unmap option is\n");
+ log("used then the $macc cell is mapped to $and, $sub, etc. cells instead.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ bool unmap_mode = false;
+
+ log_header("Executing MACCMAP pass (map $macc cells).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-unmap") {
+ unmap_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto mod : design->selected_modules())
+ for (auto cell : mod->selected_cells())
+ if (cell->type == "$macc") {
+ log("Mapping %s.%s (%s).\n", log_id(mod), log_id(cell), log_id(cell->type));
+ maccmap(mod, cell, unmap_mode);
+ mod->remove(cell);
+ }
+ }
+} MaccmapPass;
+
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index e67b1e05..f8d5d458 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -21,84 +21,52 @@
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <string.h>
-extern void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
+extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
static void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\Y_WIDTH").as_int();
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- sig_a.extend(width, cell->parameters.at("\\A_SIGNED").as_bool());
- sig_a.expand();
+ sig_a.extend(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
- sig_y.expand();
-
- for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = "$_INV_";
- gate->connections["\\A"] = sig_a.chunks.at(i);
- gate->connections["\\Y"] = sig_y.chunks.at(i);
- module->add(gate);
+ for (int i = 0; i < SIZE(sig_y); i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
+ gate->setPort("\\A", sig_a[i]);
+ gate->setPort("\\Y", sig_y[i]);
}
}
static void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\Y_WIDTH").as_int();
-
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- sig_a.extend(width, cell->parameters.at("\\A_SIGNED").as_bool());
-
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
-
- module->connections.push_back(RTLIL::SigSig(sig_y, sig_a));
-}
-
-static void simplemap_bu0(RTLIL::Module *module, RTLIL::Cell *cell)
-{
- int width = cell->parameters.at("\\Y_WIDTH").as_int();
-
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- sig_a.extend_u0(width, cell->parameters.at("\\A_SIGNED").as_bool());
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
+ sig_a.extend_u0(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
- module->connections.push_back(RTLIL::SigSig(sig_y, sig_a));
+ module->connect(RTLIL::SigSig(sig_y, sig_a));
}
static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\Y_WIDTH").as_int();
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- sig_a.extend_u0(width, cell->parameters.at("\\A_SIGNED").as_bool());
- sig_a.expand();
-
- RTLIL::SigSpec sig_b = cell->connections.at("\\B");
- sig_b.extend_u0(width, cell->parameters.at("\\B_SIGNED").as_bool());
- sig_b.expand();
-
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
- sig_y.expand();
+ sig_a.extend_u0(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
+ sig_b.extend_u0(SIZE(sig_y), cell->parameters.at("\\B_SIGNED").as_bool());
if (cell->type == "$xnor")
{
- RTLIL::SigSpec sig_t = module->new_wire(width, NEW_ID);
- sig_t.expand();
-
- for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = "$_INV_";
- gate->connections["\\A"] = sig_t.chunks.at(i);
- gate->connections["\\Y"] = sig_y.chunks.at(i);
- module->add(gate);
+ RTLIL::SigSpec sig_t = module->addWire(NEW_ID, SIZE(sig_y));
+
+ for (int i = 0; i < SIZE(sig_y); i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
+ gate->setPort("\\A", sig_t[i]);
+ gate->setPort("\\Y", sig_y[i]);
}
sig_y = sig_t;
@@ -111,38 +79,33 @@ static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
if (cell->type == "$xnor") gate_type = "$_XOR_";
log_assert(!gate_type.empty());
- for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\A"] = sig_a.chunks.at(i);
- gate->connections["\\B"] = sig_b.chunks.at(i);
- gate->connections["\\Y"] = sig_y.chunks.at(i);
- module->add(gate);
+ for (int i = 0; i < SIZE(sig_y); i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\A", sig_a[i]);
+ gate->setPort("\\B", sig_b[i]);
+ gate->setPort("\\Y", sig_y[i]);
}
}
static void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- sig_a.expand();
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
-
- if (sig_y.width == 0)
+ if (sig_y.size() == 0)
return;
- if (sig_a.width == 0) {
- if (cell->type == "$reduce_and") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.width)));
- if (cell->type == "$reduce_or") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.width)));
- if (cell->type == "$reduce_xor") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.width)));
- if (cell->type == "$reduce_xnor") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.width)));
- if (cell->type == "$reduce_bool") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.width)));
+ if (sig_a.size() == 0) {
+ if (cell->type == "$reduce_and") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size())));
+ if (cell->type == "$reduce_or") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
+ if (cell->type == "$reduce_xor") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
+ if (cell->type == "$reduce_xnor") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size())));
+ if (cell->type == "$reduce_bool") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
return;
}
- if (sig_y.width > 1) {
- module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.width-1), RTLIL::SigSpec(0, sig_y.width-1)));
+ if (sig_y.size() > 1) {
+ module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1)));
sig_y = sig_y.extract(0, 1);
}
@@ -154,122 +117,106 @@ static void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
if (cell->type == "$reduce_bool") gate_type = "$_OR_";
log_assert(!gate_type.empty());
- RTLIL::SigSpec *last_output = NULL;
+ RTLIL::Cell *last_output_cell = NULL;
- while (sig_a.width > 1)
+ while (sig_a.size() > 1)
{
- RTLIL::SigSpec sig_t = module->new_wire(sig_a.width / 2, NEW_ID);
- sig_t.expand();
+ RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig_a.size() / 2);
- for (int i = 0; i < sig_a.width; i += 2)
+ for (int i = 0; i < sig_a.size(); i += 2)
{
- if (i+1 == sig_a.width) {
- sig_t.append(sig_a.chunks.at(i));
+ if (i+1 == sig_a.size()) {
+ sig_t.append(sig_a[i]);
continue;
}
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\A"] = sig_a.chunks.at(i);
- gate->connections["\\B"] = sig_a.chunks.at(i+1);
- gate->connections["\\Y"] = sig_t.chunks.at(i/2);
- last_output = &gate->connections["\\Y"];
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\A", sig_a[i]);
+ gate->setPort("\\B", sig_a[i+1]);
+ gate->setPort("\\Y", sig_t[i/2]);
+ last_output_cell = gate;
}
sig_a = sig_t;
}
if (cell->type == "$reduce_xnor") {
- RTLIL::SigSpec sig_t = module->new_wire(1, NEW_ID);
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = "$_INV_";
- gate->connections["\\A"] = sig_a;
- gate->connections["\\Y"] = sig_t;
- last_output = &gate->connections["\\Y"];
- module->add(gate);
+ RTLIL::SigSpec sig_t = module->addWire(NEW_ID);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
+ gate->setPort("\\A", sig_a);
+ gate->setPort("\\Y", sig_t);
+ last_output_cell = gate;
sig_a = sig_t;
}
- if (last_output == NULL) {
- module->connections.push_back(RTLIL::SigSig(sig_y, sig_a));
+ if (last_output_cell == NULL) {
+ module->connect(RTLIL::SigSig(sig_y, sig_a));
} else {
- *last_output = sig_y;
+ last_output_cell->setPort("\\Y", sig_y);
}
}
static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig)
{
- sig.expand();
-
- while (sig.width > 1)
+ while (sig.size() > 1)
{
- RTLIL::SigSpec sig_t = module->new_wire(sig.width / 2, NEW_ID);
- sig_t.expand();
+ RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig.size() / 2);
- for (int i = 0; i < sig.width; i += 2)
+ for (int i = 0; i < sig.size(); i += 2)
{
- if (i+1 == sig.width) {
- sig_t.append(sig.chunks.at(i));
+ if (i+1 == sig.size()) {
+ sig_t.append(sig[i]);
continue;
}
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = "$_OR_";
- gate->connections["\\A"] = sig.chunks.at(i);
- gate->connections["\\B"] = sig.chunks.at(i+1);
- gate->connections["\\Y"] = sig_t.chunks.at(i/2);
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, "$_OR_");
+ gate->setPort("\\A", sig[i]);
+ gate->setPort("\\B", sig[i+1]);
+ gate->setPort("\\Y", sig_t[i/2]);
}
sig = sig_t;
}
- if (sig.width == 0)
+ if (sig.size() == 0)
sig = RTLIL::SigSpec(0, 1);
}
static void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
logic_reduce(module, sig_a);
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- if (sig_y.width == 0)
+ if (sig_y.size() == 0)
return;
- if (sig_y.width > 1) {
- module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.width-1), RTLIL::SigSpec(0, sig_y.width-1)));
+ if (sig_y.size() > 1) {
+ module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1)));
sig_y = sig_y.extract(0, 1);
}
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = "$_INV_";
- gate->connections["\\A"] = sig_a;
- gate->connections["\\Y"] = sig_y;
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
+ gate->setPort("\\A", sig_a);
+ gate->setPort("\\Y", sig_y);
}
static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
logic_reduce(module, sig_a);
- RTLIL::SigSpec sig_b = cell->connections.at("\\B");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
logic_reduce(module, sig_b);
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- if (sig_y.width == 0)
+ if (sig_y.size() == 0)
return;
- if (sig_y.width > 1) {
- module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.width-1), RTLIL::SigSpec(0, sig_y.width-1)));
+ if (sig_y.size() > 1) {
+ module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1)));
sig_y = sig_y.extract(0, 1);
}
@@ -278,54 +225,41 @@ static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
if (cell->type == "$logic_or") gate_type = "$_OR_";
log_assert(!gate_type.empty());
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\A"] = sig_a;
- gate->connections["\\B"] = sig_b;
- gate->connections["\\Y"] = sig_y;
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\A", sig_a);
+ gate->setPort("\\B", sig_b);
+ gate->setPort("\\Y", sig_y);
}
static void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\WIDTH").as_int();
-
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- sig_a.expand();
-
- RTLIL::SigSpec sig_b = cell->connections.at("\\B");
- sig_b.expand();
-
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
- sig_y.expand();
-
- for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = "$_MUX_";
- gate->connections["\\A"] = sig_a.chunks.at(i);
- gate->connections["\\B"] = sig_b.chunks.at(i);
- gate->connections["\\S"] = cell->connections.at("\\S");
- gate->connections["\\Y"] = sig_y.chunks.at(i);
- module->add(gate);
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+
+ for (int i = 0; i < SIZE(sig_y); i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, "$_MUX_");
+ gate->setPort("\\A", sig_a[i]);
+ gate->setPort("\\B", sig_b[i]);
+ gate->setPort("\\S", cell->getPort("\\S"));
+ gate->setPort("\\Y", sig_y[i]);
}
}
static void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell)
{
int offset = cell->parameters.at("\\OFFSET").as_int();
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
- module->connections.push_back(RTLIL::SigSig(sig_y, sig_a.extract(offset, sig_y.width)));
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ module->connect(RTLIL::SigSig(sig_y, sig_a.extract(offset, sig_y.size())));
}
static void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_ab = cell->connections.at("\\A");
- sig_ab.append(cell->connections.at("\\B"));
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
- module->connections.push_back(RTLIL::SigSig(sig_y, sig_ab));
+ RTLIL::SigSpec sig_ab = cell->getPort("\\A");
+ sig_ab.append(cell->getPort("\\B"));
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ module->connect(RTLIL::SigSig(sig_y, sig_ab));
}
static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
@@ -334,25 +268,17 @@ static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N';
char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N';
- RTLIL::SigSpec sig_s = cell->connections.at("\\SET");
- sig_s.expand();
-
- RTLIL::SigSpec sig_r = cell->connections.at("\\CLR");
- sig_r.expand();
-
- RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
- sig_q.expand();
+ RTLIL::SigSpec sig_s = cell->getPort("\\SET");
+ RTLIL::SigSpec sig_r = cell->getPort("\\CLR");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
std::string gate_type = stringf("$_SR_%c%c_", set_pol, clr_pol);
for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\S"] = sig_s.chunks.at(i);
- gate->connections["\\R"] = sig_r.chunks.at(i);
- gate->connections["\\Q"] = sig_q.chunks.at(i);
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\S", sig_s[i]);
+ gate->setPort("\\R", sig_r[i]);
+ gate->setPort("\\Q", sig_q[i]);
}
}
@@ -361,24 +287,17 @@ static void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
int width = cell->parameters.at("\\WIDTH").as_int();
char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
- RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK");
-
- RTLIL::SigSpec sig_d = cell->connections.at("\\D");
- sig_d.expand();
-
- RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
- sig_q.expand();
+ RTLIL::SigSpec sig_clk = cell->getPort("\\CLK");
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
std::string gate_type = stringf("$_DFF_%c_", clk_pol);
for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\C"] = sig_clk;
- gate->connections["\\D"] = sig_d.chunks.at(i);
- gate->connections["\\Q"] = sig_q.chunks.at(i);
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\C", sig_clk);
+ gate->setPort("\\D", sig_d[i]);
+ gate->setPort("\\Q", sig_q[i]);
}
}
@@ -389,32 +308,21 @@ static void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell)
char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N';
char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N';
- RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK");
-
- RTLIL::SigSpec sig_s = cell->connections.at("\\SET");
- sig_s.expand();
-
- RTLIL::SigSpec sig_r = cell->connections.at("\\CLR");
- sig_r.expand();
-
- RTLIL::SigSpec sig_d = cell->connections.at("\\D");
- sig_d.expand();
-
- RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
- sig_q.expand();
+ RTLIL::SigSpec sig_clk = cell->getPort("\\CLK");
+ RTLIL::SigSpec sig_s = cell->getPort("\\SET");
+ RTLIL::SigSpec sig_r = cell->getPort("\\CLR");
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
std::string gate_type = stringf("$_DFFSR_%c%c%c_", clk_pol, set_pol, clr_pol);
for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\C"] = sig_clk;
- gate->connections["\\S"] = sig_s.chunks.at(i);
- gate->connections["\\R"] = sig_r.chunks.at(i);
- gate->connections["\\D"] = sig_d.chunks.at(i);
- gate->connections["\\Q"] = sig_q.chunks.at(i);
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\C", sig_clk);
+ gate->setPort("\\S", sig_s[i]);
+ gate->setPort("\\R", sig_r[i]);
+ gate->setPort("\\D", sig_d[i]);
+ gate->setPort("\\Q", sig_q[i]);
}
}
@@ -428,27 +336,20 @@ static void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell)
while (int(rst_val.size()) < width)
rst_val.push_back(RTLIL::State::S0);
- RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK");
- RTLIL::SigSpec sig_rst = cell->connections.at("\\ARST");
-
- RTLIL::SigSpec sig_d = cell->connections.at("\\D");
- sig_d.expand();
-
- RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
- sig_q.expand();
+ RTLIL::SigSpec sig_clk = cell->getPort("\\CLK");
+ RTLIL::SigSpec sig_rst = cell->getPort("\\ARST");
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
std::string gate_type_0 = stringf("$_DFF_%c%c0_", clk_pol, rst_pol);
std::string gate_type_1 = stringf("$_DFF_%c%c1_", clk_pol, rst_pol);
for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0;
- gate->connections["\\C"] = sig_clk;
- gate->connections["\\R"] = sig_rst;
- gate->connections["\\D"] = sig_d.chunks.at(i);
- gate->connections["\\Q"] = sig_q.chunks.at(i);
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0);
+ gate->setPort("\\C", sig_clk);
+ gate->setPort("\\R", sig_rst);
+ gate->setPort("\\D", sig_d[i]);
+ gate->setPort("\\Q", sig_q[i]);
}
}
@@ -457,32 +358,24 @@ static void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell)
int width = cell->parameters.at("\\WIDTH").as_int();
char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N';
- RTLIL::SigSpec sig_en = cell->connections.at("\\EN");
-
- RTLIL::SigSpec sig_d = cell->connections.at("\\D");
- sig_d.expand();
-
- RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
- sig_q.expand();
+ RTLIL::SigSpec sig_en = cell->getPort("\\EN");
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
std::string gate_type = stringf("$_DLATCH_%c_", en_pol);
for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\E"] = sig_en;
- gate->connections["\\D"] = sig_d.chunks.at(i);
- gate->connections["\\Q"] = sig_q.chunks.at(i);
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\E", sig_en);
+ gate->setPort("\\D", sig_d[i]);
+ gate->setPort("\\Q", sig_q[i]);
}
}
-void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
+void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
{
mappers["$not"] = simplemap_not;
mappers["$pos"] = simplemap_pos;
- mappers["$bu0"] = simplemap_bu0;
mappers["$and"] = simplemap_bitop;
mappers["$or"] = simplemap_bitop;
mappers["$xor"] = simplemap_bitop;
@@ -516,7 +409,7 @@ struct SimplemapPass : public Pass {
log("This pass maps a small selection of simple coarse-grain cells to yosys gate\n");
log("primitives. The following internal cell types are mapped by this pass:\n");
log("\n");
- log(" $not, $pos, $bu0, $and, $or, $xor, $xnor\n");
+ log(" $not, $pos, $and, $or, $xor, $xnor\n");
log(" $reduce_and, $reduce_or, $reduce_xor, $reduce_xnor, $reduce_bool\n");
log(" $logic_not, $logic_and, $logic_or, $mux\n");
log(" $sr, $dff, $dffsr, $adff, $dlatch\n");
@@ -527,25 +420,21 @@ struct SimplemapPass : public Pass {
log_header("Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
extra_args(args, 1, design);
- std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
+ std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
simplemap_get_mappers(mappers);
- for (auto &mod_it : design->modules) {
- if (!design->selected(mod_it.second))
+ for (auto mod : design->modules()) {
+ if (!design->selected(mod))
continue;
- std::vector<RTLIL::Cell*> delete_cells;
- for (auto &cell_it : mod_it.second->cells) {
- if (mappers.count(cell_it.second->type) == 0)
+ std::vector<RTLIL::Cell*> cells = mod->cells();
+ for (auto cell : cells) {
+ if (mappers.count(cell->type) == 0)
continue;
- if (!design->selected(mod_it.second, cell_it.second))
+ if (!design->selected(mod, cell))
continue;
- log("Mapping %s.%s (%s).\n", RTLIL::id2cstr(mod_it.first), RTLIL::id2cstr(cell_it.first), RTLIL::id2cstr(cell_it.second->type));
- mappers.at(cell_it.second->type)(mod_it.second, cell_it.second);
- delete_cells.push_back(cell_it.second);
- }
- for (auto &it : delete_cells) {
- mod_it.second->cells.erase(it->name);
- delete it;
+ log("Mapping %s.%s (%s).\n", log_id(mod), log_id(cell), log_id(cell->type));
+ mappers.at(cell->type)(mod, cell);
+ mod->remove(cell);
}
}
}
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index eeeebd11..ed466faa 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -17,18 +17,22 @@
*
*/
-#include "kernel/register.h"
+#include "kernel/yosys.h"
+#include "kernel/utils.h"
#include "kernel/sigtools.h"
-#include "kernel/log.h"
+#include "libs/sha1/sha1.h"
+
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <string.h>
-#include "passes/techmap/stdcells.inc"
+#include "passes/techmap/techmap.inc"
// see simplemap.cc
-extern void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
+extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
+
+// see maccmap.cc
+extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false);
static void apply_prefix(std::string prefix, std::string &id)
{
@@ -40,327 +44,712 @@ static void apply_prefix(std::string prefix, std::string &id)
static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
{
- for (size_t i = 0; i < sig.chunks.size(); i++) {
- if (sig.chunks[i].wire == NULL)
- continue;
- std::string wire_name = sig.chunks[i].wire->name;
- apply_prefix(prefix, wire_name);
- assert(module->wires.count(wire_name) > 0);
- sig.chunks[i].wire = module->wires[wire_name];
- }
+ std::vector<RTLIL::SigChunk> chunks = sig;
+ for (auto &chunk : chunks)
+ if (chunk.wire != NULL) {
+ std::string wire_name = chunk.wire->name.str();
+ apply_prefix(prefix, wire_name);
+ log_assert(module->wires_.count(wire_name) > 0);
+ chunk.wire = module->wires_[wire_name];
+ }
+ sig = chunks;
}
-std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers;
-std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
-std::map<RTLIL::Module*, bool> techmap_do_cache;
-
-struct TechmapWireData {
- RTLIL::Wire *wire;
- RTLIL::SigSpec value;
-};
+struct TechmapWorker
+{
+ std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers;
+ std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
+ std::map<RTLIL::Module*, bool> techmap_do_cache;
+ std::set<RTLIL::Module*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Module>> module_queue;
-typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires;
+ struct TechmapWireData {
+ RTLIL::Wire *wire;
+ RTLIL::SigSpec value;
+ };
-static TechmapWires techmap_find_special_wires(RTLIL::Module *module)
-{
- TechmapWires result;
+ typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires;
- if (module == NULL)
- return result;
+ bool extern_mode;
+ bool assert_mode;
+ bool flatten_mode;
+ bool recursive_mode;
+ bool autoproc_mode;
- for (auto &it : module->wires) {
- const char *p = it.first.c_str();
- if (*p == '$')
- continue;
-
- const char *q = strrchr(p+1, '.');
- p = q ? q : p+1;
-
- if (!strncmp(p, "_TECHMAP_", 9)) {
- TechmapWireData record;
- record.wire = it.second;
- record.value = it.second;
- result[p].push_back(record);
- it.second->attributes["\\keep"] = RTLIL::Const(1);
- it.second->attributes["\\_techmap_special_"] = RTLIL::Const(1);
- }
+ TechmapWorker()
+ {
+ extern_mode = false;
+ assert_mode = false;
+ flatten_mode = false;
+ recursive_mode = false;
+ autoproc_mode = false;
}
- if (!result.empty()) {
- SigMap sigmap(module);
- for (auto &it1 : result)
- for (auto &it2 : it1.second)
- sigmap.apply(it2.value);
+ std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose)
+ {
+ std::string constmap_info;
+ std::map<RTLIL::SigBit, std::pair<RTLIL::IdString, int>> connbits_map;
+
+ for (auto conn : cell->connections())
+ for (int i = 0; i < SIZE(conn.second); i++) {
+ RTLIL::SigBit bit = sigmap(conn.second[i]);
+ if (bit.wire == nullptr) {
+ if (verbose)
+ log(" Constant input on bit %d of port %s: %s\n", i, log_id(conn.first), log_signal(bit));
+ constmap_info += stringf("|%s %d %d", log_id(conn.first), i, bit.data);
+ } else if (connbits_map.count(bit)) {
+ if (verbose)
+ log(" Bit %d of port %s and bit %d of port %s are connected.\n", i, log_id(conn.first),
+ connbits_map.at(bit).second, log_id(connbits_map.at(bit).first));
+ constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i,
+ log_id(connbits_map.at(bit).first), connbits_map.at(bit).second);
+ } else
+ connbits_map[bit] = std::pair<RTLIL::IdString, int>(conn.first, i);stringf("%s %d", log_id(conn.first), i, bit.data);
+ }
+
+ return stringf("$paramod$constmap:%s%s", sha1(constmap_info).c_str(), tpl->name.c_str());
}
- return result;
-}
+ TechmapWires techmap_find_special_wires(RTLIL::Module *module)
+ {
+ TechmapWires result;
-static void techmap_module_worker(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, bool flatten_mode)
-{
- log("Mapping `%s.%s' using `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(tpl->name));
-
- if (tpl->memories.size() != 0)
- log_error("Technology map yielded memories -> this is not supported.\n");
-
- if (tpl->processes.size() != 0)
- log_error("Technology map yielded processes -> this is not supported.\n");
-
- std::map<RTLIL::IdString, RTLIL::IdString> positional_ports;
-
- for (auto &it : tpl->wires) {
- if (it.second->port_id > 0)
- positional_ports[stringf("$%d", it.second->port_id)] = it.first;
- RTLIL::Wire *w = new RTLIL::Wire(*it.second);
- apply_prefix(cell->name, w->name);
- w->port_input = false;
- w->port_output = false;
- w->port_id = 0;
- if (it.second->get_bool_attribute("\\_techmap_special_"))
- w->attributes.clear();
- module->wires[w->name] = w;
- design->select(module, w);
- }
+ if (module == NULL)
+ return result;
+
+ for (auto &it : module->wires_) {
+ const char *p = it.first.c_str();
+ if (*p == '$')
+ continue;
- SigMap port_signal_map;
+ const char *q = strrchr(p+1, '.');
+ p = q ? q : p+1;
- for (auto &it : cell->connections) {
- RTLIL::IdString portname = it.first;
- if (positional_ports.count(portname) > 0)
- portname = positional_ports.at(portname);
- if (tpl->wires.count(portname) == 0 || tpl->wires.at(portname)->port_id == 0) {
- if (portname.substr(0, 1) == "$")
- log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str());
- continue;
+ if (!strncmp(p, "_TECHMAP_", 9)) {
+ TechmapWireData record;
+ record.wire = it.second;
+ record.value = it.second;
+ result[p].push_back(record);
+ it.second->attributes["\\keep"] = RTLIL::Const(1);
+ it.second->attributes["\\_techmap_special_"] = RTLIL::Const(1);
+ }
}
- RTLIL::Wire *w = tpl->wires.at(portname);
- RTLIL::SigSig c;
- if (w->port_output) {
- c.first = it.second;
- c.second = RTLIL::SigSpec(w);
- apply_prefix(cell->name, c.second, module);
- } else {
- c.first = RTLIL::SigSpec(w);
- c.second = it.second;
- apply_prefix(cell->name, c.first, module);
+
+ if (!result.empty()) {
+ SigMap sigmap(module);
+ for (auto &it1 : result)
+ for (auto &it2 : it1.second)
+ sigmap.apply(it2.value);
}
- if (c.second.width > c.first.width)
- c.second.remove(c.first.width, c.second.width - c.first.width);
- if (c.second.width < c.first.width)
- c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.width - c.second.width));
- assert(c.first.width == c.second.width);
-#if 0
- // more conservative approach:
- // connect internal and external wires
- module->connections.push_back(c);
-#else
- // approach that yields nicer outputs:
- // replace internal wires that are connected to external wires
- if (w->port_output)
- port_signal_map.add(c.second, c.first);
- else
- port_signal_map.add(c.first, c.second);
-#endif
+
+ return result;
}
- for (auto &it : tpl->cells) {
- RTLIL::Cell *c = new RTLIL::Cell(*it.second);
- if (!flatten_mode && c->type.substr(0, 2) == "\\$")
- c->type = c->type.substr(1);
- apply_prefix(cell->name, c->name);
- for (auto &it2 : c->connections) {
- apply_prefix(cell->name, it2.second, module);
- port_signal_map.apply(it2.second);
+ void techmap_module_worker(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl)
+ {
+ if (tpl->memories.size() != 0)
+ log_error("Technology map yielded memories -> this is not supported.\n");
+
+ if (tpl->processes.size() != 0) {
+ log("Technology map yielded processes:\n");
+ for (auto &it : tpl->processes)
+ log(" %s",RTLIL::id2cstr(it.first));
+ if (autoproc_mode) {
+ Pass::call_on_module(tpl->design, tpl, "proc");
+ log_assert(SIZE(tpl->processes) == 0);
+ } else
+ log_error("Technology map yielded processes -> this is not supported (use -autoproc to run 'proc' automatically).\n");
}
- module->cells[c->name] = c;
- design->select(module, c);
- }
- for (auto &it : tpl->connections) {
- RTLIL::SigSig c = it;
- apply_prefix(cell->name, c.first, module);
- apply_prefix(cell->name, c.second, module);
- port_signal_map.apply(c.first);
- port_signal_map.apply(c.second);
- module->connections.push_back(c);
- }
+ std::string orig_cell_name;
+ if (!flatten_mode)
+ for (auto &it : tpl->cells_)
+ if (it.first == "\\_TECHMAP_REPLACE_") {
+ orig_cell_name = cell->name.str();
+ module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str());
+ break;
+ }
- module->cells.erase(cell->name);
- delete cell;
-}
+ std::map<RTLIL::IdString, RTLIL::IdString> positional_ports;
+
+ for (auto &it : tpl->wires_) {
+ if (it.second->port_id > 0)
+ positional_ports[stringf("$%d", it.second->port_id)] = it.first;
+ std::string w_name = it.second->name.str();
+ apply_prefix(cell->name.str(), w_name);
+ RTLIL::Wire *w = module->addWire(w_name, it.second);
+ w->port_input = false;
+ w->port_output = false;
+ w->port_id = 0;
+ if (it.second->get_bool_attribute("\\_techmap_special_"))
+ w->attributes.clear();
+ design->select(module, w);
+ }
-static bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells,
- const std::map<RTLIL::IdString, std::set<RTLIL::IdString>> &celltypeMap, bool flatten_mode)
-{
- if (!design->selected(module))
- return false;
+ SigMap port_signal_map;
+
+ for (auto &it : cell->connections()) {
+ RTLIL::IdString portname = it.first;
+ if (positional_ports.count(portname) > 0)
+ portname = positional_ports.at(portname);
+ if (tpl->wires_.count(portname) == 0 || tpl->wires_.at(portname)->port_id == 0) {
+ if (portname.substr(0, 1) == "$")
+ log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str());
+ continue;
+ }
+ RTLIL::Wire *w = tpl->wires_.at(portname);
+ RTLIL::SigSig c;
+ if (w->port_output) {
+ c.first = it.second;
+ c.second = RTLIL::SigSpec(w);
+ apply_prefix(cell->name.str(), c.second, module);
+ } else {
+ c.first = RTLIL::SigSpec(w);
+ c.second = it.second;
+ apply_prefix(cell->name.str(), c.first, module);
+ }
+ if (c.second.size() > c.first.size())
+ c.second.remove(c.first.size(), c.second.size() - c.first.size());
+ if (c.second.size() < c.first.size())
+ c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.size() - c.second.size()));
+ log_assert(c.first.size() == c.second.size());
+ if (flatten_mode) {
+ // more conservative approach:
+ // connect internal and external wires
+ module->connect(c);
+ } else {
+ // approach that yields nicer outputs:
+ // replace internal wires that are connected to external wires
+ if (w->port_output)
+ port_signal_map.add(c.second, c.first);
+ else
+ port_signal_map.add(c.first, c.second);
+ }
+ }
+
+ for (auto &it : tpl->cells_)
+ {
+ std::string c_name = it.second->name.str();
+
+ if (!flatten_mode && c_name == "\\_TECHMAP_REPLACE_")
+ c_name = orig_cell_name;
+ else
+ apply_prefix(cell->name.str(), c_name);
+
+ RTLIL::Cell *c = module->addCell(c_name, it.second);
+ design->select(module, c);
+
+ if (!flatten_mode && c->type.substr(0, 2) == "\\$")
+ c->type = c->type.substr(1);
- bool log_continue = false;
- bool did_something = false;
- std::vector<std::string> cell_names;
+ for (auto &it2 : c->connections_) {
+ apply_prefix(cell->name.str(), it2.second, module);
+ port_signal_map.apply(it2.second);
+ }
+ }
+
+ for (auto &it : tpl->connections()) {
+ RTLIL::SigSig c = it;
+ apply_prefix(cell->name.str(), c.first, module);
+ apply_prefix(cell->name.str(), c.second, module);
+ port_signal_map.apply(c.first);
+ port_signal_map.apply(c.second);
+ module->connect(c);
+ }
- for (auto &cell_it : module->cells)
- cell_names.push_back(cell_it.first);
+ module->remove(cell);
+ }
- for (auto &cell_name : cell_names)
+ bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells,
+ const std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> &celltypeMap, bool in_recursion)
{
- if (module->cells.count(cell_name) == 0)
- continue;
+ std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping";
+
+ if (!design->selected(module))
+ return false;
- RTLIL::Cell *cell = module->cells[cell_name];
+ bool log_continue = false;
+ bool did_something = false;
- if (!design->selected(module, cell) || handled_cells.count(cell) > 0)
- continue;
+ SigMap sigmap(module);
- if (celltypeMap.count(cell->type) == 0)
- continue;
+ TopoSort<RTLIL::Cell*> cells;
+ std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit;
+ std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell;
- for (auto &tpl_name : celltypeMap.at(cell->type))
+ for (auto cell : module->cells())
{
- std::string derived_name = tpl_name;
- RTLIL::Module *tpl = map->modules[tpl_name];
- std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters;
+ if (!design->selected(module, cell) || handled_cells.count(cell) > 0)
+ continue;
- if (!flatten_mode)
- {
- if (tpl->get_bool_attribute("\\techmap_simplemap")) {
- log("Mapping %s.%s (%s) with simplemap.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
- if (simplemap_mappers.count(cell->type) == 0)
- log_error("No simplemap mapper for cell type %s found!\n", RTLIL::id2cstr(cell->type));
- simplemap_mappers.at(cell->type)(module, cell);
- module->cells.erase(cell->name);
- delete cell;
- cell = NULL;
- did_something = true;
- break;
- }
+ std::string cell_type = cell->type.str();
+ if (in_recursion && cell_type.substr(0, 2) == "\\$")
+ cell_type = cell_type.substr(1);
- for (auto conn : cell->connections) {
- if (conn.first.substr(0, 1) == "$")
- continue;
- if (tpl->wires.count(conn.first) > 0 && tpl->wires.at(conn.first)->port_id > 0)
- continue;
- if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0)
- goto next_tpl;
- parameters[conn.first] = conn.second.as_const();
- }
+ if (celltypeMap.count(cell_type) == 0) {
+ if (assert_mode && cell_type.back() != '_')
+ log_error("(ASSERT MODE) No matching template cell for type %s found.\n", log_id(cell_type));
+ continue;
+ }
- if (0) {
- next_tpl:
- continue;
- }
+ for (auto &conn : cell->connections())
+ {
+ RTLIL::SigSpec sig = sigmap(conn.second);
+ sig.remove_const();
- if (tpl->avail_parameters.count("\\_TECHMAP_CELLTYPE_") != 0)
- parameters["\\_TECHMAP_CELLTYPE_"] = RTLIL::unescape_id(cell->type);
- }
+ if (SIZE(sig) == 0)
+ continue;
- std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters);
- if (techmap_cache.count(key) > 0) {
- tpl = techmap_cache[key];
- } else {
- if (cell->parameters.size() != 0) {
- derived_name = tpl->derive(map, parameters);
- tpl = map->modules[derived_name];
- log_continue = true;
+ for (auto &tpl_name : celltypeMap.at(cell_type)) {
+ RTLIL::Module *tpl = map->modules_[tpl_name];
+ RTLIL::Wire *port = tpl->wire(conn.first);
+ if (port && port->port_input)
+ cell_to_inbit[cell].insert(sig.begin(), sig.end());
+ if (port && port->port_output)
+ for (auto &bit : sig)
+ outbit_to_cell[bit].insert(cell);
}
- techmap_cache[key] = tpl;
}
- if (flatten_mode)
- techmap_do_cache[tpl] = true;
+ cells.node(cell);
+ }
+
+ for (auto &it_right : cell_to_inbit)
+ for (auto &it_sigbit : it_right.second)
+ for (auto &it_left : outbit_to_cell[it_sigbit])
+ cells.edge(it_left, it_right.first);
+
+ cells.sort();
+
+ for (auto cell : cells.sorted)
+ {
+ log_assert(handled_cells.count(cell) == 0);
+ log_assert(cell == module->cell(cell->name));
+ bool mapped_cell = false;
+
+ std::string cell_type = cell->type.str();
+ if (in_recursion && cell_type.substr(0, 2) == "\\$")
+ cell_type = cell_type.substr(1);
- if (techmap_do_cache.count(tpl) == 0)
+ for (auto &tpl_name : celltypeMap.at(cell_type))
{
- bool keep_running = true;
- techmap_do_cache[tpl] = true;
+ RTLIL::IdString derived_name = tpl_name;
+ RTLIL::Module *tpl = map->modules_[tpl_name];
+ std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters;
+
+ if (tpl->get_bool_attribute("\\blackbox"))
+ continue;
- while (keep_running)
+ if (!flatten_mode)
{
- TechmapWires twd = techmap_find_special_wires(tpl);
- keep_running = false;
-
- for (auto &it : twd["_TECHMAP_FAIL_"]) {
- RTLIL::SigSpec value = it.value;
- if (value.is_fully_const() && value.as_bool()) {
- log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n",
- derived_name.c_str(), RTLIL::id2cstr(it.wire->name), log_signal(value));
- techmap_do_cache[tpl] = false;
+ std::string extmapper_name;
+
+ if (tpl->get_bool_attribute("\\techmap_simplemap"))
+ extmapper_name = "simplemap";
+
+ if (tpl->get_bool_attribute("\\techmap_maccmap"))
+ extmapper_name = "maccmap";
+
+ if (tpl->attributes.count("\\techmap_wrap"))
+ extmapper_name = "wrap";
+
+ if (!extmapper_name.empty())
+ {
+ cell->type = cell_type;
+
+ if ((extern_mode && !in_recursion) || extmapper_name == "wrap")
+ {
+ std::string m_name = stringf("$extern:%s:%s", extmapper_name.c_str(), log_id(cell->type));
+
+ for (auto &c : cell->parameters)
+ m_name += stringf(":%s=%s", log_id(c.first), log_signal(c.second));
+
+ if (extmapper_name == "wrap")
+ m_name += ":" + sha1(tpl->attributes.at("\\techmap_wrap").decode_string());
+
+ RTLIL::Design *extmapper_design = extern_mode && !in_recursion ? design : tpl->design;
+ RTLIL::Module *extmapper_module = extmapper_design->module(m_name);
+
+ if (extmapper_module == nullptr)
+ {
+ extmapper_module = extmapper_design->addModule(m_name);
+ RTLIL::Cell *extmapper_cell = extmapper_module->addCell(cell->type, cell);
+
+ int port_counter = 1;
+ for (auto &c : extmapper_cell->connections_) {
+ RTLIL::Wire *w = extmapper_module->addWire(c.first, SIZE(c.second));
+ if (w->name == "\\Y" || w->name == "\\Q")
+ w->port_output = true;
+ else
+ w->port_input = true;
+ w->port_id = port_counter++;
+ c.second = w;
+ }
+
+ extmapper_module->fixup_ports();
+ extmapper_module->check();
+
+ if (extmapper_name == "simplemap") {
+ log("Creating %s with simplemap.\n", log_id(extmapper_module));
+ if (simplemap_mappers.count(extmapper_cell->type) == 0)
+ log_error("No simplemap mapper for cell type %s found!\n", log_id(extmapper_cell->type));
+ simplemap_mappers.at(extmapper_cell->type)(extmapper_module, extmapper_cell);
+ extmapper_module->remove(extmapper_cell);
+ }
+
+ if (extmapper_name == "maccmap") {
+ log("Creating %s with maccmap.\n", log_id(extmapper_module));
+ if (extmapper_cell->type != "$macc")
+ log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(extmapper_cell->type));
+ maccmap(extmapper_module, extmapper_cell);
+ extmapper_module->remove(extmapper_cell);
+ }
+
+ if (extmapper_name == "wrap") {
+ std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string();
+ log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module));
+ Pass::call_on_module(extmapper_design, extmapper_module, cmd_string);
+ log_continue = true;
+ }
+ }
+
+ cell->type = extmapper_module->name;
+ cell->parameters.clear();
+
+ if (!extern_mode || in_recursion) {
+ tpl = extmapper_module;
+ goto use_wrapper_tpl;
+ }
+
+ log("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module));
+ }
+ else
+ {
+ log("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str());
+
+ if (extmapper_name == "simplemap") {
+ if (simplemap_mappers.count(cell->type) == 0)
+ log_error("No simplemap mapper for cell type %s found!\n", RTLIL::id2cstr(cell->type));
+ simplemap_mappers.at(cell->type)(module, cell);
+ }
+
+ if (extmapper_name == "maccmap") {
+ if (cell->type != "$macc")
+ log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(cell->type));
+ maccmap(module, cell);
+ }
+
+ module->remove(cell);
+ cell = NULL;
}
- }
- if (!techmap_do_cache[tpl])
+ did_something = true;
+ mapped_cell = true;
break;
+ }
- for (auto &it : twd)
- {
- if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty())
+ for (auto conn : cell->connections()) {
+ if (conn.first.substr(0, 1) == "$")
+ continue;
+ if (tpl->wires_.count(conn.first) > 0 && tpl->wires_.at(conn.first)->port_id > 0)
continue;
+ if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0)
+ goto next_tpl;
+ parameters[conn.first] = conn.second.as_const();
+ }
+
+ if (0) {
+ next_tpl:
+ continue;
+ }
+
+ if (tpl->avail_parameters.count("\\_TECHMAP_CELLTYPE_") != 0)
+ parameters["\\_TECHMAP_CELLTYPE_"] = RTLIL::unescape_id(cell->type);
+
+ for (auto conn : cell->connections()) {
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector();
+ for (auto &bit : v)
+ bit = RTLIL::SigBit(bit.wire == NULL ? RTLIL::State::S1 : RTLIL::State::S0);
+ parameters[stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const();
+ }
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector();
+ for (auto &bit : v)
+ if (bit.wire != NULL)
+ bit = RTLIL::SigBit(RTLIL::State::Sx);
+ parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const();
+ }
+ }
+
+ int unique_bit_id_counter = 0;
+ std::map<RTLIL::SigBit, int> unique_bit_id;
+ unique_bit_id[RTLIL::State::S0] = unique_bit_id_counter++;
+ unique_bit_id[RTLIL::State::S1] = unique_bit_id_counter++;
+ unique_bit_id[RTLIL::State::Sx] = unique_bit_id_counter++;
+ unique_bit_id[RTLIL::State::Sz] = unique_bit_id_counter++;
+
+ for (auto conn : cell->connections())
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ for (auto &bit : sigmap(conn.second).to_sigbit_vector())
+ if (unique_bit_id.count(bit) == 0)
+ unique_bit_id[bit] = unique_bit_id_counter++;
+ }
- auto &data = it.second.front();
+ int bits = 0;
+ for (int i = 0; i < 32; i++)
+ if (((unique_bit_id_counter-1) & (1 << i)) != 0)
+ bits = i;
+ if (tpl->avail_parameters.count("\\_TECHMAP_BITS_CONNMAP_"))
+ parameters["\\_TECHMAP_BITS_CONNMAP_"] = bits;
+
+ for (auto conn : cell->connections())
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ RTLIL::Const value;
+ for (auto &bit : sigmap(conn.second).to_sigbit_vector()) {
+ RTLIL::Const chunk(unique_bit_id.at(bit), bits);
+ value.bits.insert(value.bits.end(), chunk.bits.begin(), chunk.bits.end());
+ }
+ parameters[stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))] = value;
+ }
+ }
- if (!data.value.is_fully_const())
- log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(data.wire->name), log_signal(data.value));
+ if (0) {
+ use_wrapper_tpl:;
+ // do not register techmap_wrap modules with techmap_cache
+ } else {
+ std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters);
+ if (techmap_cache.count(key) > 0) {
+ tpl = techmap_cache[key];
+ } else {
+ if (cell->parameters.size() != 0) {
+ derived_name = tpl->derive(map, parameters);
+ tpl = map->module(derived_name);
+ log_continue = true;
+ }
+ techmap_cache[key] = tpl;
+ }
+ }
- tpl->wires.erase(data.wire->name);
- const char *p = data.wire->name.c_str();
- const char *q = strrchr(p+1, '.');
- q = q ? q : p+1;
+ if (flatten_mode) {
+ techmap_do_cache[tpl] = true;
+ } else {
+ RTLIL::Module *constmapped_tpl = map->module(constmap_tpl_name(sigmap, tpl, cell, false));
+ if (constmapped_tpl != nullptr)
+ tpl = constmapped_tpl;
+ }
- assert(!strncmp(q, "_TECHMAP_DO_", 12));
- std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12);
- while (tpl->wires.count(new_name))
- new_name += "_";
- data.wire->name = new_name;
- tpl->add(data.wire);
+ if (techmap_do_cache.count(tpl) == 0)
+ {
+ bool keep_running = true;
+ techmap_do_cache[tpl] = true;
- std::string cmd_string = data.value.as_const().decode_string();
+ std::set<std::string> techmap_wire_names;
- RTLIL::Selection tpl_mod_sel(false);
- tpl_mod_sel.select(tpl);
- map->selection_stack.push_back(tpl_mod_sel);
- Pass::call(map, cmd_string);
- map->selection_stack.pop_back();
+ while (keep_running)
+ {
+ TechmapWires twd = techmap_find_special_wires(tpl);
+ keep_running = false;
+
+ for (auto &it : twd)
+ techmap_wire_names.insert(it.first);
+
+ for (auto &it : twd["_TECHMAP_FAIL_"]) {
+ RTLIL::SigSpec value = it.value;
+ if (value.is_fully_const() && value.as_bool()) {
+ log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n",
+ derived_name.c_str(), RTLIL::id2cstr(it.wire->name), log_signal(value));
+ techmap_do_cache[tpl] = false;
+ }
+ }
- keep_running = true;
- break;
+ if (!techmap_do_cache[tpl])
+ break;
+
+ for (auto &it : twd)
+ {
+ if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty())
+ continue;
+
+ auto &data = it.second.front();
+
+ if (!data.value.is_fully_const())
+ log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(data.wire->name), log_signal(data.value));
+
+ techmap_wire_names.erase(it.first);
+
+ const char *p = data.wire->name.c_str();
+ const char *q = strrchr(p+1, '.');
+ q = q ? q : p+1;
+
+ std::string cmd_string = data.value.as_const().decode_string();
+
+ restart_eval_cmd_string:
+ if (cmd_string.rfind("CONSTMAP; ", 0) == 0)
+ {
+ cmd_string = cmd_string.substr(strlen("CONSTMAP; "));
+
+ log("Analyzing pattern of constant bits for this cell:\n");
+ RTLIL::IdString new_tpl_name = constmap_tpl_name(sigmap, tpl, cell, true);
+ log("Creating constmapped module `%s'.\n", log_id(new_tpl_name));
+ log_assert(map->module(new_tpl_name) == nullptr);
+
+ RTLIL::Module *new_tpl = map->addModule(new_tpl_name);
+ tpl->cloneInto(new_tpl);
+
+ techmap_do_cache.erase(tpl);
+ techmap_do_cache[new_tpl] = true;
+ tpl = new_tpl;
+
+ std::map<RTLIL::SigBit, RTLIL::SigBit> port_new2old_map;
+ std::map<RTLIL::SigBit, RTLIL::SigBit> port_connmap;
+ std::map<RTLIL::SigBit, RTLIL::SigBit> cellbits_to_tplbits;
+
+ for (auto wire : tpl->wires().to_vector())
+ {
+ if (!wire->port_input || wire->port_output)
+ continue;
+
+ RTLIL::IdString port_name = wire->name;
+ tpl->rename(wire, NEW_ID);
+
+ RTLIL::Wire *new_wire = tpl->addWire(port_name, wire);
+ wire->port_input = false;
+ wire->port_id = 0;
+
+ for (int i = 0; i < wire->width; i++) {
+ port_new2old_map[RTLIL::SigBit(new_wire, i)] = RTLIL::SigBit(wire, i);
+ port_connmap[RTLIL::SigBit(wire, i)] = RTLIL::SigBit(new_wire, i);
+ }
+ }
+
+ for (auto conn : cell->connections())
+ for (int i = 0; i < SIZE(conn.second); i++)
+ {
+ RTLIL::SigBit bit = sigmap(conn.second[i]);
+ RTLIL::SigBit tplbit(tpl->wire(conn.first), i);
+
+ if (bit.wire == nullptr)
+ {
+ RTLIL::SigBit oldbit = port_new2old_map.at(tplbit);
+ port_connmap.at(oldbit) = bit;
+ }
+ else if (cellbits_to_tplbits.count(bit))
+ {
+ RTLIL::SigBit oldbit = port_new2old_map.at(tplbit);
+ port_connmap.at(oldbit) = cellbits_to_tplbits[bit];
+ }
+ else
+ cellbits_to_tplbits[bit] = tplbit;
+ }
+
+ RTLIL::SigSig port_conn;
+ for (auto &it : port_connmap) {
+ port_conn.first.append_bit(it.first);
+ port_conn.second.append_bit(it.second);
+ }
+ tpl->connect(port_conn);
+
+ tpl->check();
+ goto restart_eval_cmd_string;
+ }
+
+ if (cmd_string.rfind("RECURSION; ", 0) == 0)
+ {
+ cmd_string = cmd_string.substr(strlen("RECURSION; "));
+ while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { }
+ goto restart_eval_cmd_string;
+ }
+
+ Pass::call_on_module(map, tpl, cmd_string);
+
+ log_assert(!strncmp(q, "_TECHMAP_DO_", 12));
+ std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12);
+ while (tpl->wires_.count(new_name))
+ new_name += "_";
+ tpl->rename(data.wire->name, new_name);
+
+ keep_running = true;
+ break;
+ }
+ }
+
+ TechmapWires twd = techmap_find_special_wires(tpl);
+ for (auto &it : twd) {
+ if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_")
+ log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str());
+ if (techmap_do_cache[tpl])
+ for (auto &it2 : it.second)
+ if (!it2.value.is_fully_const())
+ log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value));
+ techmap_wire_names.erase(it.first);
+ }
+
+ for (auto &it : techmap_wire_names)
+ log_error("Techmap special wire %s disappeared. This is considered a fatal error.\n", RTLIL::id2cstr(it));
+
+ if (recursive_mode) {
+ if (log_continue) {
+ log_header("Continuing TECHMAP pass.\n");
+ log_continue = false;
+ }
+ while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { }
}
}
- TechmapWires twd = techmap_find_special_wires(tpl);
- for (auto &it : twd) {
- if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_")
- log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str());
- if (techmap_do_cache[tpl])
- for (auto &it2 : it.second)
- if (!it2.value.is_fully_const())
- log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value));
+ if (techmap_do_cache.at(tpl) == false)
+ continue;
+
+ if (log_continue) {
+ log_header("Continuing TECHMAP pass.\n");
+ log_continue = false;
}
- }
- if (techmap_do_cache.at(tpl) == false)
- continue;
+ if (extern_mode && !in_recursion)
+ {
+ std::string m_name = stringf("$extern:%s", log_id(tpl));
- if (log_continue) {
- log_header("Continuing TECHMAP pass.\n");
- log_continue = false;
+ if (!design->module(m_name))
+ {
+ RTLIL::Module *m = design->addModule(m_name);
+ tpl->cloneInto(m);
+
+ for (auto cell : m->cells()) {
+ if (cell->type.substr(0, 2) == "\\$")
+ cell->type = cell->type.substr(1);
+ }
+
+ module_queue.insert(m);
+ }
+
+ log("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name));
+ cell->type = m_name;
+ cell->parameters.clear();
+ }
+ else
+ {
+ log("%s %s.%s using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(tpl));
+ techmap_module_worker(design, module, cell, tpl);
+ cell = NULL;
+ }
+ did_something = true;
+ mapped_cell = true;
+ break;
}
- techmap_module_worker(design, module, cell, tpl, flatten_mode);
- did_something = true;
- cell = NULL;
- break;
+ if (assert_mode && !mapped_cell)
+ log_error("(ASSERT MODE) Failed to map cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
+
+ handled_cells.insert(cell);
}
- handled_cells.insert(cell);
- }
+ if (log_continue) {
+ log_header("Continuing TECHMAP pass.\n");
+ log_continue = false;
+ }
- if (log_continue) {
- log_header("Continuing TECHMAP pass.\n");
- log_continue = false;
+ return did_something;
}
-
- return did_something;
-}
+};
struct TechmapPass : public Pass {
TechmapPass() : Pass("techmap", "generic technology mapper") { }
@@ -380,11 +769,34 @@ struct TechmapPass : public Pass {
log(" transforms the internal RTL cells to the internal gate\n");
log(" library.\n");
log("\n");
+ log(" -map %%<design-name>\n");
+ log(" like -map above, but with an in-memory design instead of a file.\n");
+ log("\n");
log(" -share_map filename\n");
log(" like -map, but look for the file in the share directory (where the\n");
log(" yosys data files are). this is mainly used internally when techmap\n");
log(" is called from other commands.\n");
log("\n");
+ log(" -extern\n");
+ log(" load the cell implementations as separate modules into the design\n");
+ log(" instead of inlining them.\n");
+ log("\n");
+ log(" -max_iter <number>\n");
+ log(" only run the specified number of iterations.\n");
+ log("\n");
+ log(" -recursive\n");
+ log(" instead of the iterative breadth-first algorithm use a recursive\n");
+ log(" depth-first algorithm. both methods should yield equivialent results,\n");
+ log(" but may differ in performance.\n");
+ log("\n");
+ log(" -autoproc\n");
+ log(" Automatically call \"proc\" on implementations that contain processes.\n");
+ log("\n");
+ log(" -assert\n");
+ log(" this option will cause techmap to exit with an error if it can't map\n");
+ log(" a selected cell. only cell types that end on an underscore are accepted\n");
+ log(" as final cell types by this mode.\n");
+ log("\n");
log(" -D <define>, -I <incdir>\n");
log(" this options are passed as-is to the verilog frontend for loading the\n");
log(" map file. Note that the verilog frontend is also called with the\n");
@@ -397,6 +809,13 @@ struct TechmapPass : public Pass {
log("When a module in the map file has the 'techmap_simplemap' attribute set, techmap\n");
log("will use 'simplemap' (see 'help simplemap') to map cells matching the module.\n");
log("\n");
+ log("When a module in the map file has the 'techmap_maccmap' attribute set, techmap\n");
+ log("will use 'maccmap' (see 'help maccmap') to map cells matching the module.\n");
+ log("\n");
+ log("When a module in the map file has the 'techmap_wrap' attribute set, techmap\n");
+ log("will create a wrapper for the cell and then run the command string that the\n");
+ log("attribute is set to on the wrapper module.\n");
+ log("\n");
log("All wires in the modules from the map file matching the pattern _TECHMAP_*\n");
log("or *._TECHMAP_* are special wires that are used to pass instructions from\n");
log("the mapping module to the techmap command. At the moment the following special\n");
@@ -421,6 +840,20 @@ struct TechmapPass : public Pass {
log(" wire to start out as non-constant and evaluate to a constant value\n");
log(" during processing of other _TECHMAP_DO_* commands.\n");
log("\n");
+ log(" A _TECHMAP_DO_* command may start with the special token 'CONSTMAP; '.\n");
+ log(" in this case techmap will create a copy for each distinct configuration\n");
+ log(" of constant inputs and shorted inputs at this point and import the\n");
+ log(" constant and connected bits into the map module. All further commands\n");
+ log(" are executed in this copy. This is a very convenient way of creating\n");
+ log(" optimizied specializations of techmap modules without using the special\n");
+ log(" parameters described below.\n");
+ log("\n");
+ log(" A _TECHMAP_DO_* command may start with the special token 'RECURSION; '.\n");
+ log(" then techmap will recursively replace the cells in the module with their\n");
+ log(" implementation. This is not affected by the -max_iter option.\n");
+ log("\n");
+ log(" It is possible to combine both prefixes to 'RECURSION; CONSTMAP; '.\n");
+ log("\n");
log("In addition to this special wires, techmap also supports special parameters in\n");
log("modules in the map file:\n");
log("\n");
@@ -428,11 +861,28 @@ struct TechmapPass : public Pass {
log(" When a parameter with this name exists, it will be set to the type name\n");
log(" of the cell that matches the module.\n");
log("\n");
+ log(" _TECHMAP_CONSTMSK_<port-name>_\n");
+ log(" _TECHMAP_CONSTVAL_<port-name>_\n");
+ log(" When this pair of parameters is available in a module for a port, then\n");
+ log(" former has a 1-bit for each constant input bit and the latter has the\n");
+ log(" value for this bit. The unused bits of the latter are set to undef (x).\n");
+ log("\n");
+ log(" _TECHMAP_BITS_CONNMAP_\n");
+ log(" _TECHMAP_CONNMAP_<port-name>_\n");
+ log(" For an N-bit port, the _TECHMAP_CONNMAP_<port-name>_ parameter, if it\n");
+ log(" exists, will be set to an N*_TECHMAP_BITS_CONNMAP_ bit vector containing\n");
+ log(" N words (of _TECHMAP_BITS_CONNMAP_ bits each) that assign each single\n");
+ log(" bit driver a unique id. The values 0-3 are reserved for 0, 1, x, and z.\n");
+ log(" This can be used to detect shorted inputs.\n");
+ log("\n");
log("When a module in the map file has a parameter where the according cell in the\n");
log("design has a port, the module from the map file is only used if the port in\n");
log("the design is connected to a constant value. The parameter is then set to the\n");
log("constant value.\n");
log("\n");
+ log("A cell with the name _TECHMAP_REPLACE_ in the map file will inherit the name\n");
+ log("of the cell that is beeing replaced.\n");
+ log("\n");
log("See 'help extract' for a pass that does the opposite thing.\n");
log("\n");
log("See 'help flatten' for a pass that does flatten the design (which is\n");
@@ -444,17 +894,28 @@ struct TechmapPass : public Pass {
log_header("Executing TECHMAP pass (map to technology primitives).\n");
log_push();
+ TechmapWorker worker;
+ simplemap_get_mappers(worker.simplemap_mappers);
+
std::vector<std::string> map_files;
std::string verilog_frontend = "verilog -ignore_redef";
+ int max_iter = -1;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-map" && argidx+1 < args.size()) {
- map_files.push_back(args[++argidx]);
+ if (args[argidx+1].substr(0, 2) == "+/")
+ map_files.push_back(proc_share_dirname() + args[++argidx].substr(2));
+ else
+ map_files.push_back(args[++argidx]);
continue;
}
if (args[argidx] == "-share_map" && argidx+1 < args.size()) {
- map_files.push_back(get_share_file_name(args[++argidx]));
+ map_files.push_back(proc_share_dirname() + args[++argidx]);
+ continue;
+ }
+ if (args[argidx] == "-max_iter" && argidx+1 < args.size()) {
+ max_iter = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-D" && argidx+1 < args.size()) {
@@ -465,36 +926,58 @@ struct TechmapPass : public Pass {
verilog_frontend += " -I " + args[++argidx];
continue;
}
+ if (args[argidx] == "-assert") {
+ worker.assert_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-extern") {
+ worker.extern_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-recursive") {
+ worker.recursive_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-autoproc") {
+ worker.autoproc_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
- simplemap_get_mappers(simplemap_mappers);
-
RTLIL::Design *map = new RTLIL::Design;
if (map_files.empty()) {
- FILE *f = fmemopen(stdcells_code, strlen(stdcells_code), "rt");
- Frontend::frontend_call(map, f, "<stdcells.v>", verilog_frontend);
- fclose(f);
+ std::istringstream f(stdcells_code);
+ Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend);
} else
- for (auto &fn : map_files) {
- FILE *f = fopen(fn.c_str(), "rt");
- if (f == NULL)
- log_cmd_error("Can't open map file `%s'\n", fn.c_str());
- Frontend::frontend_call(map, f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
- fclose(f);
- }
+ for (auto &fn : map_files)
+ if (fn.substr(0, 1) == "%") {
+ if (!saved_designs.count(fn.substr(1))) {
+ delete map;
+ log_cmd_error("Can't saved design `%s'.\n", fn.c_str()+1);
+ }
+ for (auto mod : saved_designs.at(fn.substr(1))->modules())
+ if (!map->has(mod->name))
+ map->add(mod->clone());
+ } else {
+ std::ifstream f;
+ f.open(fn.c_str());
+ if (f.fail())
+ log_cmd_error("Can't open map file `%s'\n", fn.c_str());
+ Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
+ }
std::map<RTLIL::IdString, RTLIL::Module*> modules_new;
- for (auto &it : map->modules) {
+ for (auto &it : map->modules_) {
if (it.first.substr(0, 2) == "\\$")
it.second->name = it.first.substr(1);
modules_new[it.second->name] = it.second;
}
- map->modules.swap(modules_new);
+ map->modules_.swap(modules_new);
- std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap;
- for (auto &it : map->modules) {
+ std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
+ for (auto &it : map->modules_) {
if (it.second->attributes.count("\\techmap_celltype") && !it.second->attributes.at("\\techmap_celltype").bits.empty()) {
char *p = strdup(it.second->attributes.at("\\techmap_celltype").decode_string().c_str());
for (char *q = strtok(p, " \t\r\n"); q; q = strtok(NULL, " \t\r\n"))
@@ -504,22 +987,30 @@ struct TechmapPass : public Pass {
celltypeMap[it.first].insert(it.first);
}
- bool did_something = true;
- std::set<RTLIL::Cell*> handled_cells;
- while (did_something) {
- did_something = false;
- for (auto &mod_it : design->modules)
- if (techmap_module(design, mod_it.second, map, handled_cells, celltypeMap, false))
- did_something = true;
- if (did_something)
- design->check();
+ for (auto module : design->modules())
+ worker.module_queue.insert(module);
+
+ while (!worker.module_queue.empty())
+ {
+ RTLIL::Module *module = *worker.module_queue.begin();
+ worker.module_queue.erase(module);
+
+ bool did_something = true;
+ std::set<RTLIL::Cell*> handled_cells;
+ while (did_something) {
+ did_something = false;
+ if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false))
+ did_something = true;
+ if (did_something)
+ module->check();
+ if (max_iter > 0 && --max_iter == 0)
+ break;
+ }
}
log("No more expansions possible.\n");
- techmap_cache.clear();
- techmap_do_cache.clear();
- simplemap_mappers.clear();
delete map;
+
log_pop();
}
} TechmapPass;
@@ -544,26 +1035,29 @@ struct FlattenPass : public Pass {
extra_args(args, 1, design);
- std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap;
- for (auto &it : design->modules)
+ TechmapWorker worker;
+ worker.flatten_mode = true;
+
+ std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
+ for (auto &it : design->modules_)
celltypeMap[it.first].insert(it.first);
RTLIL::Module *top_mod = NULL;
if (design->full_selection())
- for (auto &mod_it : design->modules)
- if (mod_it.second->get_bool_attribute("\\top"))
- top_mod = mod_it.second;
+ for (auto mod : design->modules())
+ if (mod->get_bool_attribute("\\top"))
+ top_mod = mod;
bool did_something = true;
std::set<RTLIL::Cell*> handled_cells;
while (did_something) {
did_something = false;
if (top_mod != NULL) {
- if (techmap_module(design, top_mod, design, handled_cells, celltypeMap, true))
+ if (worker.techmap_module(design, top_mod, design, handled_cells, celltypeMap, false))
did_something = true;
} else {
- for (auto &mod_it : design->modules)
- if (techmap_module(design, mod_it.second, design, handled_cells, celltypeMap, true))
+ for (auto mod : design->modules())
+ if (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false))
did_something = true;
}
}
@@ -572,18 +1066,16 @@ struct FlattenPass : public Pass {
if (top_mod != NULL) {
std::map<RTLIL::IdString, RTLIL::Module*> new_modules;
- for (auto &mod_it : design->modules)
- if (mod_it.second == top_mod) {
- new_modules[mod_it.first] = mod_it.second;
+ for (auto mod : design->modules())
+ if (mod == top_mod || mod->get_bool_attribute("\\blackbox")) {
+ new_modules[mod->name] = mod;
} else {
- log("Deleting now unused module %s.\n", RTLIL::id2cstr(mod_it.first));
- delete mod_it.second;
+ log("Deleting now unused module %s.\n", log_id(mod));
+ delete mod;
}
- design->modules.swap(new_modules);
+ design->modules_.swap(new_modules);
}
- techmap_cache.clear();
- techmap_do_cache.clear();
log_pop();
}
} FlattenPass;
diff --git a/passes/tests/Makefile.inc b/passes/tests/Makefile.inc
new file mode 100644
index 00000000..531943d7
--- /dev/null
+++ b/passes/tests/Makefile.inc
@@ -0,0 +1,5 @@
+
+OBJS += passes/tests/test_autotb.o
+OBJS += passes/tests/test_cell.o
+OBJS += passes/tests/test_abcloop.o
+
diff --git a/passes/tests/test_abcloop.cc b/passes/tests/test_abcloop.cc
new file mode 100644
index 00000000..0a0ceb1d
--- /dev/null
+++ b/passes/tests/test_abcloop.cc
@@ -0,0 +1,285 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2014 Johann Glaser <Johann.Glaser@gmx.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/satgen.h"
+
+static uint32_t xorshift32_state = 123456789;
+
+static uint32_t xorshift32(uint32_t limit) {
+ xorshift32_state ^= xorshift32_state << 13;
+ xorshift32_state ^= xorshift32_state >> 17;
+ xorshift32_state ^= xorshift32_state << 5;
+ return xorshift32_state % limit;
+}
+
+static RTLIL::Wire *getw(std::vector<RTLIL::Wire*> &wires, RTLIL::Wire *w)
+{
+ while (1) {
+ int idx = xorshift32(SIZE(wires));
+ if (wires[idx] != w && !wires[idx]->port_output)
+ return wires[idx];
+ }
+}
+
+static void test_abcloop()
+{
+ log("Rng seed value: %u\n", int(xorshift32_state));
+
+ RTLIL::Design *design = new RTLIL::Design;
+ RTLIL::Module *module = nullptr;
+ RTLIL::SigSpec in_sig, out_sig;
+
+ bool truthtab[16][4];
+ int create_cycles = 0;
+
+ while (1)
+ {
+ module = design->addModule("\\uut");
+ create_cycles++;
+
+ in_sig = {};
+ out_sig = {};
+
+ std::vector<RTLIL::Wire*> wires;
+
+ for (int i = 0; i < 4; i++) {
+ RTLIL::Wire *w = module->addWire(stringf("\\i%d", i));
+ w->port_input = true;
+ wires.push_back(w);
+ in_sig.append(w);
+ }
+
+ for (int i = 0; i < 4; i++) {
+ RTLIL::Wire *w = module->addWire(stringf("\\o%d", i));
+ w->port_output = true;
+ wires.push_back(w);
+ out_sig.append(w);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ RTLIL::Wire *w = module->addWire(stringf("\\t%d", i));
+ wires.push_back(w);
+ }
+
+ for (auto w : wires)
+ if (!w->port_input)
+ switch (xorshift32(12))
+ {
+ case 0:
+ module->addNotGate(w->name.str() + "g", getw(wires, w), w);
+ break;
+ case 1:
+ module->addAndGate(w->name.str() + "g", getw(wires, w), getw(wires, w), w);
+ break;
+ case 2:
+ module->addNandGate(w->name.str() + "g", getw(wires, w), getw(wires, w), w);
+ break;
+ case 3:
+ module->addOrGate(w->name.str() + "g", getw(wires, w), getw(wires, w), w);
+ break;
+ case 4:
+ module->addNorGate(w->name.str() + "g", getw(wires, w), getw(wires, w), w);
+ break;
+ case 5:
+ module->addXorGate(w->name.str() + "g", getw(wires, w), getw(wires, w), w);
+ break;
+ case 6:
+ module->addXnorGate(w->name.str() + "g", getw(wires, w), getw(wires, w), w);
+ break;
+ case 7:
+ module->addMuxGate(w->name.str() + "g", getw(wires, w), getw(wires, w), getw(wires, w), w);
+ break;
+ case 8:
+ module->addAoi3Gate(w->name.str() + "g", getw(wires, w), getw(wires, w), getw(wires, w), w);
+ break;
+ case 9:
+ module->addOai3Gate(w->name.str() + "g", getw(wires, w), getw(wires, w), getw(wires, w), w);
+ break;
+ case 10:
+ module->addAoi4Gate(w->name.str() + "g", getw(wires, w), getw(wires, w), getw(wires, w), getw(wires, w), w);
+ break;
+ case 11:
+ module->addOai4Gate(w->name.str() + "g", getw(wires, w), getw(wires, w), getw(wires, w), getw(wires, w), w);
+ break;
+ }
+
+ module->fixup_ports();
+ Pass::call(design, "clean");
+
+ ezDefaultSAT ez;
+ SigMap sigmap(module);
+ SatGen satgen(&ez, &sigmap);
+
+ for (auto c : module->cells()) {
+ bool ok = satgen.importCell(c);
+ log_assert(ok);
+ }
+
+ std::vector<int> in_vec = satgen.importSigSpec(in_sig);
+ std::vector<int> inverse_in_vec = ez.vec_not(in_vec);
+
+ std::vector<int> out_vec = satgen.importSigSpec(out_sig);
+
+ for (int i = 0; i < 16; i++)
+ {
+ std::vector<int> assumptions;
+ for (int j = 0; j < SIZE(in_vec); j++)
+ assumptions.push_back((i & (1 << j)) ? in_vec.at(j) : inverse_in_vec.at(j));
+
+ std::vector<bool> results;
+ if (!ez.solve(out_vec, results, assumptions)) {
+ log("No stable solution for input %d found -> recreate module.\n", i);
+ goto recreate_module;
+ }
+
+ for (int j = 0; j < 4; j++)
+ truthtab[i][j] = results[j];
+
+ assumptions.push_back(ez.vec_ne(out_vec, ez.vec_const(results)));
+
+ std::vector<bool> results2;
+ if (ez.solve(out_vec, results2, assumptions)) {
+ log("Two stable solutions for input %d found -> recreate module.\n", i);
+ goto recreate_module;
+ }
+ }
+ break;
+
+ recreate_module:
+ design->remove(module);
+ }
+
+ log("Found viable UUT after %d cycles:\n", create_cycles);
+ Pass::call(design, "write_ilang");
+ Pass::call(design, "abc");
+
+ log("\n");
+ log("Pre- and post-abc truth table:\n");
+
+ ezDefaultSAT ez;
+ SigMap sigmap(module);
+ SatGen satgen(&ez, &sigmap);
+
+ for (auto c : module->cells()) {
+ bool ok = satgen.importCell(c);
+ log_assert(ok);
+ }
+
+ std::vector<int> in_vec = satgen.importSigSpec(in_sig);
+ std::vector<int> inverse_in_vec = ez.vec_not(in_vec);
+
+ std::vector<int> out_vec = satgen.importSigSpec(out_sig);
+
+ bool found_error = false;
+ bool truthtab2[16][4];
+
+ for (int i = 0; i < 16; i++)
+ {
+ std::vector<int> assumptions;
+ for (int j = 0; j < SIZE(in_vec); j++)
+ assumptions.push_back((i & (1 << j)) ? in_vec.at(j) : inverse_in_vec.at(j));
+
+ for (int j = 0; j < 4; j++)
+ truthtab2[i][j] = truthtab[i][j];
+
+ std::vector<bool> results;
+ if (!ez.solve(out_vec, results, assumptions)) {
+ log("No stable solution for input %d found.\n", i);
+ found_error = true;
+ continue;
+ }
+
+ for (int j = 0; j < 4; j++)
+ truthtab2[i][j] = results[j];
+
+ assumptions.push_back(ez.vec_ne(out_vec, ez.vec_const(results)));
+
+ std::vector<bool> results2;
+ if (ez.solve(out_vec, results2, assumptions)) {
+ log("Two stable solutions for input %d found -> recreate module.\n", i);
+ found_error = true;
+ }
+ }
+
+ for (int i = 0; i < 16; i++) {
+ log("%3d ", i);
+ for (int j = 0; j < 4; j++)
+ log("%c", truthtab[i][j] ? '1' : '0');
+ log(" ");
+ for (int j = 0; j < 4; j++)
+ log("%c", truthtab2[i][j] ? '1' : '0');
+ for (int j = 0; j < 4; j++)
+ if (truthtab[i][j] != truthtab2[i][j]) {
+ found_error = true;
+ log(" !");
+ break;
+ }
+ log("\n");
+ }
+
+ log_assert(found_error == false);
+ log("\n");
+}
+
+struct TestAbcloopPass : public Pass {
+ TestAbcloopPass() : Pass("test_abcloop", "automatically test handling of loops in abc command") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" test_abcloop [options]\n");
+ log("\n");
+ log("Test handling of logic loops in ABC.\n");
+ log("\n");
+ log(" -n {integer}\n");
+ log(" create this number of circuits and test them (default = 100).\n");
+ log("\n");
+ log(" -s {positive_integer}\n");
+ log(" use this value as rng seed value (default = unix time).\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+ {
+ int num_iter = 100;
+ xorshift32_state = 0;
+
+ int argidx;
+ for (argidx = 1; argidx < SIZE(args); argidx++)
+ {
+ if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
+ num_iter = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-s" && argidx+1 < SIZE(args)) {
+ xorshift32_state = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+
+ if (xorshift32_state == 0)
+ xorshift32_state = time(NULL) & 0x7fffffff;
+
+ for (int i = 0; i < num_iter; i++)
+ test_abcloop();
+ }
+} TestAbcloopPass;
+
diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc
new file mode 100644
index 00000000..eed0f75f
--- /dev/null
+++ b/passes/tests/test_autotb.cc
@@ -0,0 +1,353 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+PRIVATE_NAMESPACE_BEGIN
+
+static std::string id(std::string internal_id)
+{
+ const char *str = internal_id.c_str();
+ bool do_escape = false;
+
+ if (*str == '\\')
+ str++;
+
+ if ('0' <= *str && *str <= '9')
+ do_escape = true;
+
+ for (int i = 0; str[i]; i++) {
+ if ('0' <= str[i] && str[i] <= '9')
+ continue;
+ if ('a' <= str[i] && str[i] <= 'z')
+ continue;
+ if ('A' <= str[i] && str[i] <= 'Z')
+ continue;
+ if (str[i] == '_')
+ continue;
+ do_escape = true;
+ break;
+ }
+
+ if (do_escape)
+ return "\\" + std::string(str) + " ";
+ return std::string(str);
+}
+
+static std::string idx(std::string str)
+{
+ if (str[0] == '\\')
+ return str.substr(1);
+ return str;
+}
+
+static std::string idy(std::string str1, std::string str2 = std::string(), std::string str3 = std::string())
+{
+ str1 = idx(str1);
+ if (!str2.empty())
+ str1 += "_" + idx(str2);
+ if (!str3.empty())
+ str1 += "_" + idx(str3);
+ return id(str1);
+}
+
+static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
+{
+ f << stringf("module testbench;\n\n");
+
+ f << stringf("integer i;\n\n");
+
+ f << stringf("reg [31:0] xorshift128_x = 123456789;\n");
+ f << stringf("reg [31:0] xorshift128_y = 362436069;\n");
+ f << stringf("reg [31:0] xorshift128_z = 521288629;\n");
+ f << stringf("reg [31:0] xorshift128_w = %u; // <-- seed value\n", int(time(NULL)));
+ f << stringf("reg [31:0] xorshift128_t;\n\n");
+ f << stringf("task xorshift128;\n");
+ f << stringf("begin\n");
+ f << stringf("\txorshift128_t = xorshift128_x ^ (xorshift128_x << 11);\n");
+ f << stringf("\txorshift128_x = xorshift128_y;\n");
+ f << stringf("\txorshift128_y = xorshift128_z;\n");
+ f << stringf("\txorshift128_z = xorshift128_w;\n");
+ f << stringf("\txorshift128_w = xorshift128_w ^ (xorshift128_w >> 19) ^ xorshift128_t ^ (xorshift128_t >> 8);\n");
+ f << stringf("end\n");
+ f << stringf("endtask\n\n");
+
+ for (auto it = design->modules_.begin(); it != design->modules_.end(); it++)
+ {
+ std::map<std::string, int> signal_in;
+ std::map<std::string, std::string> signal_const;
+ std::map<std::string, int> signal_clk;
+ std::map<std::string, int> signal_out;
+
+ RTLIL::Module *mod = it->second;
+
+ if (mod->get_bool_attribute("\\gentb_skip"))
+ continue;
+
+ int count_ports = 0;
+ log("Generating test bench for module `%s'.\n", it->first.c_str());
+ for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); it2++) {
+ RTLIL::Wire *wire = it2->second;
+ if (wire->port_output) {
+ count_ports++;
+ signal_out[idy("sig", mod->name.str(), wire->name.str())] = wire->width;
+ f << stringf("wire [%d:0] %s;\n", wire->width-1, idy("sig", mod->name.str(), wire->name.str()).c_str());
+ } else if (wire->port_input) {
+ count_ports++;
+ bool is_clksignal = wire->get_bool_attribute("\\gentb_clock");
+ for (auto it3 = mod->processes.begin(); it3 != mod->processes.end(); it3++)
+ for (auto it4 = it3->second->syncs.begin(); it4 != it3->second->syncs.end(); it4++) {
+ if ((*it4)->type == RTLIL::ST0 || (*it4)->type == RTLIL::ST1)
+ continue;
+ RTLIL::SigSpec &signal = (*it4)->signal;
+ for (auto &c : signal.chunks())
+ if (c.wire == wire)
+ is_clksignal = true;
+ }
+ if (is_clksignal && wire->attributes.count("\\gentb_constant") == 0) {
+ signal_clk[idy("sig", mod->name.str(), wire->name.str())] = wire->width;
+ } else {
+ signal_in[idy("sig", mod->name.str(), wire->name.str())] = wire->width;
+ if (wire->attributes.count("\\gentb_constant") != 0)
+ signal_const[idy("sig", mod->name.str(), wire->name.str())] = wire->attributes["\\gentb_constant"].as_string();
+ }
+ f << stringf("reg [%d:0] %s;\n", wire->width-1, idy("sig", mod->name.str(), wire->name.str()).c_str());
+ }
+ }
+ f << stringf("%s %s(\n", id(mod->name.str()).c_str(), idy("uut", mod->name.str()).c_str());
+ for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); it2++) {
+ RTLIL::Wire *wire = it2->second;
+ if (wire->port_output || wire->port_input)
+ f << stringf("\t.%s(%s)%s\n", id(wire->name.str()).c_str(),
+ idy("sig", mod->name.str(), wire->name.str()).c_str(), --count_ports ? "," : "");
+ }
+ f << stringf(");\n\n");
+
+ f << stringf("task %s;\n", idy(mod->name.str(), "reset").c_str());
+ f << stringf("begin\n");
+ int delay_counter = 0;
+ for (auto it = signal_in.begin(); it != signal_in.end(); it++)
+ f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); it++)
+ f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
+ f << stringf("\t#100; %s <= 1;\n", it->first.c_str());
+ f << stringf("\t#100; %s <= 0;\n", it->first.c_str());
+ }
+ delay_counter = 0;
+ for (auto it = signal_in.begin(); it != signal_in.end(); it++)
+ f << stringf("\t%s <= #%d ~0;\n", it->first.c_str(), ++delay_counter*2);
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
+ f << stringf("\t#100; %s <= 1;\n", it->first.c_str());
+ f << stringf("\t#100; %s <= 0;\n", it->first.c_str());
+ }
+ delay_counter = 0;
+ for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
+ if (signal_const.count(it->first) == 0)
+ continue;
+ f << stringf("\t%s <= #%d 'b%s;\n", it->first.c_str(), ++delay_counter*2, signal_const[it->first].c_str());
+ }
+ f << stringf("end\n");
+ f << stringf("endtask\n\n");
+
+ f << stringf("task %s;\n", idy(mod->name.str(), "update_data").c_str());
+ f << stringf("begin\n");
+ delay_counter = 0;
+ for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
+ if (signal_const.count(it->first) > 0)
+ continue;
+ f << stringf("\txorshift128;\n");
+ f << stringf("\t%s <= #%d { xorshift128_x, xorshift128_y, xorshift128_z, xorshift128_w };\n", it->first.c_str(), ++delay_counter*2);
+ }
+ f << stringf("end\n");
+ f << stringf("endtask\n\n");
+
+ f << stringf("task %s;\n", idy(mod->name.str(), "update_clock").c_str());
+ f << stringf("begin\n");
+ if (signal_clk.size()) {
+ f << stringf("\txorshift128;\n");
+ f << stringf("\t{");
+ int total_clock_bits = 0;
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
+ f << stringf("%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
+ total_clock_bits += it->second;
+ }
+ f << stringf(" } = {");
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); it++)
+ f << stringf("%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
+ f << stringf(" } ^ (%d'b1 << (xorshift128_w %% %d));\n", total_clock_bits, total_clock_bits);
+ }
+ f << stringf("end\n");
+ f << stringf("endtask\n\n");
+
+ char shorthand = 'A';
+ std::vector<std::string> header1;
+ std::string header2 = "";
+
+ f << stringf("task %s;\n", idy(mod->name.str(), "print_status").c_str());
+ f << stringf("begin\n");
+ f << stringf("\t$display(\"#OUT# %%b %%b %%b %%t %%d\", {");
+ if (signal_in.size())
+ for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
+ f << stringf("%s %s", it == signal_in.begin() ? "" : ",", it->first.c_str());
+ int len = it->second;
+ if (len > 1)
+ header2 += "/", len--;
+ while (len > 1)
+ header2 += "-", len--;
+ if (len > 0)
+ header2 += shorthand, len--;
+ header1.push_back(" " + it->first);
+ header1.back()[0] = shorthand++;
+ }
+ else {
+ f << stringf(" 1'bx");
+ header2 += "#";
+ }
+ f << stringf(" }, {");
+ header2 += " ";
+ if (signal_clk.size()) {
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
+ f << stringf("%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
+ int len = it->second;
+ if (len > 1)
+ header2 += "/", len--;
+ while (len > 1)
+ header2 += "-", len--;
+ if (len > 0)
+ header2 += shorthand, len--;
+ header1.push_back(" " + it->first);
+ header1.back()[0] = shorthand++;
+ }
+ } else {
+ f << stringf(" 1'bx");
+ header2 += "#";
+ }
+ f << stringf(" }, {");
+ header2 += " ";
+ if (signal_out.size()) {
+ for (auto it = signal_out.begin(); it != signal_out.end(); it++) {
+ f << stringf("%s %s", it == signal_out.begin() ? "" : ",", it->first.c_str());
+ int len = it->second;
+ if (len > 1)
+ header2 += "/", len--;
+ while (len > 1)
+ header2 += "-", len--;
+ if (len > 0)
+ header2 += shorthand, len--;
+ header1.push_back(" " + it->first);
+ header1.back()[0] = shorthand++;
+ }
+ } else {
+ f << stringf(" 1'bx");
+ header2 += "#";
+ }
+ f << stringf(" }, $time, i);\n");
+ f << stringf("end\n");
+ f << stringf("endtask\n\n");
+
+ f << stringf("task %s;\n", idy(mod->name.str(), "print_header").c_str());
+ f << stringf("begin\n");
+ f << stringf("\t$display(\"#OUT#\");\n");
+ for (auto &hdr : header1)
+ f << stringf("\t$display(\"#OUT# %s\");\n", hdr.c_str());
+ f << stringf("\t$display(\"#OUT#\");\n");
+ f << stringf("\t$display(\"#OUT# %s\");\n", header2.c_str());
+ f << stringf("end\n");
+ f << stringf("endtask\n\n");
+
+ f << stringf("task %s;\n", idy(mod->name.str(), "test").c_str());
+ f << stringf("begin\n");
+ f << stringf("\t$display(\"#OUT#\\n#OUT# ==== %s ====\");\n", idy(mod->name.str()).c_str());
+ f << stringf("\t%s;\n", idy(mod->name.str(), "reset").c_str());
+ f << stringf("\tfor (i=0; i<%d; i=i+1) begin\n", num_iter);
+ f << stringf("\t\tif (i %% 20 == 0) %s;\n", idy(mod->name.str(), "print_header").c_str());
+ f << stringf("\t\t#100; %s;\n", idy(mod->name.str(), "update_data").c_str());
+ f << stringf("\t\t#100; %s;\n", idy(mod->name.str(), "update_clock").c_str());
+ f << stringf("\t\t#100; %s;\n", idy(mod->name.str(), "print_status").c_str());
+ f << stringf("\tend\n");
+ f << stringf("end\n");
+ f << stringf("endtask\n\n");
+ }
+
+ f << stringf("initial begin\n");
+ f << stringf("\t// $dumpfile(\"testbench.vcd\");\n");
+ f << stringf("\t// $dumpvars(0, testbench);\n");
+ for (auto it = design->modules_.begin(); it != design->modules_.end(); it++)
+ if (!it->second->get_bool_attribute("\\gentb_skip"))
+ f << stringf("\t%s;\n", idy(it->first.str(), "test").c_str());
+ f << stringf("\t$finish;\n");
+ f << stringf("end\n\n");
+
+ f << stringf("endmodule\n");
+}
+
+struct TestAutotbBackend : public Backend {
+ TestAutotbBackend() : Backend("=test_autotb", "generate simple test benches") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" test_autotb [options] [filename]\n");
+ log("\n");
+ log("Automatically create primitive verilog test benches for all modules in the\n");
+ log("design. The generated testbenches toggle the input pins of the module in\n");
+ log("a semi-random manner and dumps the resulting output signals.\n");
+ log("\n");
+ log("This can be used to check the synthesis results for simple circuits by\n");
+ log("comparing the testbench output for the input files and the synthesis results.\n");
+ log("\n");
+ log("The backend automatically detects clock signals. Additionally a signal can\n");
+ log("be forced to be interpreted as clock signal by setting the attribute\n");
+ log("'gentb_clock' on the signal.\n");
+ log("\n");
+ log("The attribute 'gentb_constant' can be used to force a signal to a constant\n");
+ log("value after initialization. This can e.g. be used to force a reset signal\n");
+ log("low in order to explore more inner states in a state machine.\n");
+ log("\n");
+ log(" -n <int>\n");
+ log(" number of iterations the test bench shuld run (default = 1000)\n");
+ log("\n");
+ }
+ virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ {
+ int num_iter = 1000;
+
+ log_header("Executing TEST_AUTOTB backend (auto-generate pseudo-random test benches).\n");
+
+ int argidx;
+ for (argidx = 1; argidx < SIZE(args); argidx++)
+ {
+ if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
+ num_iter = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+
+ extra_args(f, filename, args, argidx);
+ autotest(*f, design, num_iter);
+ }
+} TestAutotbBackend;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc
new file mode 100644
index 00000000..1fa90b54
--- /dev/null
+++ b/passes/tests/test_cell.cc
@@ -0,0 +1,745 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2014 Johann Glaser <Johann.Glaser@gmx.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/satgen.h"
+#include "kernel/consteval.h"
+#include "kernel/macc.h"
+#include <algorithm>
+
+static uint32_t xorshift32_state = 123456789;
+
+static uint32_t xorshift32(uint32_t limit) {
+ xorshift32_state ^= xorshift32_state << 13;
+ xorshift32_state ^= xorshift32_state >> 17;
+ xorshift32_state ^= xorshift32_state << 5;
+ return xorshift32_state % limit;
+}
+
+static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, std::string cell_type_flags, bool constmode)
+{
+ RTLIL::Module *module = design->addModule("\\gold");
+ RTLIL::Cell *cell = module->addCell("\\UUT", cell_type);
+ RTLIL::Wire *wire;
+
+ if (cell_type == "$fa")
+ {
+ int width = 1 + xorshift32(8);
+
+ wire = module->addWire("\\A");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\A", wire);
+
+ wire = module->addWire("\\B");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\B", wire);
+
+ wire = module->addWire("\\C");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\C", wire);
+
+ wire = module->addWire("\\X");
+ wire->width = width;
+ wire->port_output = true;
+ cell->setPort("\\X", wire);
+
+ wire = module->addWire("\\Y");
+ wire->width = width;
+ wire->port_output = true;
+ cell->setPort("\\Y", wire);
+ }
+
+ if (cell_type == "$lcu")
+ {
+ int width = 1 + xorshift32(8);
+
+ wire = module->addWire("\\P");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\P", wire);
+
+ wire = module->addWire("\\G");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\G", wire);
+
+ wire = module->addWire("\\CI");
+ wire->port_input = true;
+ cell->setPort("\\CI", wire);
+
+ wire = module->addWire("\\CO");
+ wire->width = width;
+ wire->port_output = true;
+ cell->setPort("\\CO", wire);
+ }
+
+ if (cell_type == "$macc")
+ {
+ Macc macc;
+ int width = 1 + xorshift32(8);
+ int depth = 1 + xorshift32(6);
+ int mulbits_a = 0, mulbits_b = 0;
+
+ RTLIL::Wire *wire_a = module->addWire("\\A");
+ wire_a->width = 0;
+ wire_a->port_input = true;
+
+ for (int i = 0; i < depth; i++)
+ {
+ int size_a = xorshift32(width) + 1;
+ int size_b = depth > 4 ? 0 : xorshift32(width) + 1;
+
+ if (mulbits_a + size_a*size_b <= 96 && mulbits_b + size_a + size_b <= 16 && xorshift32(2) == 1) {
+ mulbits_a += size_a * size_b;
+ mulbits_b += size_a + size_b;
+ } else
+ size_b = 0;
+
+ Macc::port_t this_port;
+
+ wire_a->width += size_a;
+ this_port.in_a = RTLIL::SigSpec(wire_a, wire_a->width - size_a, size_a);
+
+ wire_a->width += size_b;
+ this_port.in_b = RTLIL::SigSpec(wire_a, wire_a->width - size_b, size_b);
+
+ this_port.is_signed = xorshift32(2) == 1;
+ this_port.do_subtract = xorshift32(2) == 1;
+ macc.ports.push_back(this_port);
+ }
+
+ wire = module->addWire("\\B");
+ wire->width = xorshift32(mulbits_a ? xorshift32(4)+1 : xorshift32(16)+1);
+ wire->port_input = true;
+ macc.bit_ports = wire;
+
+ wire = module->addWire("\\Y");
+ wire->width = width;
+ wire->port_output = true;
+ cell->setPort("\\Y", wire);
+
+ macc.to_cell(cell);
+ }
+
+ if (cell_type == "$lut")
+ {
+ int width = 1 + xorshift32(6);
+
+ wire = module->addWire("\\A");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\A", wire);
+
+ wire = module->addWire("\\Y");
+ wire->port_output = true;
+ cell->setPort("\\Y", wire);
+
+ RTLIL::SigSpec config;
+ for (int i = 0; i < (1 << width); i++)
+ config.append(xorshift32(2) ? RTLIL::S1 : RTLIL::S0);
+
+ cell->setParam("\\LUT", config.as_const());
+ }
+
+ if (cell_type_flags.find('A') != std::string::npos) {
+ wire = module->addWire("\\A");
+ wire->width = 1 + xorshift32(8);
+ wire->port_input = true;
+ cell->setPort("\\A", wire);
+ }
+
+ if (cell_type_flags.find('B') != std::string::npos) {
+ wire = module->addWire("\\B");
+ if (cell_type_flags.find('h') != std::string::npos)
+ wire->width = 1 + xorshift32(6);
+ else
+ wire->width = 1 + xorshift32(8);
+ wire->port_input = true;
+ cell->setPort("\\B", wire);
+ }
+
+ if (cell_type_flags.find('S') != std::string::npos && xorshift32(2)) {
+ if (cell_type_flags.find('A') != std::string::npos)
+ cell->parameters["\\A_SIGNED"] = true;
+ if (cell_type_flags.find('B') != std::string::npos)
+ cell->parameters["\\B_SIGNED"] = true;
+ }
+
+ if (cell_type_flags.find('s') != std::string::npos) {
+ if (cell_type_flags.find('A') != std::string::npos && xorshift32(2))
+ cell->parameters["\\A_SIGNED"] = true;
+ if (cell_type_flags.find('B') != std::string::npos && xorshift32(2))
+ cell->parameters["\\B_SIGNED"] = true;
+ }
+
+ if (cell_type_flags.find('Y') != std::string::npos) {
+ wire = module->addWire("\\Y");
+ wire->width = 1 + xorshift32(8);
+ wire->port_output = true;
+ cell->setPort("\\Y", wire);
+ }
+
+ if (cell_type == "$alu")
+ {
+ wire = module->addWire("\\CI");
+ wire->port_input = true;
+ cell->setPort("\\CI", wire);
+
+ wire = module->addWire("\\BI");
+ wire->port_input = true;
+ cell->setPort("\\BI", wire);
+
+ wire = module->addWire("\\X");
+ wire->width = SIZE(cell->getPort("\\Y"));
+ wire->port_output = true;
+ cell->setPort("\\X", wire);
+
+ wire = module->addWire("\\CO");
+ wire->width = SIZE(cell->getPort("\\Y"));
+ wire->port_output = true;
+ cell->setPort("\\CO", wire);
+ }
+
+ if (constmode)
+ {
+ auto conn_list = cell->connections();
+ for (auto &conn : conn_list)
+ {
+ RTLIL::SigSpec sig = conn.second;
+
+ if (SIZE(sig) == 0 || sig[0].wire == nullptr || sig[0].wire->port_output)
+ continue;
+
+ int n, m;
+ switch (xorshift32(5))
+ {
+ case 0:
+ n = xorshift32(SIZE(sig) + 1);
+ for (int i = 0; i < n; i++)
+ sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
+ break;
+ case 1:
+ n = xorshift32(SIZE(sig) + 1);
+ for (int i = n; i < SIZE(sig); i++)
+ sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
+ break;
+ case 2:
+ n = xorshift32(SIZE(sig));
+ m = xorshift32(SIZE(sig));
+ for (int i = std::min(n, m); i < std::max(n, m); i++)
+ sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
+ break;
+ }
+
+ cell->setPort(conn.first, sig);
+ }
+ }
+
+ module->fixup_ports();
+ cell->fixup_parameters();
+ cell->check();
+}
+
+static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::string uut_name, std::ofstream &vlog_file)
+{
+ log("Eval testing:%c", verbose ? '\n' : ' ');
+
+ RTLIL::Module *gold_mod = design->module("\\gold");
+ RTLIL::Module *gate_mod = design->module("\\gate");
+ ConstEval gold_ce(gold_mod), gate_ce(gate_mod);
+
+ ezDefaultSAT ez1, ez2;
+ SigMap sigmap(gold_mod);
+ SatGen satgen1(&ez1, &sigmap);
+ SatGen satgen2(&ez2, &sigmap);
+ satgen2.model_undef = true;
+
+ if (!nosat)
+ for (auto cell : gold_mod->cells()) {
+ satgen1.importCell(cell);
+ satgen2.importCell(cell);
+ }
+
+ if (vlog_file.is_open())
+ {
+ vlog_file << stringf("\nmodule %s;\n", uut_name.c_str());
+
+ for (auto port : gold_mod->ports) {
+ RTLIL::Wire *wire = gold_mod->wire(port);
+ if (wire->port_input)
+ vlog_file << stringf(" reg [%d:0] %s;\n", SIZE(wire)-1, log_id(wire));
+ else
+ vlog_file << stringf(" wire [%d:0] %s_expr, %s_noexpr;\n", SIZE(wire)-1, log_id(wire), log_id(wire));
+ }
+
+ vlog_file << stringf(" %s_expr uut_expr(", uut_name.c_str());
+ for (int i = 0; i < SIZE(gold_mod->ports); i++)
+ vlog_file << stringf("%s.%s(%s%s)", i ? ", " : "", log_id(gold_mod->ports[i]), log_id(gold_mod->ports[i]),
+ gold_mod->wire(gold_mod->ports[i])->port_input ? "" : "_expr");
+ vlog_file << stringf(");\n");
+
+ vlog_file << stringf(" %s_expr uut_noexpr(", uut_name.c_str());
+ for (int i = 0; i < SIZE(gold_mod->ports); i++)
+ vlog_file << stringf("%s.%s(%s%s)", i ? ", " : "", log_id(gold_mod->ports[i]), log_id(gold_mod->ports[i]),
+ gold_mod->wire(gold_mod->ports[i])->port_input ? "" : "_noexpr");
+ vlog_file << stringf(");\n");
+
+ vlog_file << stringf(" task run;\n");
+ vlog_file << stringf(" begin\n");
+ vlog_file << stringf(" $display(\"%s\");\n", uut_name.c_str());
+ }
+
+ for (int i = 0; i < 64; i++)
+ {
+ log(verbose ? "\n" : ".");
+ gold_ce.clear();
+ gate_ce.clear();
+
+ RTLIL::SigSpec in_sig, in_val;
+ RTLIL::SigSpec out_sig, out_val;
+ std::string vlog_pattern_info;
+
+ for (auto port : gold_mod->ports)
+ {
+ RTLIL::Wire *gold_wire = gold_mod->wire(port);
+ RTLIL::Wire *gate_wire = gate_mod->wire(port);
+
+ log_assert(gold_wire != nullptr);
+ log_assert(gate_wire != nullptr);
+ log_assert(gold_wire->port_input == gate_wire->port_input);
+ log_assert(SIZE(gold_wire) == SIZE(gate_wire));
+
+ if (!gold_wire->port_input)
+ continue;
+
+ RTLIL::Const in_value;
+ for (int i = 0; i < SIZE(gold_wire); i++)
+ in_value.bits.push_back(xorshift32(2) ? RTLIL::S1 : RTLIL::S0);
+
+ if (xorshift32(4) == 0) {
+ int inv_chance = 1 + xorshift32(8);
+ for (int i = 0; i < SIZE(gold_wire); i++)
+ if (xorshift32(inv_chance) == 0)
+ in_value.bits[i] = RTLIL::Sx;
+ }
+
+ if (verbose)
+ log("%s: %s\n", log_id(gold_wire), log_signal(in_value));
+
+ in_sig.append(gold_wire);
+ in_val.append(in_value);
+
+ gold_ce.set(gold_wire, in_value);
+ gate_ce.set(gate_wire, in_value);
+
+ if (vlog_file.is_open() && SIZE(in_value) > 0) {
+ vlog_file << stringf(" %s = 'b%s;\n", log_id(gold_wire), in_value.as_string().c_str());
+ if (!vlog_pattern_info.empty())
+ vlog_pattern_info += " ";
+ vlog_pattern_info += stringf("%s=%s", log_id(gold_wire), log_signal(in_value));
+ }
+ }
+
+ if (vlog_file.is_open())
+ vlog_file << stringf(" #1;\n");
+
+ for (auto port : gold_mod->ports)
+ {
+ RTLIL::Wire *gold_wire = gold_mod->wire(port);
+ RTLIL::Wire *gate_wire = gate_mod->wire(port);
+
+ log_assert(gold_wire != nullptr);
+ log_assert(gate_wire != nullptr);
+ log_assert(gold_wire->port_output == gate_wire->port_output);
+ log_assert(SIZE(gold_wire) == SIZE(gate_wire));
+
+ if (!gold_wire->port_output)
+ continue;
+
+ RTLIL::SigSpec gold_outval(gold_wire);
+ RTLIL::SigSpec gate_outval(gate_wire);
+
+ if (!gold_ce.eval(gold_outval))
+ log_error("Failed to eval %s in gold module.\n", log_id(gold_wire));
+
+ if (!gate_ce.eval(gate_outval))
+ log_error("Failed to eval %s in gate module.\n", log_id(gate_wire));
+
+ bool gold_gate_mismatch = false;
+ for (int i = 0; i < SIZE(gold_wire); i++) {
+ if (gold_outval[i] == RTLIL::Sx)
+ continue;
+ if (gold_outval[i] == gate_outval[i])
+ continue;
+ gold_gate_mismatch = true;
+ break;
+ }
+
+ if (gold_gate_mismatch)
+ log_error("Mismatch in output %s: gold:%s != gate:%s\n", log_id(gate_wire), log_signal(gold_outval), log_signal(gate_outval));
+
+ if (verbose)
+ log("%s: %s\n", log_id(gold_wire), log_signal(gold_outval));
+
+ out_sig.append(gold_wire);
+ out_val.append(gold_outval);
+
+ if (vlog_file.is_open()) {
+ vlog_file << stringf(" $display(\"[%s] %s expected: %%b, expr: %%b, noexpr: %%b\", %d'b%s, %s_expr, %s_noexpr);\n",
+ vlog_pattern_info.c_str(), log_id(gold_wire), SIZE(gold_outval), gold_outval.as_string().c_str(), log_id(gold_wire), log_id(gold_wire));
+ vlog_file << stringf(" if (%s_expr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire), SIZE(gold_outval), gold_outval.as_string().c_str());
+ vlog_file << stringf(" if (%s_noexpr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire), SIZE(gold_outval), gold_outval.as_string().c_str());
+ }
+ }
+
+ if (verbose)
+ log("EVAL: %s\n", out_val.as_string().c_str());
+
+ if (!nosat)
+ {
+ std::vector<int> sat1_in_sig = satgen1.importSigSpec(in_sig);
+ std::vector<int> sat1_in_val = satgen1.importSigSpec(in_val);
+
+ std::vector<int> sat1_model = satgen1.importSigSpec(out_sig);
+ std::vector<bool> sat1_model_value;
+
+ if (!ez1.solve(sat1_model, sat1_model_value, ez1.vec_eq(sat1_in_sig, sat1_in_val)))
+ log_error("Evaluating sat model 1 (no undef modeling) failed!\n");
+
+ if (verbose) {
+ log("SAT 1: ");
+ for (int i = SIZE(out_sig)-1; i >= 0; i--)
+ log("%c", sat1_model_value.at(i) ? '1' : '0');
+ log("\n");
+ }
+
+ for (int i = 0; i < SIZE(out_sig); i++) {
+ if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1)
+ continue;
+ if (out_val[i] == RTLIL::S0 && sat1_model_value.at(i) == false)
+ continue;
+ if (out_val[i] == RTLIL::S1 && sat1_model_value.at(i) == true)
+ continue;
+ log_error("Mismatch in sat model 1 (no undef modeling) output!\n");
+ }
+
+ std::vector<int> sat2_in_def_sig = satgen2.importDefSigSpec(in_sig);
+ std::vector<int> sat2_in_def_val = satgen2.importDefSigSpec(in_val);
+
+ std::vector<int> sat2_in_undef_sig = satgen2.importUndefSigSpec(in_sig);
+ std::vector<int> sat2_in_undef_val = satgen2.importUndefSigSpec(in_val);
+
+ std::vector<int> sat2_model_def_sig = satgen2.importDefSigSpec(out_sig);
+ std::vector<int> sat2_model_undef_sig = satgen2.importUndefSigSpec(out_sig);
+
+ std::vector<int> sat2_model;
+ sat2_model.insert(sat2_model.end(), sat2_model_def_sig.begin(), sat2_model_def_sig.end());
+ sat2_model.insert(sat2_model.end(), sat2_model_undef_sig.begin(), sat2_model_undef_sig.end());
+
+ std::vector<bool> sat2_model_value;
+
+ if (!ez2.solve(sat2_model, sat2_model_value, ez2.vec_eq(sat2_in_def_sig, sat2_in_def_val), ez2.vec_eq(sat2_in_undef_sig, sat2_in_undef_val)))
+ log_error("Evaluating sat model 2 (undef modeling) failed!\n");
+
+ if (verbose) {
+ log("SAT 2: ");
+ for (int i = SIZE(out_sig)-1; i >= 0; i--)
+ log("%c", sat2_model_value.at(SIZE(out_sig) + i) ? 'x' : sat2_model_value.at(i) ? '1' : '0');
+ log("\n");
+ }
+
+ for (int i = 0; i < SIZE(out_sig); i++) {
+ if (sat2_model_value.at(SIZE(out_sig) + i)) {
+ if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1)
+ continue;
+ } else {
+ if (out_val[i] == RTLIL::S0 && sat2_model_value.at(i) == false)
+ continue;
+ if (out_val[i] == RTLIL::S1 && sat2_model_value.at(i) == true)
+ continue;
+ }
+ log_error("Mismatch in sat model 2 (undef modeling) output!\n");
+ }
+ }
+ }
+
+ if (vlog_file.is_open()) {
+ vlog_file << stringf(" end\n");
+ vlog_file << stringf(" endtask\n");
+ vlog_file << stringf("endmodule\n");
+ }
+
+ if (!verbose)
+ log(" ok.\n");
+}
+
+struct TestCellPass : public Pass {
+ TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" test_cell [options] {cell-types}\n");
+ log("\n");
+ log("Tests the internal implementation of the given cell type (for example '$add')\n");
+ log("by comparing SAT solver, EVAL and TECHMAP implementations of the cell types..\n");
+ log("\n");
+ log("Run with 'all' instead of a cell type to run the test on all supported\n");
+ log("cell types.\n");
+ log("\n");
+ log(" -n {integer}\n");
+ log(" create this number of cell instances and test them (default = 100).\n");
+ log("\n");
+ log(" -s {positive_integer}\n");
+ log(" use this value as rng seed value (default = unix time).\n");
+ log("\n");
+ log(" -f {ilang_file}\n");
+ log(" don't generate circuits. instead load the specified ilang file.\n");
+ log("\n");
+ log(" -map {filename}\n");
+ log(" pass this option to techmap.\n");
+ log("\n");
+ log(" -simplib\n");
+ log(" use \"techmap -map +/simlib.v -max_iter 2 -autoproc\"\n");
+ log("\n");
+ log(" -script {script_file}\n");
+ log(" instead of calling \"techmap\", call \"script {script_file}\".\n");
+ log("\n");
+ log(" -const\n");
+ log(" set some input bits to random constant values\n");
+ log("\n");
+ log(" -nosat\n");
+ log(" do not check SAT model or run SAT equivalence checking\n");
+ log("\n");
+ log(" -v\n");
+ log(" print additional debug information to the console\n");
+ log("\n");
+ log(" -vlog {filename}\n");
+ log(" create a verilog test bench to test simlib and write_verilog\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+ {
+ int num_iter = 100;
+ std::string techmap_cmd = "techmap -assert";
+ std::string ilang_file;
+ xorshift32_state = 0;
+ std::ofstream vlog_file;
+ bool verbose = false;
+ bool constmode = false;
+ bool nosat = false;
+
+ int argidx;
+ for (argidx = 1; argidx < SIZE(args); argidx++)
+ {
+ if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
+ num_iter = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-s" && argidx+1 < SIZE(args)) {
+ xorshift32_state = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-map" && argidx+1 < SIZE(args)) {
+ techmap_cmd += " -map " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-f" && argidx+1 < SIZE(args)) {
+ ilang_file = args[++argidx];
+ num_iter = 1;
+ continue;
+ }
+ if (args[argidx] == "-script" && argidx+1 < SIZE(args)) {
+ techmap_cmd = "script " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-simlib") {
+ techmap_cmd = "techmap -map +/simlib.v -max_iter 2 -autoproc";
+ continue;
+ }
+ if (args[argidx] == "-const") {
+ constmode = true;
+ continue;
+ }
+ if (args[argidx] == "-nosat") {
+ nosat = true;
+ continue;
+ }
+ if (args[argidx] == "-v") {
+ verbose = true;
+ continue;
+ }
+ if (args[argidx] == "-vlog" && argidx+1 < SIZE(args)) {
+ vlog_file.open(args[++argidx], std::ios_base::trunc);
+ if (!vlog_file.is_open())
+ log_cmd_error("Failed to open output file `%s'.\n", args[argidx].c_str());
+ continue;
+ }
+ break;
+ }
+
+ if (xorshift32_state == 0) {
+ xorshift32_state = time(NULL) & 0x7fffffff;
+ log("Rng seed value: %d\n", int(xorshift32_state));
+ }
+
+ std::map<std::string, std::string> cell_types;
+ std::vector<std::string> selected_cell_types;
+
+ cell_types["$not"] = "ASY";
+ cell_types["$pos"] = "ASY";
+ cell_types["$neg"] = "ASY";
+
+ cell_types["$and"] = "ABSY";
+ cell_types["$or"] = "ABSY";
+ cell_types["$xor"] = "ABSY";
+ cell_types["$xnor"] = "ABSY";
+
+ cell_types["$reduce_and"] = "ASY";
+ cell_types["$reduce_or"] = "ASY";
+ cell_types["$reduce_xor"] = "ASY";
+ cell_types["$reduce_xnor"] = "ASY";
+ cell_types["$reduce_bool"] = "ASY";
+
+ cell_types["$shl"] = "ABshY";
+ cell_types["$shr"] = "ABshY";
+ cell_types["$sshl"] = "ABshY";
+ cell_types["$sshr"] = "ABshY";
+ cell_types["$shift"] = "ABshY";
+ cell_types["$shiftx"] = "ABshY";
+
+ cell_types["$lt"] = "ABSY";
+ cell_types["$le"] = "ABSY";
+ cell_types["$eq"] = "ABSY";
+ cell_types["$ne"] = "ABSY";
+ // cell_types["$eqx"] = "ABSY";
+ // cell_types["$nex"] = "ABSY";
+ cell_types["$ge"] = "ABSY";
+ cell_types["$gt"] = "ABSY";
+
+ cell_types["$add"] = "ABSY";
+ cell_types["$sub"] = "ABSY";
+ cell_types["$mul"] = "ABSY";
+ cell_types["$div"] = "ABSY";
+ cell_types["$mod"] = "ABSY";
+ // cell_types["$pow"] = "ABsY";
+
+ cell_types["$logic_not"] = "ASY";
+ cell_types["$logic_and"] = "ABSY";
+ cell_types["$logic_or"] = "ABSY";
+
+ // cell_types["$mux"] = "A";
+ // cell_types["$pmux"] = "A";
+ // cell_types["$slice"] = "A";
+ // cell_types["$concat"] = "A";
+ // cell_types["$assert"] = "A";
+
+ cell_types["$lut"] = "*";
+ cell_types["$alu"] = "ABSY";
+ cell_types["$lcu"] = "*";
+ cell_types["$macc"] = "*";
+ cell_types["$fa"] = "*";
+
+ for (; argidx < SIZE(args); argidx++)
+ {
+ if (args[argidx].rfind("-", 0) == 0)
+ log_cmd_error("Unexpected option: %s\n", args[argidx].c_str());
+
+ if (args[argidx] == "all") {
+ for (auto &it : cell_types)
+ if (std::count(selected_cell_types.begin(), selected_cell_types.end(), it.first) == 0)
+ selected_cell_types.push_back(it.first);
+ continue;
+ }
+
+ if (cell_types.count(args[argidx]) == 0) {
+ std::string cell_type_list;
+ int charcount = 100;
+ for (auto &it : cell_types) {
+ if (charcount > 60) {
+ cell_type_list += "\n" + it.first;
+ charcount = 0;
+ } else
+ cell_type_list += " " + it.first;
+ charcount += SIZE(it.first);
+ }
+ log_cmd_error("The cell type `%s' is currently not supported. Try one of these:%s\n",
+ args[argidx].c_str(), cell_type_list.c_str());
+ }
+
+ if (std::count(selected_cell_types.begin(), selected_cell_types.end(), args[argidx]) == 0)
+ selected_cell_types.push_back(args[argidx]);
+ }
+
+ if (!ilang_file.empty()) {
+ if (!selected_cell_types.empty())
+ log_cmd_error("Do not specify any cell types when using -f.\n");
+ selected_cell_types.push_back("ilang");
+ }
+
+ if (selected_cell_types.empty())
+ log_cmd_error("No cell type to test specified.\n");
+
+ std::vector<std::string> uut_names;
+
+ for (auto cell_type : selected_cell_types)
+ for (int i = 0; i < num_iter; i++)
+ {
+ RTLIL::Design *design = new RTLIL::Design;
+ if (cell_type == "ilang")
+ Frontend::frontend_call(design, NULL, std::string(), "ilang " + ilang_file);
+ else
+ create_gold_module(design, cell_type, cell_types.at(cell_type), constmode);
+ Pass::call(design, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd.c_str()));
+ if (!nosat)
+ Pass::call(design, "miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter");
+ if (verbose)
+ Pass::call(design, "dump gate");
+ Pass::call(design, "dump gold");
+ if (!nosat)
+ Pass::call(design, "sat -verify -enable_undef -prove trigger 0 -show-inputs -show-outputs miter");
+ std::string uut_name = stringf("uut_%s_%d", cell_type.substr(1).c_str(), i);
+ if (vlog_file.is_open()) {
+ Pass::call(design, stringf("copy gold %s_expr; select %s_expr", uut_name.c_str(), uut_name.c_str()));
+ Backend::backend_call(design, &vlog_file, "<test_cell -vlog>", "verilog -selected");
+ Pass::call(design, stringf("copy gold %s_noexpr; select %s_noexpr", uut_name.c_str(), uut_name.c_str()));
+ Backend::backend_call(design, &vlog_file, "<test_cell -vlog>", "verilog -selected -noexpr");
+ uut_names.push_back(uut_name);
+ }
+ run_eval_test(design, verbose, nosat, uut_name, vlog_file);
+ delete design;
+ }
+
+ if (vlog_file.is_open()) {
+ vlog_file << "\nmodule testbench;\n";
+ for (auto &uut : uut_names)
+ vlog_file << stringf(" %s %s ();\n", uut.c_str(), uut.c_str());
+ vlog_file << " initial begin\n";
+ for (auto &uut : uut_names)
+ vlog_file << " " << uut << ".run;\n";
+ vlog_file << " end\n";
+ vlog_file << "endmodule\n";
+ }
+ }
+} TestCellPass;
+
diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc
index 6d94d5c9..7c8cc2f6 100644
--- a/techlibs/common/Makefile.inc
+++ b/techlibs/common/Makefile.inc
@@ -1,25 +1,35 @@
+OBJS += techlibs/common/synth.o
+
EXTRA_TARGETS += techlibs/common/blackbox.v
techlibs/common/blackbox.v: techlibs/common/blackbox.sed techlibs/common/simlib.v techlibs/common/simcells.v
- cat techlibs/common/simlib.v techlibs/common/simcells.v | sed -rf techlibs/common/blackbox.sed > techlibs/common/blackbox.v.new
- mv techlibs/common/blackbox.v.new techlibs/common/blackbox.v
+ $(P) cat techlibs/common/simlib.v techlibs/common/simcells.v | $(SED) -rf techlibs/common/blackbox.sed > techlibs/common/blackbox.v.new
+ $(Q) mv techlibs/common/blackbox.v.new techlibs/common/blackbox.v
-EXTRA_TARGETS += share/simlib.v share/simcells.v share/blackbox.v share/pmux2mux.v
+EXTRA_TARGETS += share/simlib.v share/simcells.v share/techmap.v share/blackbox.v share/pmux2mux.v share/adff2dff.v
share/simlib.v: techlibs/common/simlib.v
- mkdir -p share
- cp techlibs/common/simlib.v share/simlib.v
+ $(P) mkdir -p share
+ $(Q) cp techlibs/common/simlib.v share/simlib.v
share/simcells.v: techlibs/common/simcells.v
- mkdir -p share
- cp techlibs/common/simcells.v share/simcells.v
+ $(P) mkdir -p share
+ $(Q) cp techlibs/common/simcells.v share/simcells.v
+
+share/techmap.v: techlibs/common/techmap.v
+ $(P) mkdir -p share
+ $(Q) cp techlibs/common/techmap.v share/techmap.v
share/blackbox.v: techlibs/common/blackbox.v
- mkdir -p share
- cp techlibs/common/blackbox.v share/blackbox.v
+ $(P) mkdir -p share
+ $(Q) cp techlibs/common/blackbox.v share/blackbox.v
share/pmux2mux.v: techlibs/common/pmux2mux.v
- mkdir -p share
- cp techlibs/common/pmux2mux.v share/pmux2mux.v
+ $(P) mkdir -p share
+ $(Q) cp techlibs/common/pmux2mux.v share/pmux2mux.v
+
+share/adff2dff.v: techlibs/common/adff2dff.v
+ $(P) mkdir -p share
+ $(Q) cp techlibs/common/adff2dff.v share/adff2dff.v
diff --git a/techlibs/common/adff2dff.v b/techlibs/common/adff2dff.v
new file mode 100644
index 00000000..86744d41
--- /dev/null
+++ b/techlibs/common/adff2dff.v
@@ -0,0 +1,27 @@
+(* techmap_celltype = "$adff" *)
+module adff2dff (CLK, ARST, D, Q);
+ parameter WIDTH = 1;
+ parameter CLK_POLARITY = 1;
+ parameter ARST_POLARITY = 1;
+ parameter ARST_VALUE = 0;
+
+ input CLK, ARST;
+ input [WIDTH-1:0] D;
+ output reg [WIDTH-1:0] Q;
+ wire reg [WIDTH-1:0] NEXT_Q;
+
+ wire [1023:0] _TECHMAP_DO_ = "proc;;";
+
+ always @*
+ if (ARST == ARST_POLARITY)
+ NEXT_Q <= ARST_VALUE;
+ else
+ NEXT_Q <= D;
+
+ if (CLK_POLARITY)
+ always @(posedge CLK)
+ Q <= NEXT_Q;
+ else
+ always @(negedge CLK)
+ Q <= NEXT_Q;
+endmodule
diff --git a/techlibs/common/blackbox.sed b/techlibs/common/blackbox.sed
index 21693ecd..db890034 100644
--- a/techlibs/common/blackbox.sed
+++ b/techlibs/common/blackbox.sed
@@ -1,4 +1,5 @@
#!/bin/sed -r
-/^(wire|assign|reg|event)/ d;
-/^(genvar|generate|always|initial)/,/^end/ d;
+/^(wire|assign|reg|event|integer|localparam|\/\/|[\/ ]\*| *$|`)/ d;
+/^(genvar|generate|always|initial|task|function)/,/^end/ d;
+/^endmodule/ s/$/\n/;
s/ reg / /;
diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v
index 10a809db..a2a37735 100644
--- a/techlibs/common/simcells.v
+++ b/techlibs/common/simcells.v
@@ -20,12 +20,12 @@
* The internal logic cell simulation library.
*
* This verilog library contains simple simulation models for the internal
- * logic cells ($_INV_ , $_AND_ , ...) that are generated by the default technology
- * mapper (see "stdcells.v" in this directory) and expected by the "abc" pass.
+ * logic cells ($_NOT_ , $_AND_ , ...) that are generated by the default technology
+ * mapper (see "techmap.v" in this directory) and expected by the "abc" pass.
*
*/
-module \$_INV_ (A, Y);
+module \$_NOT_ (A, Y);
input A;
output Y;
assign Y = ~A;
@@ -37,24 +37,66 @@ output Y;
assign Y = A & B;
endmodule
+module \$_NAND_ (A, B, Y);
+input A, B;
+output Y;
+assign Y = ~(A & B);
+endmodule
+
module \$_OR_ (A, B, Y);
input A, B;
output Y;
assign Y = A | B;
endmodule
+module \$_NOR_ (A, B, Y);
+input A, B;
+output Y;
+assign Y = ~(A | B);
+endmodule
+
module \$_XOR_ (A, B, Y);
input A, B;
output Y;
assign Y = A ^ B;
endmodule
+module \$_XNOR_ (A, B, Y);
+input A, B;
+output Y;
+assign Y = ~(A ^ B);
+endmodule
+
module \$_MUX_ (A, B, S, Y);
input A, B, S;
output Y;
assign Y = S ? B : A;
endmodule
+module \$_AOI3_ (A, B, C, Y);
+input A, B, C;
+output Y;
+assign Y = ~((A & B) | C);
+endmodule
+
+module \$_OAI3_ (A, B, C, Y);
+input A, B, C;
+output Y;
+assign Y = ~((A | B) & C);
+endmodule
+
+module \$_AOI4_ (A, B, C, D, Y);
+input A, B, C, D;
+output Y;
+assign Y = ~((A & B) | (C & D));
+endmodule
+
+module \$_OAI4_ (A, B, C, D, Y);
+input A, B, C, D;
+output Y;
+assign Y = ~((A | B) & (C | D));
+endmodule
+
module \$_SR_NN_ (S, R, Q);
input S, R;
output reg Q;
@@ -325,3 +367,107 @@ always @* begin
end
endmodule
+module \$_DLATCHSR_NNN_ (E, S, R, D, Q);
+input E, S, R, D;
+output reg Q;
+always @* begin
+ if (R == 0)
+ Q <= 0;
+ else if (S == 0)
+ Q <= 1;
+ else if (E == 0)
+ Q <= D;
+end
+endmodule
+
+module \$_DLATCHSR_NNP_ (E, S, R, D, Q);
+input E, S, R, D;
+output reg Q;
+always @* begin
+ if (R == 1)
+ Q <= 0;
+ else if (S == 0)
+ Q <= 1;
+ else if (E == 0)
+ Q <= D;
+end
+endmodule
+
+module \$_DLATCHSR_NPN_ (E, S, R, D, Q);
+input E, S, R, D;
+output reg Q;
+always @* begin
+ if (R == 0)
+ Q <= 0;
+ else if (S == 1)
+ Q <= 1;
+ else if (E == 0)
+ Q <= D;
+end
+endmodule
+
+module \$_DLATCHSR_NPP_ (E, S, R, D, Q);
+input E, S, R, D;
+output reg Q;
+always @* begin
+ if (R == 1)
+ Q <= 0;
+ else if (S == 1)
+ Q <= 1;
+ else if (E == 0)
+ Q <= D;
+end
+endmodule
+
+module \$_DLATCHSR_PNN_ (E, S, R, D, Q);
+input E, S, R, D;
+output reg Q;
+always @* begin
+ if (R == 0)
+ Q <= 0;
+ else if (S == 0)
+ Q <= 1;
+ else if (E == 1)
+ Q <= D;
+end
+endmodule
+
+module \$_DLATCHSR_PNP_ (E, S, R, D, Q);
+input E, S, R, D;
+output reg Q;
+always @* begin
+ if (R == 1)
+ Q <= 0;
+ else if (S == 0)
+ Q <= 1;
+ else if (E == 1)
+ Q <= D;
+end
+endmodule
+
+module \$_DLATCHSR_PPN_ (E, S, R, D, Q);
+input E, S, R, D;
+output reg Q;
+always @* begin
+ if (R == 0)
+ Q <= 0;
+ else if (S == 1)
+ Q <= 1;
+ else if (E == 1)
+ Q <= D;
+end
+endmodule
+
+module \$_DLATCHSR_PPP_ (E, S, R, D, Q);
+input E, S, R, D;
+output reg Q;
+always @* begin
+ if (R == 1)
+ Q <= 0;
+ else if (S == 1)
+ Q <= 1;
+ else if (E == 1)
+ Q <= D;
+end
+endmodule
+
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index 4436abfe..2d8088ad 100644
--- a/techlibs/common/simlib.v
+++ b/techlibs/common/simlib.v
@@ -55,30 +55,6 @@ endmodule
// --------------------------------------------------------
-module \$bu0 (A, Y);
-
-parameter A_SIGNED = 0;
-parameter A_WIDTH = 0;
-parameter Y_WIDTH = 0;
-
-input [A_WIDTH-1:0] A;
-output [Y_WIDTH-1:0] Y;
-
-generate
- if (!A_SIGNED && 0 < A_WIDTH && A_WIDTH < Y_WIDTH) begin:BLOCK1
- assign Y[A_WIDTH-1:0] = A;
- assign Y[Y_WIDTH-1:A_WIDTH] = 0;
- end else if (A_SIGNED) begin:BLOCK2
- assign Y = $signed(A);
- end else begin:BLOCK3
- assign Y = A;
- end
-endgenerate
-
-endmodule
-
-// --------------------------------------------------------
-
module \$pos (A, Y);
parameter A_SIGNED = 0;
@@ -418,6 +394,142 @@ endmodule
// --------------------------------------------------------
+module \$shift (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+generate
+ if (B_SIGNED) begin:BLOCK1
+ assign Y = $signed(B) < 0 ? A << -B : A >> B;
+ end else begin:BLOCK2
+ assign Y = A >> B;
+ end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$shiftx (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+generate
+ if (Y_WIDTH > 0)
+ if (B_SIGNED) begin:BLOCK1
+ assign Y = A[$signed(B) +: Y_WIDTH];
+ end else begin:BLOCK2
+ assign Y = A[B +: Y_WIDTH];
+ end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$fa (A, B, C, X, Y);
+
+parameter WIDTH = 1;
+
+input [WIDTH-1:0] A, B, C;
+output [WIDTH-1:0] X, Y;
+
+wire [WIDTH-1:0] t1, t2, t3;
+
+assign t1 = A ^ B, t2 = A & B, t3 = C & t1;
+assign Y = t1 ^ C, X = (t2 | t3) ^ (Y ^ Y);
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$lcu (P, G, CI, CO);
+
+parameter WIDTH = 1;
+
+input [WIDTH-1:0] P, G;
+input CI;
+
+output reg [WIDTH-1:0] CO;
+
+integer i;
+always @* begin
+ CO = 'bx;
+ if (^{P, G, CI} !== 1'bx) begin
+ CO[0] = G[0] || (P[0] && CI);
+ for (i = 1; i < WIDTH; i = i+1)
+ CO[i] = G[i] || (P[i] && CO[i-1]);
+ end
+end
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$alu (A, B, CI, BI, X, Y, CO);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] X, Y;
+
+input CI, BI;
+output [Y_WIDTH-1:0] CO;
+
+wire [Y_WIDTH-1:0] AA, BB;
+
+generate
+ if (A_SIGNED && B_SIGNED) begin:BLOCK1
+ assign AA = $signed(A), BB = BI ? ~$signed(B) : $signed(B);
+ end else begin:BLOCK2
+ assign AA = $unsigned(A), BB = BI ? ~$unsigned(B) : $unsigned(B);
+ end
+endgenerate
+
+// this is 'x' if Y and CO should be all 'x', and '0' otherwise
+wire y_co_undef = ^{A, A, B, B, CI, CI, BI, BI};
+
+assign X = AA ^ BB;
+assign Y = (AA + BB + CI) ^ {Y_WIDTH{y_co_undef}};
+
+function get_carry;
+ input a, b, c;
+ get_carry = (a&b) | (a&c) | (b&c);
+endfunction
+
+genvar i;
+generate
+ assign CO[0] = get_carry(AA[0], BB[0], CI) ^ y_co_undef;
+ for (i = 1; i < Y_WIDTH; i = i+1) begin:BLOCK3
+ assign CO[i] = get_carry(AA[i], BB[i], CO[i-1]) ^ y_co_undef;
+ end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
module \$lt (A, B, Y);
parameter A_SIGNED = 0;
@@ -682,6 +794,108 @@ endmodule
// --------------------------------------------------------
+module \$macc (A, B, Y);
+
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+parameter CONFIG = 4'b0000;
+parameter CONFIG_WIDTH = 4;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output reg [Y_WIDTH-1:0] Y;
+
+// Xilinx XSIM does not like $clog2() below..
+function integer my_clog2;
+ input integer v;
+ begin
+ if (v > 0)
+ v = v - 1;
+ my_clog2 = 0;
+ while (v) begin
+ v = v >> 1;
+ my_clog2 = my_clog2 + 1;
+ end
+ end
+endfunction
+
+localparam integer num_bits = CONFIG[3:0] > 0 ? CONFIG[3:0] : 1;
+localparam integer num_ports = (CONFIG_WIDTH-4) / (2 + 2*num_bits);
+localparam integer num_abits = my_clog2(A_WIDTH) > 0 ? my_clog2(A_WIDTH) : 1;
+
+function [2*num_ports*num_abits-1:0] get_port_offsets;
+ input [CONFIG_WIDTH-1:0] cfg;
+ integer i, cursor;
+ begin
+ cursor = 0;
+ get_port_offsets = 0;
+ for (i = 0; i < num_ports; i = i+1) begin
+ get_port_offsets[(2*i + 0)*num_abits +: num_abits] = cursor;
+ cursor = cursor + cfg[4 + i*(2 + 2*num_bits) + 2 +: num_bits];
+ get_port_offsets[(2*i + 1)*num_abits +: num_abits] = cursor;
+ cursor = cursor + cfg[4 + i*(2 + 2*num_bits) + 2 + num_bits +: num_bits];
+ end
+ end
+endfunction
+
+localparam [2*num_ports*num_abits-1:0] port_offsets = get_port_offsets(CONFIG);
+
+`define PORT_IS_SIGNED (0 + CONFIG[4 + i*(2 + 2*num_bits)])
+`define PORT_DO_SUBTRACT (0 + CONFIG[4 + i*(2 + 2*num_bits) + 1])
+`define PORT_SIZE_A (0 + CONFIG[4 + i*(2 + 2*num_bits) + 2 +: num_bits])
+`define PORT_SIZE_B (0 + CONFIG[4 + i*(2 + 2*num_bits) + 2 + num_bits +: num_bits])
+`define PORT_OFFSET_A (0 + port_offsets[2*i*num_abits +: num_abits])
+`define PORT_OFFSET_B (0 + port_offsets[2*i*num_abits + num_abits +: num_abits])
+
+integer i, j;
+reg [Y_WIDTH-1:0] tmp_a, tmp_b;
+
+always @* begin
+ Y = 0;
+ for (i = 0; i < num_ports; i = i+1)
+ begin
+ tmp_a = 0;
+ tmp_b = 0;
+
+ for (j = 0; j < `PORT_SIZE_A; j = j+1)
+ tmp_a[j] = A[`PORT_OFFSET_A + j];
+
+ if (`PORT_IS_SIGNED && `PORT_SIZE_A > 0)
+ for (j = `PORT_SIZE_A; j < Y_WIDTH; j = j+1)
+ tmp_a[j] = tmp_a[`PORT_SIZE_A-1];
+
+ for (j = 0; j < `PORT_SIZE_B; j = j+1)
+ tmp_b[j] = A[`PORT_OFFSET_B + j];
+
+ if (`PORT_IS_SIGNED && `PORT_SIZE_B > 0)
+ for (j = `PORT_SIZE_B; j < Y_WIDTH; j = j+1)
+ tmp_b[j] = tmp_b[`PORT_SIZE_B-1];
+
+ if (`PORT_SIZE_B > 0)
+ tmp_a = tmp_a * tmp_b;
+
+ if (`PORT_DO_SUBTRACT)
+ Y = Y - tmp_a;
+ else
+ Y = Y + tmp_a;
+ end
+ for (i = 0; i < B_WIDTH; i = i+1) begin
+ Y = Y + B[i];
+ end
+end
+
+`undef PORT_IS_SIGNED
+`undef PORT_DO_SUBTRACT
+`undef PORT_SIZE_A
+`undef PORT_SIZE_B
+`undef PORT_OFFSET_A
+`undef PORT_OFFSET_B
+
+endmodule
+
+// --------------------------------------------------------
+
module \$div (A, B, Y);
parameter A_SIGNED = 0;
@@ -889,52 +1103,30 @@ input [S_WIDTH-1:0] S;
output reg [WIDTH-1:0] Y;
integer i;
+reg found_active_sel_bit;
always @* begin
Y = A;
- for (i = 0; i < S_WIDTH; i = i+1)
- if (S[i])
- Y = B >> (WIDTH*i);
-end
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$safe_pmux (A, B, S, Y);
-
-parameter WIDTH = 0;
-parameter S_WIDTH = 0;
-
-input [WIDTH-1:0] A;
-input [WIDTH*S_WIDTH-1:0] B;
-input [S_WIDTH-1:0] S;
-output reg [WIDTH-1:0] Y;
-
-integer i, j;
-
-always @* begin
- j = 0;
+ found_active_sel_bit = 0;
for (i = 0; i < S_WIDTH; i = i+1)
if (S[i]) begin
- Y = B >> (WIDTH*i);
- j = j + 1;
+ Y = found_active_sel_bit ? 'bx : B >> (WIDTH*i);
+ found_active_sel_bit = 1;
end
- if (j != 1)
- Y = A;
end
endmodule
// --------------------------------------------------------
+`ifndef SIMLIB_NOLUT
-module \$lut (I, O);
+module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
-input [WIDTH-1:0] I;
-output reg O;
+input [WIDTH-1:0] A;
+output reg Y;
wire lut0_out, lut1_out;
@@ -942,18 +1134,18 @@ generate
if (WIDTH <= 1) begin:simple
assign {lut1_out, lut0_out} = LUT;
end else begin:complex
- \$lut #( .WIDTH(WIDTH-1), .LUT(LUT ) ) lut0 ( .I(I[WIDTH-2:0]), .O(lut0_out) );
- \$lut #( .WIDTH(WIDTH-1), .LUT(LUT >> (2**(WIDTH-1))) ) lut1 ( .I(I[WIDTH-2:0]), .O(lut1_out) );
+ \$lut #( .WIDTH(WIDTH-1), .LUT(LUT ) ) lut0 ( .A(A[WIDTH-2:0]), .Y(lut0_out) );
+ \$lut #( .WIDTH(WIDTH-1), .LUT(LUT >> (2**(WIDTH-1))) ) lut1 ( .A(A[WIDTH-2:0]), .Y(lut1_out) );
end
if (WIDTH > 0) begin:lutlogic
always @* begin
- casez ({I[WIDTH-1], lut0_out, lut1_out})
- 3'b?11: O = 1'b1;
- 3'b?00: O = 1'b0;
- 3'b0??: O = lut0_out;
- 3'b1??: O = lut1_out;
- default: O = 1'bx;
+ casez ({A[WIDTH-1], lut0_out, lut1_out})
+ 3'b?11: Y = 1'b1;
+ 3'b?00: Y = 1'b0;
+ 3'b0??: Y = lut0_out;
+ 3'b1??: Y = lut1_out;
+ default: Y = 1'bx;
endcase
end
end
@@ -961,6 +1153,7 @@ endgenerate
endmodule
+`endif
// --------------------------------------------------------
module \$assert (A, EN);
@@ -977,6 +1170,7 @@ end
endmodule
// --------------------------------------------------------
+`ifndef SIMLIB_NOSR
module \$sr (SET, CLR, Q);
@@ -1003,6 +1197,7 @@ endgenerate
endmodule
+`endif
// --------------------------------------------------------
module \$dff (CLK, D, Q);
@@ -1022,6 +1217,7 @@ end
endmodule
// --------------------------------------------------------
+`ifndef SIMLIB_NOSR
module \$dffsr (CLK, SET, CLR, D, Q);
@@ -1053,6 +1249,7 @@ endgenerate
endmodule
+`endif
// --------------------------------------------------------
module \$adff (CLK, ARST, D, Q);
@@ -1096,6 +1293,40 @@ end
endmodule
// --------------------------------------------------------
+`ifndef SIMLIB_NOSR
+
+module \$dlatchsr (EN, SET, CLR, D, Q);
+
+parameter WIDTH = 0;
+parameter EN_POLARITY = 1'b1;
+parameter SET_POLARITY = 1'b1;
+parameter CLR_POLARITY = 1'b1;
+
+input EN;
+input [WIDTH-1:0] SET, CLR, D;
+output reg [WIDTH-1:0] Q;
+
+wire pos_en = EN == EN_POLARITY;
+wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET;
+wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR;
+
+genvar i;
+generate
+ for (i = 0; i < WIDTH; i = i+1) begin:bit
+ always @*
+ if (pos_clr[i])
+ Q[i] <= 0;
+ else if (pos_set[i])
+ Q[i] <= 1;
+ else if (pos_en)
+ Q[i] <= D[i];
+ end
+endgenerate
+
+endmodule
+
+`endif
+// --------------------------------------------------------
module \$fsm (CLK, ARST, CTRL_IN, CTRL_OUT);
@@ -1224,7 +1455,8 @@ parameter WIDTH = 8;
parameter CLK_ENABLE = 0;
parameter CLK_POLARITY = 0;
-input CLK, EN;
+input CLK;
+input [WIDTH-1:0] EN;
input [ABITS-1:0] ADDR;
input [WIDTH-1:0] DATA;
@@ -1260,7 +1492,8 @@ input [RD_PORTS-1:0] RD_CLK;
input [RD_PORTS*ABITS-1:0] RD_ADDR;
output reg [RD_PORTS*WIDTH-1:0] RD_DATA;
-input [WR_PORTS-1:0] WR_CLK, WR_EN;
+input [WR_PORTS-1:0] WR_CLK;
+input [WR_PORTS*WIDTH-1:0] WR_EN;
input [WR_PORTS*ABITS-1:0] WR_ADDR;
input [WR_PORTS*WIDTH-1:0] WR_DATA;
@@ -1273,71 +1506,94 @@ generate
for (i = 0; i < RD_PORTS; i = i+1) begin:rd
if (RD_CLK_ENABLE[i] == 0) begin:rd_noclk
always @(RD_ADDR or update_async_rd)
- RD_DATA[ i*WIDTH +: WIDTH ] <= data[ RD_ADDR[ i*ABITS +: ABITS ] - OFFSET ];
+ RD_DATA[i*WIDTH +: WIDTH] <= data[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
end else
if (RD_TRANSPARENT[i] == 1) begin:rd_transparent
reg [ABITS-1:0] addr_buf;
if (RD_CLK_POLARITY[i] == 1) begin:rd_trans_posclk
always @(posedge RD_CLK[i])
- addr_buf <= RD_ADDR[ i*ABITS +: ABITS ];
+ addr_buf <= RD_ADDR[i*ABITS +: ABITS];
end else begin:rd_trans_negclk
always @(negedge RD_CLK[i])
- addr_buf <= RD_ADDR[ i*ABITS +: ABITS ];
+ addr_buf <= RD_ADDR[i*ABITS +: ABITS];
end
always @(addr_buf or update_async_rd)
- RD_DATA[ i*WIDTH +: WIDTH ] <= data[ addr_buf - OFFSET ];
+ RD_DATA[i*WIDTH +: WIDTH] <= data[addr_buf - OFFSET];
end else begin:rd_notransparent
if (RD_CLK_POLARITY[i] == 1) begin:rd_notrans_posclk
always @(posedge RD_CLK[i])
- RD_DATA[ i*WIDTH +: WIDTH ] <= data[ RD_ADDR[ i*ABITS +: ABITS ] - OFFSET ];
+ RD_DATA[i*WIDTH +: WIDTH] <= data[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
end else begin:rd_notrans_negclk
always @(negedge RD_CLK[i])
- RD_DATA[ i*WIDTH +: WIDTH ] <= data[ RD_ADDR[ i*ABITS +: ABITS ] - OFFSET ];
+ RD_DATA[i*WIDTH +: WIDTH] <= data[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
end
end
end
for (i = 0; i < WR_PORTS; i = i+1) begin:wr
- integer k;
- reg found_collision;
+ integer k, n;
+ reg found_collision, run_update;
if (WR_CLK_ENABLE[i] == 0) begin:wr_noclk
always @(WR_ADDR or WR_DATA or WR_EN) begin
- if (WR_EN[i]) begin
- found_collision = 0;
- for (k = i+1; k < WR_PORTS; k = k+1)
- if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
- found_collision = 1;
- if (!found_collision) begin
- data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ];
- update_async_rd <= 1; update_async_rd <= 0;
+ run_update = 0;
+ for (n = 0; n < WIDTH; n = n+1) begin
+ if (WR_EN[i*WIDTH + n]) begin
+ found_collision = 0;
+ for (k = i+1; k < WR_PORTS; k = k+1)
+ if (WR_EN[k*WIDTH + n] && WR_ADDR[i*ABITS +: ABITS] == WR_ADDR[k*ABITS +: ABITS])
+ found_collision = 1;
+ if (!found_collision) begin
+ data[WR_ADDR[i*ABITS +: ABITS] - OFFSET][n] <= WR_DATA[i*WIDTH + n];
+ run_update = 1;
+ end
end
end
+ if (run_update) begin
+ update_async_rd <= 1;
+ update_async_rd <= 0;
+ end
end
end else
if (WR_CLK_POLARITY[i] == 1) begin:rd_posclk
- always @(posedge WR_CLK[i])
- if (WR_EN[i]) begin
- found_collision = 0;
- for (k = i+1; k < WR_PORTS; k = k+1)
- if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
- found_collision = 1;
- if (!found_collision) begin
- data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ];
- update_async_rd <= 1; update_async_rd <= 0;
+ always @(posedge WR_CLK[i]) begin
+ run_update = 0;
+ for (n = 0; n < WIDTH; n = n+1) begin
+ if (WR_EN[i*WIDTH + n]) begin
+ found_collision = 0;
+ for (k = i+1; k < WR_PORTS; k = k+1)
+ if (WR_EN[k*WIDTH + n] && WR_ADDR[i*ABITS +: ABITS] == WR_ADDR[k*ABITS +: ABITS])
+ found_collision = 1;
+ if (!found_collision) begin
+ data[WR_ADDR[i*ABITS +: ABITS] - OFFSET][n] <= WR_DATA[i*WIDTH + n];
+ run_update = 1;
+ end
end
end
+ if (run_update) begin
+ update_async_rd <= 1;
+ update_async_rd <= 0;
+ end
+ end
end else begin:rd_negclk
- always @(negedge WR_CLK[i])
- if (WR_EN[i]) begin
- found_collision = 0;
- for (k = i+1; k < WR_PORTS; k = k+1)
- if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
- found_collision = 1;
- if (!found_collision) begin
- data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ];
- update_async_rd <= 1; update_async_rd <= 0;
+ always @(negedge WR_CLK[i]) begin
+ run_update = 0;
+ for (n = 0; n < WIDTH; n = n+1) begin
+ if (WR_EN[i*WIDTH + n]) begin
+ found_collision = 0;
+ for (k = i+1; k < WR_PORTS; k = k+1)
+ if (WR_EN[k*WIDTH + n] && WR_ADDR[i*ABITS +: ABITS] == WR_ADDR[k*ABITS +: ABITS])
+ found_collision = 1;
+ if (!found_collision) begin
+ data[WR_ADDR[i*ABITS +: ABITS] - OFFSET][n] <= WR_DATA[i*WIDTH + n];
+ run_update = 1;
+ end
end
end
+ if (run_update) begin
+ update_async_rd <= 1;
+ update_async_rd <= 0;
+ end
+ end
end
end
diff --git a/techlibs/common/stdcells.v b/techlibs/common/stdcells.v
deleted file mode 100644
index fdee26b6..00000000
--- a/techlibs/common/stdcells.v
+++ /dev/null
@@ -1,1080 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * ---
- *
- * The internal logic cell technology mapper.
- *
- * This verilog library contains the mapping of internal cells (e.g. $not with
- * variable bit width) to the internal logic cells (such as the single bit $_INV_
- * gate). Usually this logic network is then mapped to the actual technology
- * using e.g. the "abc" pass.
- *
- * Note that this library does not map $mem cells. They must be mapped to logic
- * and $dff cells using the "memory_map" pass first. (Or map it to custom cells,
- * which is of course highly recommended for larger memories.)
- *
- */
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$not ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$pos ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$bu0 ;
-endmodule
-
-// --------------------------------------------------------
-
-module \$neg (A, Y);
-
-parameter A_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-input [A_WIDTH-1:0] A;
-output [Y_WIDTH-1:0] Y;
-
-\$sub #(
- .A_SIGNED(A_SIGNED),
- .B_SIGNED(A_SIGNED),
- .A_WIDTH(1),
- .B_WIDTH(A_WIDTH),
- .Y_WIDTH(Y_WIDTH)
-) sub (
- .A(1'b0),
- .B(A),
- .Y(Y)
-);
-
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$and ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$or ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$xor ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$xnor ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$reduce_and ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$reduce_or ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$reduce_xor ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$reduce_xnor ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$reduce_bool ;
-endmodule
-
-// --------------------------------------------------------
-
-module \$__shift (X, A, Y);
-
-parameter WIDTH = 1;
-parameter SHIFT = 0;
-
-input X;
-input [WIDTH-1:0] A;
-output [WIDTH-1:0] Y;
-
-genvar i;
-generate
- for (i = 0; i < WIDTH; i = i + 1) begin:V
- if (i+SHIFT < 0) begin
- assign Y[i] = 0;
- end else
- if (i+SHIFT < WIDTH) begin
- assign Y[i] = A[i+SHIFT];
- end else begin
- assign Y[i] = X;
- end
- end
-endgenerate
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$shl (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-parameter WIDTH = Y_WIDTH;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-genvar i;
-generate
- wire [WIDTH*(B_WIDTH+1)-1:0] chain;
- \$pos #(
- .A_SIGNED(A_SIGNED),
- .A_WIDTH(A_WIDTH),
- .Y_WIDTH(WIDTH)
- ) expand (
- .A(A),
- .Y(chain[WIDTH-1:0])
- );
- assign Y = chain[WIDTH*(B_WIDTH+1)-1 : WIDTH*B_WIDTH];
- for (i = 0; i < B_WIDTH; i = i + 1) begin:V
- wire [WIDTH-1:0] unshifted, shifted, result;
- assign unshifted = chain[WIDTH*i + WIDTH-1 : WIDTH*i];
- assign chain[WIDTH*(i+1) + WIDTH-1 : WIDTH*(i+1)] = result;
- \$__shift #(
- .WIDTH(WIDTH),
- .SHIFT(0 - (2 ** (i > 30 ? 30 : i)))
- ) sh (
- .X(0),
- .A(unshifted),
- .Y(shifted)
- );
- \$mux #(
- .WIDTH(WIDTH)
- ) mux (
- .A(unshifted),
- .B(shifted),
- .Y(result),
- .S(B[i])
- );
- end
-endgenerate
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$shr (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-localparam WIDTH = A_WIDTH > Y_WIDTH ? A_WIDTH : Y_WIDTH;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-genvar i;
-generate
- wire [WIDTH*(B_WIDTH+1)-1:0] chain;
- \$pos #(
- .A_SIGNED(A_SIGNED),
- .A_WIDTH(A_WIDTH),
- .Y_WIDTH(WIDTH)
- ) expand (
- .A(A),
- .Y(chain[WIDTH-1:0])
- );
- assign Y = chain[WIDTH*(B_WIDTH+1)-1 : WIDTH*B_WIDTH];
- for (i = 0; i < B_WIDTH; i = i + 1) begin:V
- wire [WIDTH-1:0] unshifted, shifted, result;
- assign unshifted = chain[WIDTH*i + WIDTH-1 : WIDTH*i];
- assign chain[WIDTH*(i+1) + WIDTH-1 : WIDTH*(i+1)] = result;
- \$__shift #(
- .WIDTH(WIDTH),
- .SHIFT(2 ** (i > 30 ? 30 : i))
- ) sh (
- .X(0),
- .A(unshifted),
- .Y(shifted)
- );
- \$mux #(
- .WIDTH(WIDTH)
- ) mux (
- .A(unshifted),
- .B(shifted),
- .Y(result),
- .S(B[i])
- );
- end
-endgenerate
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$sshl (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-localparam WIDTH = Y_WIDTH;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-genvar i;
-generate
- wire [WIDTH*(B_WIDTH+1)-1:0] chain;
- \$pos #(
- .A_SIGNED(A_SIGNED),
- .A_WIDTH(A_WIDTH),
- .Y_WIDTH(WIDTH)
- ) expand (
- .A(A),
- .Y(chain[WIDTH-1:0])
- );
- assign Y = chain[WIDTH*(B_WIDTH+1)-1 : WIDTH*B_WIDTH];
- for (i = 0; i < B_WIDTH; i = i + 1) begin:V
- wire [WIDTH-1:0] unshifted, shifted, result;
- assign unshifted = chain[WIDTH*i + WIDTH-1 : WIDTH*i];
- assign chain[WIDTH*(i+1) + WIDTH-1 : WIDTH*(i+1)] = result;
- \$__shift #(
- .WIDTH(WIDTH),
- .SHIFT(0 - (2 ** (i > 30 ? 30 : i)))
- ) sh (
- .X(0),
- .A(unshifted),
- .Y(shifted)
- );
- \$mux #(
- .WIDTH(WIDTH)
- ) mux (
- .A(unshifted),
- .B(shifted),
- .Y(result),
- .S(B[i])
- );
- end
-endgenerate
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$sshr (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-localparam WIDTH = A_WIDTH > Y_WIDTH ? A_WIDTH : Y_WIDTH;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-genvar i;
-generate
- wire [WIDTH*(B_WIDTH+1)-1:0] chain;
- \$pos #(
- .A_SIGNED(A_SIGNED),
- .A_WIDTH(A_WIDTH),
- .Y_WIDTH(WIDTH)
- ) expand (
- .A(A),
- .Y(chain[WIDTH-1:0])
- );
- for (i = 0; i < Y_WIDTH; i = i + 1) begin:Y
- if (i < WIDTH) begin
- assign Y[i] = chain[WIDTH*B_WIDTH + i];
- end else
- if (A_SIGNED) begin
- assign Y[i] = chain[WIDTH*B_WIDTH + WIDTH-1];
- end else begin
- assign Y[i] = 0;
- end
- end
- for (i = 0; i < B_WIDTH; i = i + 1) begin:V
- wire [WIDTH-1:0] unshifted, shifted, result;
- assign unshifted = chain[WIDTH*i + WIDTH-1 : WIDTH*i];
- assign chain[WIDTH*(i+1) + WIDTH-1 : WIDTH*(i+1)] = result;
- \$__shift #(
- .WIDTH(WIDTH),
- .SHIFT(2 ** (i > 30 ? 30 : i))
- ) sh (
- .X(A_SIGNED && A[A_WIDTH-1]),
- .A(unshifted),
- .Y(shifted)
- );
- \$mux #(
- .WIDTH(WIDTH)
- ) mux (
- .A(unshifted),
- .B(shifted),
- .Y(result),
- .S(B[i])
- );
- end
-endgenerate
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$__fulladd (A, B, C, X, Y);
-
-// {X, Y} = A + B + C
-input A, B, C;
-output X, Y;
-
-// {t1, t2} = A + B
-wire t1, t2, t3;
-
-\$_AND_ gate1 ( .A(A), .B(B), .Y(t1) );
-\$_XOR_ gate2 ( .A(A), .B(B), .Y(t2) );
-\$_AND_ gate3 ( .A(t2), .B(C), .Y(t3) );
-\$_XOR_ gate4 ( .A(t2), .B(C), .Y(Y) );
-\$_OR_ gate5 ( .A(t1), .B(t3), .Y(X) );
-
-endmodule
-
-
-// --------------------------------------------------------
-
-module \$__alu (A, B, Cin, Y, Cout, Csign);
-
-parameter WIDTH = 1;
-
-input [WIDTH-1:0] A, B;
-input Cin;
-
-output [WIDTH-1:0] Y;
-output Cout, Csign;
-
-wire [WIDTH:0] carry;
-assign carry[0] = Cin;
-assign Cout = carry[WIDTH];
-assign Csign = carry[WIDTH-1];
-
-genvar i;
-generate
- for (i = 0; i < WIDTH; i = i + 1) begin:V
- \$__fulladd adder (
- .A(A[i]),
- .B(B[i]),
- .C(carry[i]),
- .X(carry[i+1]),
- .Y(Y[i])
- );
- end
-endgenerate
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$lt (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-wire carry, carry_sign;
-wire [WIDTH-1:0] A_buf, B_buf, Y_buf;
-\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
-\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
-
-\$__alu #(
- .WIDTH(WIDTH)
-) alu (
- .A(A_buf),
- .B(~B_buf),
- .Cin(1'b1),
- .Y(Y_buf),
- .Cout(carry),
- .Csign(carry_sign)
-);
-
-// ALU flags
-wire cf, of, zf, sf;
-assign cf = !carry;
-assign of = carry ^ carry_sign;
-assign zf = ~|Y_buf;
-assign sf = Y_buf[WIDTH-1];
-
-generate
- if (A_SIGNED && B_SIGNED) begin
- assign Y = of != sf;
- end else begin
- assign Y = cf;
- end
-endgenerate
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$le (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-wire carry, carry_sign;
-wire [WIDTH-1:0] A_buf, B_buf, Y_buf;
-\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
-\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
-
-\$__alu #(
- .WIDTH(WIDTH)
-) alu (
- .A(A_buf),
- .B(~B_buf),
- .Cin(1'b1),
- .Y(Y_buf),
- .Cout(carry),
- .Csign(carry_sign)
-);
-
-// ALU flags
-wire cf, of, zf, sf;
-assign cf = !carry;
-assign of = carry ^ carry_sign;
-assign zf = ~|Y_buf;
-assign sf = Y_buf[WIDTH-1];
-
-generate
- if (A_SIGNED && B_SIGNED) begin
- assign Y = zf || (of != sf);
- end else begin
- assign Y = zf || cf;
- end
-endgenerate
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$eq (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-wire carry, carry_sign;
-wire [WIDTH-1:0] A_buf, B_buf;
-\$bu0 #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
-\$bu0 #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
-
-assign Y = ~|(A_buf ^ B_buf);
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$ne (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-wire carry, carry_sign;
-wire [WIDTH-1:0] A_buf, B_buf;
-\$bu0 #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
-\$bu0 #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
-
-assign Y = |(A_buf ^ B_buf);
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$eqx (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-wire carry, carry_sign;
-wire [WIDTH-1:0] A_buf, B_buf;
-\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
-\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
-
-assign Y = ~|(A_buf ^ B_buf);
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$nex (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-wire carry, carry_sign;
-wire [WIDTH-1:0] A_buf, B_buf;
-\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
-\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
-
-assign Y = |(A_buf ^ B_buf);
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$ge (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-\$le #(
- .A_SIGNED(B_SIGNED),
- .B_SIGNED(A_SIGNED),
- .A_WIDTH(B_WIDTH),
- .B_WIDTH(A_WIDTH),
- .Y_WIDTH(Y_WIDTH)
-) ge_via_le (
- .A(B),
- .B(A),
- .Y(Y)
-);
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$gt (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-\$lt #(
- .A_SIGNED(B_SIGNED),
- .B_SIGNED(A_SIGNED),
- .A_WIDTH(B_WIDTH),
- .B_WIDTH(A_WIDTH),
- .Y_WIDTH(Y_WIDTH)
-) gt_via_lt (
- .A(B),
- .B(A),
- .Y(Y)
-);
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$add (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-wire [Y_WIDTH-1:0] A_buf, B_buf;
-\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
-\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
-
-\$__alu #(
- .WIDTH(Y_WIDTH)
-) alu (
- .A(A_buf),
- .B(B_buf),
- .Cin(1'b0),
- .Y(Y)
-);
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$sub (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-wire [Y_WIDTH-1:0] A_buf, B_buf;
-\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
-\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
-
-\$__alu #(
- .WIDTH(Y_WIDTH)
-) alu (
- .A(A_buf),
- .B(~B_buf),
- .Cin(1'b1),
- .Y(Y)
-);
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$__arraymul (A, B, Y);
-
-parameter WIDTH = 8;
-input [WIDTH-1:0] A, B;
-output [WIDTH-1:0] Y;
-
-wire [WIDTH*WIDTH-1:0] partials;
-
-genvar i;
-assign partials[WIDTH-1 : 0] = A[0] ? B : 0;
-generate for (i = 1; i < WIDTH; i = i+1) begin:gen
- assign partials[WIDTH*(i+1)-1 : WIDTH*i] = (A[i] ? B << i : 0) + partials[WIDTH*i-1 : WIDTH*(i-1)];
-end endgenerate
-
-assign Y = partials[WIDTH*WIDTH-1 : WIDTH*(WIDTH-1)];
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$mul (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-wire [Y_WIDTH-1:0] A_buf, B_buf;
-\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
-\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
-
-\$__arraymul #(
- .WIDTH(Y_WIDTH)
-) arraymul (
- .A(A_buf),
- .B(B_buf),
- .Y(Y)
-);
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$__div_mod_u (A, B, Y, R);
-
-parameter WIDTH = 1;
-
-input [WIDTH-1:0] A, B;
-output [WIDTH-1:0] Y, R;
-
-wire [WIDTH*WIDTH-1:0] chaindata;
-assign R = chaindata[WIDTH*WIDTH-1:WIDTH*(WIDTH-1)];
-
-genvar i;
-generate begin
- for (i = 0; i < WIDTH; i=i+1) begin:stage
- wire [WIDTH-1:0] stage_in;
-
- if (i == 0) begin:cp
- assign stage_in = A;
- end else begin:cp
- assign stage_in = chaindata[i*WIDTH-1:(i-1)*WIDTH];
- end
-
- assign Y[WIDTH-(i+1)] = stage_in >= {B, {WIDTH-(i+1){1'b0}}};
- assign chaindata[(i+1)*WIDTH-1:i*WIDTH] = Y[WIDTH-(i+1)] ? stage_in - {B, {WIDTH-(i+1){1'b0}}} : stage_in;
- end
-end endgenerate
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$__div_mod (A, B, Y, R);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-localparam WIDTH =
- A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH :
- B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y, R;
-
-wire [WIDTH-1:0] A_buf, B_buf;
-\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
-\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
-
-wire [WIDTH-1:0] A_buf_u, B_buf_u, Y_u, R_u;
-assign A_buf_u = A_SIGNED && A_buf[WIDTH-1] ? -A_buf : A_buf;
-assign B_buf_u = B_SIGNED && B_buf[WIDTH-1] ? -B_buf : B_buf;
-
-\$__div_mod_u #(
- .WIDTH(WIDTH)
-) div_mod_u (
- .A(A_buf_u),
- .B(B_buf_u),
- .Y(Y_u),
- .R(R_u)
-);
-
-assign Y = A_SIGNED && B_SIGNED && (A_buf[WIDTH-1] != B_buf[WIDTH-1]) ? -Y_u : Y_u;
-assign R = A_SIGNED && B_SIGNED && A_buf[WIDTH-1] ? -R_u : R_u;
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$div (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-\$__div_mod #(
- .A_SIGNED(A_SIGNED),
- .B_SIGNED(B_SIGNED),
- .A_WIDTH(A_WIDTH),
- .B_WIDTH(B_WIDTH),
- .Y_WIDTH(Y_WIDTH)
-) div_mod (
- .A(A),
- .B(B),
- .Y(Y)
-);
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$mod (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-\$__div_mod #(
- .A_SIGNED(A_SIGNED),
- .B_SIGNED(B_SIGNED),
- .A_WIDTH(A_WIDTH),
- .B_WIDTH(B_WIDTH),
- .Y_WIDTH(Y_WIDTH)
-) div_mod (
- .A(A),
- .B(B),
- .R(Y)
-);
-
-endmodule
-
-/****
-// --------------------------------------------------------
-
-module \$pow (A, B, Y);
-
-parameter A_SIGNED = 0;
-parameter B_SIGNED = 0;
-parameter A_WIDTH = 1;
-parameter B_WIDTH = 1;
-parameter Y_WIDTH = 1;
-
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] Y;
-
-wire signed [A_WIDTH:0] buffer_a = A_SIGNED ? $signed(A) : A;
-wire signed [B_WIDTH:0] buffer_b = B_SIGNED ? $signed(B) : B;
-
-assign Y = buffer_a ** buffer_b;
-
-endmodule
-
-// --------------------------------------------------------
-****/
-
-(* techmap_simplemap *)
-module \$logic_not ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$logic_and ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$logic_or ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$slice ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$concat ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$mux ;
-endmodule
-
-// --------------------------------------------------------
-
-module \$pmux (A, B, S, Y);
-
-parameter WIDTH = 1;
-parameter S_WIDTH = 1;
-
-input [WIDTH-1:0] A;
-input [WIDTH*S_WIDTH-1:0] B;
-input [S_WIDTH-1:0] S;
-output [WIDTH-1:0] Y;
-
-wire [WIDTH-1:0] Y_B;
-
-genvar i, j;
-generate
- wire [WIDTH*S_WIDTH-1:0] B_AND_S;
- for (i = 0; i < S_WIDTH; i = i + 1) begin:B_AND
- assign B_AND_S[WIDTH*(i+1)-1:WIDTH*i] = B[WIDTH*(i+1)-1:WIDTH*i] & {WIDTH{S[i]}};
- end:B_AND
- for (i = 0; i < WIDTH; i = i + 1) begin:B_OR
- wire [S_WIDTH-1:0] B_AND_BITS;
- for (j = 0; j < S_WIDTH; j = j + 1) begin:B_AND_BITS_COLLECT
- assign B_AND_BITS[j] = B_AND_S[WIDTH*j+i];
- end:B_AND_BITS_COLLECT
- assign Y_B[i] = |B_AND_BITS;
- end:B_OR
-endgenerate
-
-assign Y = |S ? Y_B : A;
-
-endmodule
-
-// --------------------------------------------------------
-
-module \$safe_pmux (A, B, S, Y);
-
-parameter WIDTH = 1;
-parameter S_WIDTH = 1;
-
-input [WIDTH-1:0] A;
-input [WIDTH*S_WIDTH-1:0] B;
-input [S_WIDTH-1:0] S;
-output [WIDTH-1:0] Y;
-
-wire [S_WIDTH-1:0] status_found_first;
-wire [S_WIDTH-1:0] status_found_second;
-
-genvar i;
-generate
- for (i = 0; i < S_WIDTH; i = i + 1) begin:GEN1
- wire pre_first;
- if (i > 0) begin:GEN2
- assign pre_first = status_found_first[i-1];
- end:GEN2 else begin:GEN3
- assign pre_first = 0;
- end:GEN3
- assign status_found_first[i] = pre_first | S[i];
- assign status_found_second[i] = pre_first & S[i];
- end:GEN1
-endgenerate
-
-\$pmux #(
- .WIDTH(WIDTH),
- .S_WIDTH(S_WIDTH)
-) pmux_cell (
- .A(A),
- .B(B),
- .S(S & {S_WIDTH{~|status_found_second}}),
- .Y(Y)
-);
-
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$sr ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$dff ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$adff ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$dffsr ;
-endmodule
-
-// --------------------------------------------------------
-
-(* techmap_simplemap *)
-module \$dlatch ;
-endmodule
-
-// --------------------------------------------------------
-
diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc
new file mode 100644
index 00000000..4ccacd30
--- /dev/null
+++ b/techlibs/common/synth.cc
@@ -0,0 +1,156 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+static bool check_label(bool &active, std::string run_from, std::string run_to, std::string label)
+{
+ if (!run_from.empty() && run_from == run_to) {
+ active = (label == run_from);
+ } else {
+ if (label == run_from)
+ active = true;
+ if (label == run_to)
+ active = false;
+ }
+ return active;
+}
+
+struct SynthPass : public Pass {
+ SynthPass() : Pass("synth", "generic synthesis script") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth [options]\n");
+ log("\n");
+ log("This command runs the default synthesis script. This command does not operate\n");
+ log("on partly selected designs.\n");
+ log("\n");
+ log(" -top <module>\n");
+ log(" use the specified module as top module (default='top')\n");
+ log("\n");
+ log(" -run <from_label>[:<to_label>]\n");
+ log(" only run the commands between the labels (see below). an empty\n");
+ log(" from label is synonymous to 'begin', and empty to label is\n");
+ log(" synonymous to the end of the command list.\n");
+ log("\n");
+ log("\n");
+ log("The following commands are executed by this synthesis command:\n");
+ log("\n");
+ log(" begin:\n");
+ log(" hierarchy -check [-top <top>]\n");
+ log("\n");
+ log(" coarse:\n");
+ log(" proc\n");
+ log(" opt\n");
+ log(" wreduce\n");
+ log(" alumacc\n");
+ log(" share\n");
+ log(" opt\n");
+ log(" fsm\n");
+ log(" opt -fast\n");
+ log(" memory -nomap\n");
+ log(" opt_clean\n");
+ log("\n");
+ log(" fine:\n");
+ log(" memory_map\n");
+ log(" techmap\n");
+ log(" opt -fast\n");
+ #ifdef YOSYS_ENABLE_ABC
+ log(" abc -fast\n");
+ log(" opt_clean\n");
+ #endif
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ std::string top_module;
+ std::string run_from, run_to;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-top" && argidx+1 < args.size()) {
+ top_module = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-run" && argidx+1 < args.size()) {
+ size_t pos = args[argidx+1].find(':');
+ if (pos == std::string::npos) {
+ run_from = args[++argidx];
+ run_to = args[argidx];
+ } else {
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos+1);
+ }
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!design->full_selection())
+ log_cmd_error("This comannd only operates on fully selected designs!\n");
+
+ bool active = run_from.empty();
+
+ log_header("Executing SYNTH pass.\n");
+ log_push();
+
+ if (check_label(active, run_from, run_to, "begin"))
+ {
+ if (top_module.empty())
+ Pass::call(design, stringf("hierarchy -check"));
+ else
+ Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str()));
+ }
+
+ if (check_label(active, run_from, run_to, "coarse"))
+ {
+ Pass::call(design, "proc");
+ Pass::call(design, "opt");
+ Pass::call(design, "wreduce");
+ Pass::call(design, "alumacc");
+ Pass::call(design, "share");
+ Pass::call(design, "opt");
+ Pass::call(design, "fsm");
+ Pass::call(design, "opt -fast");
+ Pass::call(design, "memory -nomap");
+ Pass::call(design, "opt_clean");
+ }
+
+ if (check_label(active, run_from, run_to, "fine"))
+ {
+ Pass::call(design, "memory_map");
+ Pass::call(design, "techmap");
+ Pass::call(design, "opt -fast");
+ #ifdef YOSYS_ENABLE_ABC
+ Pass::call(design, "abc -fast");
+ Pass::call(design, "opt_clean");
+ #endif
+ }
+
+ log_pop();
+ }
+} SynthPass;
+
diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v
new file mode 100644
index 00000000..b6c075b6
--- /dev/null
+++ b/techlibs/common/techmap.v
@@ -0,0 +1,509 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * ---
+ *
+ * The internal logic cell technology mapper.
+ *
+ * This verilog library contains the mapping of internal cells (e.g. $not with
+ * variable bit width) to the internal logic cells (such as the single bit $_NOT_
+ * gate). Usually this logic network is then mapped to the actual technology
+ * using e.g. the "abc" pass.
+ *
+ * Note that this library does not map $mem cells. They must be mapped to logic
+ * and $dff cells using the "memory_map" pass first. (Or map it to custom cells,
+ * which is of course highly recommended for larger memories.)
+ *
+ */
+
+`define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
+`define MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
+
+
+// --------------------------------------------------------
+// Use simplemap for trivial cell types
+// --------------------------------------------------------
+
+(* techmap_simplemap *)
+(* techmap_celltype = "$not $and $or $xor $xnor" *)
+module _90_simplemap_bool_ops;
+endmodule
+
+(* techmap_simplemap *)
+(* techmap_celltype = "$reduce_and $reduce_or $reduce_xor $reduce_xnor $reduce_bool" *)
+module _90_simplemap_reduce_ops;
+endmodule
+
+(* techmap_simplemap *)
+(* techmap_celltype = "$logic_not $logic_and $logic_or" *)
+module _90_simplemap_logic_ops;
+endmodule
+
+(* techmap_simplemap *)
+(* techmap_celltype = "$pos $slice $concat $mux" *)
+module _90_simplemap_various;
+endmodule
+
+(* techmap_simplemap *)
+(* techmap_celltype = "$sr $dff $adff $dffsr $dlatch" *)
+module _90_simplemap_registers;
+endmodule
+
+
+// --------------------------------------------------------
+// Shift operators
+// --------------------------------------------------------
+
+(* techmap_celltype = "$shr $shl $sshl $sshr" *)
+module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ parameter _TECHMAP_CELLTYPE_ = "";
+ localparam shift_left = _TECHMAP_CELLTYPE_ == "$shl" || _TECHMAP_CELLTYPE_ == "$sshl";
+ localparam sign_extend = A_SIGNED && _TECHMAP_CELLTYPE_ == "$sshr";
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ localparam WIDTH = `MAX(A_WIDTH, Y_WIDTH);
+ localparam BB_WIDTH = `MIN($clog2(shift_left ? Y_WIDTH : A_SIGNED ? WIDTH : A_WIDTH) + 1, B_WIDTH);
+
+ wire [1023:0] _TECHMAP_DO_00_ = "proc;;";
+ wire [1023:0] _TECHMAP_DO_01_ = "RECURSION; CONSTMAP; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;";
+
+ integer i;
+ reg [WIDTH-1:0] buffer;
+ reg overflow;
+
+ always @* begin
+ overflow = B_WIDTH > BB_WIDTH ? |B[B_WIDTH-1:BB_WIDTH] : 1'b0;
+ buffer = overflow ? {WIDTH{sign_extend ? A[A_WIDTH-1] : 1'b0}} : {{WIDTH-A_WIDTH{A_SIGNED ? A[A_WIDTH-1] : 1'b0}}, A};
+
+ for (i = 0; i < BB_WIDTH; i = i+1)
+ if (B[i]) begin
+ if (shift_left)
+ buffer = {buffer, (2**i)'b0};
+ else if (2**i < WIDTH)
+ buffer = {{2**i{sign_extend ? buffer[WIDTH-1] : 1'b0}}, buffer[WIDTH-1 : 2**i]};
+ else
+ buffer = {WIDTH{sign_extend ? buffer[WIDTH-1] : 1'b0}};
+ end
+ end
+
+ assign Y = buffer;
+endmodule
+
+(* techmap_celltype = "$shift $shiftx" *)
+module _90_shift_shiftx (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ localparam BB_WIDTH = `MIN($clog2(`MAX(A_WIDTH, Y_WIDTH)) + (B_SIGNED ? 2 : 1), B_WIDTH);
+ localparam WIDTH = `MAX(A_WIDTH, Y_WIDTH) + (B_SIGNED ? 2**(BB_WIDTH-1) : 0);
+
+ parameter _TECHMAP_CELLTYPE_ = "";
+ localparam extbit = _TECHMAP_CELLTYPE_ == "$shift" ? 1'b0 : 1'bx;
+
+ wire [1023:0] _TECHMAP_DO_00_ = "proc;;";
+ wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;";
+
+ integer i;
+ reg [WIDTH-1:0] buffer;
+ reg overflow;
+
+ always @* begin
+ overflow = 0;
+ buffer = {WIDTH{extbit}};
+ buffer[`MAX(A_WIDTH, Y_WIDTH)-1:0] = A;
+
+ if (B_WIDTH > BB_WIDTH) begin
+ if (B_SIGNED) begin
+ for (i = BB_WIDTH; i < B_WIDTH; i = i+1)
+ if (B[i] != B[BB_WIDTH-1])
+ overflow = 1;
+ end else
+ overflow = |B[B_WIDTH-1:BB_WIDTH];
+ if (overflow)
+ buffer = {WIDTH{extbit}};
+ end
+
+ for (i = BB_WIDTH-1; i >= 0; i = i-1)
+ if (B[i]) begin
+ if (B_SIGNED && i == BB_WIDTH-1)
+ buffer = {buffer, {2**i{extbit}}};
+ else if (2**i < WIDTH)
+ buffer = {{2**i{extbit}}, buffer[WIDTH-1 : 2**i]};
+ else
+ buffer = {WIDTH{extbit}};
+ end
+ end
+
+ assign Y = buffer;
+endmodule
+
+
+// --------------------------------------------------------
+// Arithmetic operators
+// --------------------------------------------------------
+
+(* techmap_celltype = "$fa" *)
+module _90_fa (A, B, C, X, Y);
+ parameter WIDTH = 1;
+
+ input [WIDTH-1:0] A, B, C;
+ output [WIDTH-1:0] X, Y;
+
+ wire [WIDTH-1:0] t1, t2, t3;
+
+ assign t1 = A ^ B, t2 = A & B, t3 = C & t1;
+ assign Y = t1 ^ C, X = t2 | t3;
+endmodule
+
+(* techmap_celltype = "$lcu" *)
+module _90_lcu (P, G, CI, CO);
+ parameter WIDTH = 2;
+
+ input [WIDTH-1:0] P, G;
+ input CI;
+
+ output [WIDTH-1:0] CO;
+
+ integer i, j;
+ reg [WIDTH-1:0] p, g;
+
+ wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast";
+
+ always @* begin
+ p = P;
+ g = G;
+
+ // in almost all cases CI will be constant zero
+ g[0] = g[0] | (p[0] & CI);
+
+ // [[CITE]] Brent Kung Adder
+ // R. P. Brent and H. T. Kung, “A Regular Layout for Parallel Adders”,
+ // IEEE Transaction on Computers, Vol. C-31, No. 3, p. 260-264, March, 1982
+
+ // Main tree
+ for (i = 1; i <= $clog2(WIDTH); i = i+1) begin
+ for (j = 2**i - 1; j < WIDTH; j = j + 2**i) begin
+ g[j] = g[j] | p[j] & g[j - 2**(i-1)];
+ p[j] = p[j] & p[j - 2**(i-1)];
+ end
+ end
+
+ // Inverse tree
+ for (i = $clog2(WIDTH); i > 0; i = i-1) begin
+ for (j = 2**i + 2**(i-1) - 1; j < WIDTH; j = j + 2**i) begin
+ g[j] = g[j] | p[j] & g[j - 2**(i-1)];
+ p[j] = p[j] & p[j - 2**(i-1)];
+ end
+ end
+ end
+
+ assign CO = g;
+endmodule
+
+(* techmap_celltype = "$alu" *)
+module _90_alu (A, B, CI, BI, X, Y, CO);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] X, Y;
+
+ input CI, BI;
+ output [Y_WIDTH-1:0] CO;
+
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
+
+ \$lcu #(.WIDTH(Y_WIDTH)) lcu (.P(X), .G(AA & BB), .CI(CI), .CO(CO));
+
+ assign X = AA ^ BB;
+ assign Y = X ^ {CO, CI};
+endmodule
+
+(* techmap_maccmap *)
+(* techmap_celltype = "$macc" *)
+module _90_macc;
+endmodule
+
+(* techmap_wrap = "alumacc" *)
+(* techmap_celltype = "$lt $le $ge $gt $add $sub $neg $mul" *)
+module _90_alumacc;
+endmodule
+
+
+// --------------------------------------------------------
+// Divide and Modulo
+// --------------------------------------------------------
+
+module \$__div_mod_u (A, B, Y, R);
+ parameter WIDTH = 1;
+
+ input [WIDTH-1:0] A, B;
+ output [WIDTH-1:0] Y, R;
+
+ wire [WIDTH*WIDTH-1:0] chaindata;
+ assign R = chaindata[WIDTH*WIDTH-1:WIDTH*(WIDTH-1)];
+
+ genvar i;
+ generate begin
+ for (i = 0; i < WIDTH; i=i+1) begin:stage
+ wire [WIDTH-1:0] stage_in;
+
+ if (i == 0) begin:cp
+ assign stage_in = A;
+ end else begin:cp
+ assign stage_in = chaindata[i*WIDTH-1:(i-1)*WIDTH];
+ end
+
+ assign Y[WIDTH-(i+1)] = stage_in >= {B, {WIDTH-(i+1){1'b0}}};
+ assign chaindata[(i+1)*WIDTH-1:i*WIDTH] = Y[WIDTH-(i+1)] ? stage_in - {B, {WIDTH-(i+1){1'b0}}} : stage_in;
+ end
+ end endgenerate
+endmodule
+
+module \$__div_mod (A, B, Y, R);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ localparam WIDTH =
+ A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH :
+ B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y, R;
+
+ wire [WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ wire [WIDTH-1:0] A_buf_u, B_buf_u, Y_u, R_u;
+ assign A_buf_u = A_SIGNED && A_buf[WIDTH-1] ? -A_buf : A_buf;
+ assign B_buf_u = B_SIGNED && B_buf[WIDTH-1] ? -B_buf : B_buf;
+
+ \$__div_mod_u #(
+ .WIDTH(WIDTH)
+ ) div_mod_u (
+ .A(A_buf_u),
+ .B(B_buf_u),
+ .Y(Y_u),
+ .R(R_u)
+ );
+
+ assign Y = A_SIGNED && B_SIGNED && (A_buf[WIDTH-1] != B_buf[WIDTH-1]) ? -Y_u : Y_u;
+ assign R = A_SIGNED && B_SIGNED && A_buf[WIDTH-1] ? -R_u : R_u;
+endmodule
+
+(* techmap_celltype = "$div" *)
+module _90_div (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ \$__div_mod #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+ ) div_mod (
+ .A(A),
+ .B(B),
+ .Y(Y)
+ );
+endmodule
+
+(* techmap_celltype = "$mod" *)
+module _90_mod (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ \$__div_mod #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+ ) div_mod (
+ .A(A),
+ .B(B),
+ .R(Y)
+ );
+endmodule
+
+
+// --------------------------------------------------------
+// Power
+// --------------------------------------------------------
+
+(* techmap_celltype = "$pow" *)
+module _90_pow (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ wire _TECHMAP_FAIL_ = 1;
+endmodule
+
+
+// --------------------------------------------------------
+// Equal and Not-Equal
+// --------------------------------------------------------
+
+(* techmap_celltype = "$eq $eqx" *)
+module _90_eq_eqx (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ wire carry, carry_sign;
+ wire [WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ assign Y = ~|(A_buf ^ B_buf);
+endmodule
+
+(* techmap_celltype = "$ne $nex" *)
+module _90_ne_nex (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ wire carry, carry_sign;
+ wire [WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ assign Y = |(A_buf ^ B_buf);
+endmodule
+
+
+// --------------------------------------------------------
+// Parallel Multiplexers
+// --------------------------------------------------------
+
+(* techmap_celltype = "$pmux" *)
+module _90_pmux (A, B, S, Y);
+ parameter WIDTH = 1;
+ parameter S_WIDTH = 1;
+
+ input [WIDTH-1:0] A;
+ input [WIDTH*S_WIDTH-1:0] B;
+ input [S_WIDTH-1:0] S;
+ output [WIDTH-1:0] Y;
+
+ wire [WIDTH-1:0] Y_B;
+
+ genvar i, j;
+ generate
+ wire [WIDTH*S_WIDTH-1:0] B_AND_S;
+ for (i = 0; i < S_WIDTH; i = i + 1) begin:B_AND
+ assign B_AND_S[WIDTH*(i+1)-1:WIDTH*i] = B[WIDTH*(i+1)-1:WIDTH*i] & {WIDTH{S[i]}};
+ end:B_AND
+ for (i = 0; i < WIDTH; i = i + 1) begin:B_OR
+ wire [S_WIDTH-1:0] B_AND_BITS;
+ for (j = 0; j < S_WIDTH; j = j + 1) begin:B_AND_BITS_COLLECT
+ assign B_AND_BITS[j] = B_AND_S[WIDTH*j+i];
+ end:B_AND_BITS_COLLECT
+ assign Y_B[i] = |B_AND_BITS;
+ end:B_OR
+ endgenerate
+
+ assign Y = |S ? Y_B : A;
+endmodule
+
+
+// --------------------------------------------------------
+// LUTs
+// --------------------------------------------------------
+
+`ifndef NOLUT
+(* techmap_celltype = "$lut" *)
+module _90_lut (A, Y);
+ parameter WIDTH = 1;
+ parameter LUT = 0;
+
+ input [WIDTH-1:0] A;
+ output Y;
+
+ assign Y = LUT[A];
+endmodule
+`endif
+
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index f88390f7..cd19f10e 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -4,6 +4,6 @@ OBJS += techlibs/xilinx/synth_xilinx.o
EXTRA_TARGETS += share/xilinx/cells.v
share/xilinx/cells.v: techlibs/xilinx/cells.v
- mkdir -p share/xilinx
- cp techlibs/xilinx/cells.v share/xilinx/cells.v
+ $(P) mkdir -p share/xilinx
+ $(Q) cp techlibs/xilinx/cells.v share/xilinx/cells.v
diff --git a/techlibs/xilinx/cells.v b/techlibs/xilinx/cells.v
index 5bf8ccd8..d19be0db 100644
--- a/techlibs/xilinx/cells.v
+++ b/techlibs/xilinx/cells.v
@@ -10,41 +10,41 @@ module \$_DFF_P_ (D, C, Q);
endmodule
-module \$lut (I, O);
+module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
- input [WIDTH-1:0] I;
- output O;
+ input [WIDTH-1:0] A;
+ output Y;
generate
if (WIDTH == 1) begin:lut1
- LUT1 #(.INIT(LUT)) fpga_lut (.O(O),
- .I0(I[0]));
+ LUT1 #(.INIT(LUT)) fpga_lut (.O(Y),
+ .I0(A[0]));
end else
if (WIDTH == 2) begin:lut2
- LUT2 #(.INIT(LUT)) fpga_lut (.O(O),
- .I0(I[0]), .I1(I[1]));
+ LUT2 #(.INIT(LUT)) fpga_lut (.O(Y),
+ .I0(A[0]), .I1(A[1]));
end else
if (WIDTH == 3) begin:lut3
- LUT3 #(.INIT(LUT)) fpga_lut (.O(O),
- .I0(I[0]), .I1(I[1]), .I2(I[2]));
+ LUT3 #(.INIT(LUT)) fpga_lut (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]));
end else
if (WIDTH == 4) begin:lut4
- LUT4 #(.INIT(LUT)) fpga_lut (.O(O),
- .I0(I[0]), .I1(I[1]), .I2(I[2]),
- .I3(I[3]));
+ LUT4 #(.INIT(LUT)) fpga_lut (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]));
end else
if (WIDTH == 5) begin:lut5
- LUT5 #(.INIT(LUT)) fpga_lut (.O(O),
- .I0(I[0]), .I1(I[1]), .I2(I[2]),
- .I3(I[3]), .I4(I[4]));
+ LUT5 #(.INIT(LUT)) fpga_lut (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]), .I4(A[4]));
end else
if (WIDTH == 6) begin:lut6
- LUT6 #(.INIT(LUT)) fpga_lut (.O(O),
- .I0(I[0]), .I1(I[1]), .I2(I[2]),
- .I3(I[3]), .I4(I[4]), .I5(I[5]));
+ LUT6 #(.INIT(LUT)) fpga_lut (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]), .I4(A[4]), .I5(A[5]));
end else begin:error
wire _TECHMAP_FAIL_ = 1;
end
diff --git a/tests/asicworld/run-test.sh b/tests/asicworld/run-test.sh
index bf27d15f..24983f1a 100755
--- a/tests/asicworld/run-test.sh
+++ b/tests/asicworld/run-test.sh
@@ -1,3 +1,2 @@
#!/bin/bash
-make -C ../.. || exit 1
-exec bash ../tools/autotest.sh *.v
+exec ${MAKE:-make} -f ../tools/autotest.mk EXTRA_FLAGS="-e" *.v
diff --git a/tests/fsm/.gitignore b/tests/fsm/.gitignore
new file mode 100644
index 00000000..9c595a6f
--- /dev/null
+++ b/tests/fsm/.gitignore
@@ -0,0 +1 @@
+temp
diff --git a/tests/fsm/generate.py b/tests/fsm/generate.py
new file mode 100644
index 00000000..b5b4626d
--- /dev/null
+++ b/tests/fsm/generate.py
@@ -0,0 +1,109 @@
+#!/usr/bin/python
+
+from __future__ import division
+from __future__ import print_function
+
+import sys
+import random
+from contextlib import contextmanager
+
+# set to 'True' to compare verific with yosys
+test_verific = False
+
+@contextmanager
+def redirect_stdout(new_target):
+ old_target, sys.stdout = sys.stdout, new_target
+ try:
+ yield new_target
+ finally:
+ sys.stdout = old_target
+
+def random_expr(variables):
+ c = random.choice(['bin', 'uni', 'var', 'const'])
+ if c == 'bin':
+ op = random.choice(['+', '-', '*', '<', '<=', '==', '!=', '>=', '>', '<<', '>>', '<<<', '>>>', '|', '&', '^', '~^', '||', '&&'])
+ return "(%s %s %s)" % (random_expr(variables), op, random_expr(variables))
+ if c == 'uni':
+ op = random.choice(['+', '-', '~', '|', '&', '^', '~^', '!', '$signed', '$unsigned'])
+ return "%s(%s)" % (op, random_expr(variables))
+ if c == 'var':
+ return random.choice(variables)
+ if c == 'const':
+ bits = random.randint(1, 32)
+ return "%d'd%s" % (bits, random.randint(0, 2**bits-1))
+ raise AssertionError
+
+for idx in range(50):
+ with file('temp/uut_%05d.v' % idx, 'w') as f, redirect_stdout(f):
+ rst2 = random.choice([False, True])
+ if rst2:
+ print('module uut_%05d(clk, rst1, rst2, rst, a, b, c, x, y, z);' % (idx))
+ print(' input clk, rst1, rst2;')
+ print(' output rst;')
+ print(' assign rst = rst1 || rst2;')
+ else:
+ print('module uut_%05d(clk, rst, a, b, c, x, y, z);' % (idx))
+ print(' input clk, rst;')
+ variables=['a', 'b', 'c', 'x', 'y', 'z']
+ print(' input%s [%d:0] a;' % (random.choice(['', ' signed']), random.randint(0, 31)))
+ print(' input%s [%d:0] b;' % (random.choice(['', ' signed']), random.randint(0, 31)))
+ print(' input%s [%d:0] c;' % (random.choice(['', ' signed']), random.randint(0, 31)))
+ print(' output reg%s [%d:0] x;' % (random.choice(['', ' signed']), random.randint(0, 31)))
+ print(' output reg%s [%d:0] y;' % (random.choice(['', ' signed']), random.randint(0, 31)))
+ print(' output reg%s [%d:0] z;' % (random.choice(['', ' signed']), random.randint(0, 31)))
+ state_bits = random.randint(5, 16);
+ print(' %sreg [%d:0] state;' % (random.choice(['', '(* fsm_encoding = "one-hot" *)',
+ '(* fsm_encoding = "binary" *)']), state_bits-1))
+ states=[]
+ for i in range(random.randint(2, 10)):
+ n = random.randint(0, 2**state_bits-1)
+ if n not in states:
+ states.append(n)
+ print(' always @(posedge clk) begin')
+ print(' if (%s) begin' % ('rst1' if rst2 else 'rst'))
+ print(' x <= %d;' % random.randint(0, 2**31-1))
+ print(' y <= %d;' % random.randint(0, 2**31-1))
+ print(' z <= %d;' % random.randint(0, 2**31-1))
+ print(' state <= %d;' % random.choice(states))
+ print(' end else begin')
+ print(' case (state)')
+ for state in states:
+ print(' %d: begin' % state)
+ for var in ('x', 'y', 'z'):
+ print(' %s <= %s;' % (var, random_expr(variables)))
+ next_states = states[:]
+ for i in range(random.randint(0, len(states))):
+ next_state = random.choice(next_states)
+ next_states.remove(next_state)
+ print(' if ((%s) %s (%s)) state <= %s;' % (random_expr(variables),
+ random.choice(['<', '<=', '>=', '>']), random_expr(variables), next_state))
+ print(' end')
+ print(' endcase')
+ if rst2:
+ print(' if (rst2) begin')
+ print(' x <= a;')
+ print(' y <= b;')
+ print(' z <= c;')
+ print(' state <= %d;' % random.choice(states))
+ print(' end')
+ print(' end')
+ print(' end')
+ print('endmodule')
+ with file('temp/uut_%05d.ys' % idx, 'w') as f, redirect_stdout(f):
+ if test_verific:
+ print('read_verilog temp/uut_%05d.v' % idx)
+ print('proc;; rename uut_%05d gold' % idx)
+ print('verific -vlog2k temp/uut_%05d.v' % idx)
+ print('verific -import uut_%05d' % idx)
+ print('rename uut_%05d gate' % idx)
+ else:
+ print('read_verilog temp/uut_%05d.v' % idx)
+ print('proc;;')
+ print('copy uut_%05d gold' % idx)
+ print('rename uut_%05d gate' % idx)
+ print('cd gate')
+ print('opt; wreduce; share%s; opt; fsm;;' % random.choice(['', ' -aggressive']))
+ print('cd ..')
+ print('miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter')
+ print('sat -verify-no-timeout -timeout 20 -seq 5 -set-at 1 %s_rst 1 -prove trigger 0 -prove-skip 1 -show-inputs -show-outputs miter' % ('gold' if rst2 else 'in'))
+
diff --git a/tests/fsm/run-test.sh b/tests/fsm/run-test.sh
new file mode 100755
index 00000000..57c2a5b1
--- /dev/null
+++ b/tests/fsm/run-test.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+# run this test many times:
+# time bash -c 'for ((i=0; i<100; i++)); do echo "-- $i --"; bash run-test.sh || exit 1; done'
+
+set -e
+
+rm -rf temp
+mkdir -p temp
+echo "generating tests.."
+python generate.py
+
+{
+ all_targets="all_targets:"
+ echo "all: all_targets"
+ echo " @echo"
+ for i in $( ls temp/*.ys | sed 's,[^0-9],,g; s,^0*\(.\),\1,g;' ); do
+ idx=$( printf "%05d" $i )
+ echo "temp/uut_${idx}.log: temp/uut_${idx}.ys temp/uut_${idx}.v"
+ echo " @echo -n '[$i]'"
+ echo " @../../yosys -ql temp/uut_${idx}.out temp/uut_${idx}.ys"
+ echo " @mv temp/uut_${idx}.out temp/uut_${idx}.log"
+ echo " @grep -q 'SAT proof finished' temp/uut_${idx}.log && echo -n K || echo -n T"
+ all_targets="$all_targets temp/uut_${idx}.log"
+ done
+ echo "$all_targets"
+} > temp/makefile
+
+echo "running tests.."
+${MAKE:-make} -f temp/makefile
+
+exit 0
diff --git a/tests/hana/README b/tests/hana/README
index 37049405..b2a08fd4 100644
--- a/tests/hana/README
+++ b/tests/hana/README
@@ -2,13 +2,3 @@
This test cases are copied from the hana project:
https://sourceforge.net/projects/sim-sim/
-** Copy tests from hana: **
-while read fn; do cp -v $fn ALL_TESTS/${fn//\//_}; done < <(find test -name '*.v' ! -name '*_gold.v')
-
-** Eliminate test's we can't parse atm: **
-rm -f test_synthesizability*.v
-rm -f test_parse2synthtrans_latch_1_test.v
-rm -f test_parse2synthtrans_always_1_test.v
-rm -f test_parse2synthtrans_always_2_test.v
-for x in test_*.v; do ../../yosys -b "" $x || rm $x; done
-
diff --git a/tests/hana/run-test.sh b/tests/hana/run-test.sh
index b8e7231c..fb766eec 100755
--- a/tests/hana/run-test.sh
+++ b/tests/hana/run-test.sh
@@ -1,3 +1,2 @@
#!/bin/bash
-make -C ../.. || exit 1
-exec bash ../tools/autotest.sh -l hana_vlib.v test_*.v
+exec ${MAKE:-make} -f ../tools/autotest.mk EXTRA_FLAGS="-l hana_vlib.v -n 300 -e" test_*.v
diff --git a/tests/hana/test_intermout.v b/tests/hana/test_intermout.v
new file mode 100644
index 00000000..88b91ee4
--- /dev/null
+++ b/tests/hana/test_intermout.v
@@ -0,0 +1,418 @@
+
+// test_intermout_always_comb_1_test.v
+module f1_test(a, b, c, d, z);
+input a, b, c, d;
+output z;
+reg z, temp1, temp2;
+
+always @(a or b or c or d)
+begin
+ temp1 = a ^ b;
+ temp2 = c ^ d;
+ z = temp1 ^ temp2;
+end
+
+endmodule
+
+// test_intermout_always_comb_3_test.v
+module f2_test (in1, in2, out);
+input in1, in2;
+output reg out;
+
+always @ ( in1 or in2)
+ if(in1 > in2)
+ out = in1;
+ else
+ out = in2;
+endmodule
+
+// test_intermout_always_comb_4_test.v
+module f3_test(a, b, c);
+input b, c;
+output reg a;
+
+always @(b or c) begin
+a = b;
+a = c;
+end
+endmodule
+
+// test_intermout_always_comb_5_test.v
+module f4_test(ctrl, in1, in2, out);
+input ctrl;
+input in1, in2;
+output reg out;
+
+always @ (ctrl or in1 or in2)
+ if(ctrl)
+ out = in1 & in2;
+ else
+ out = in1 | in2;
+endmodule
+
+// test_intermout_always_ff_3_test.v
+module f5_NonBlockingEx(clk, merge, er, xmit, fddi, claim);
+input clk, merge, er, xmit, fddi;
+output reg claim;
+reg fcr;
+
+always @(posedge clk)
+begin
+ fcr = er | xmit;
+
+ if(merge)
+ claim = fcr & fddi;
+ else
+ claim = fddi;
+end
+endmodule
+
+// test_intermout_always_ff_4_test.v
+module f6_FlipFlop(clk, cs, ns);
+input clk;
+input [31:0] cs;
+output [31:0] ns;
+integer is;
+
+always @(posedge clk)
+ is <= cs;
+
+assign ns = is;
+endmodule
+
+// test_intermout_always_ff_5_test.v
+module f7_FlipFlop(clock, cs, ns);
+input clock;
+input [3:0] cs;
+output reg [3:0] ns;
+reg [3:0] temp;
+
+always @(posedge clock)
+begin
+ temp = cs;
+ ns = temp;
+end
+
+endmodule
+
+// test_intermout_always_ff_6_test.v
+module f8_inc(clock, counter);
+
+input clock;
+output reg [3:0] counter;
+always @(posedge clock)
+ counter <= counter + 1;
+endmodule
+
+// test_intermout_always_ff_8_test.v
+module f9_NegEdgeClock(q, d, clk, reset);
+input d, clk, reset;
+output reg q;
+
+always @(negedge clk or negedge reset)
+ if(!reset)
+ q <= 1'b0;
+ else
+ q <= d;
+
+endmodule
+
+// test_intermout_always_ff_9_test.v
+module f10_MyCounter (clock, preset, updown, presetdata, counter);
+input clock, preset, updown;
+input [1: 0] presetdata;
+output reg [1:0] counter;
+
+always @(posedge clock)
+ if(preset)
+ counter <= presetdata;
+ else
+ if(updown)
+ counter <= counter + 1;
+ else
+ counter <= counter - 1;
+endmodule
+
+// test_intermout_always_latch_1_test.v
+module f11_test(en, in, out);
+input en;
+input [1:0] in;
+output reg [2:0] out;
+
+always @ (en or in)
+ if(en)
+ out = in + 1;
+endmodule
+
+// test_intermout_bufrm_1_test.v
+module f12_test(input in, output out);
+//no buffer removal
+assign out = in;
+endmodule
+
+// test_intermout_bufrm_2_test.v
+module f13_test(input in, output out);
+//intermediate buffers should be removed
+wire w1, w2;
+assign w1 = in;
+assign w2 = w1;
+assign out = w2;
+endmodule
+
+// test_intermout_bufrm_6_test.v
+module f14_test(in, out);
+input in;
+output out;
+
+wire w1, w2, w3, w4;
+assign w1 = in;
+assign w2 = w1;
+assign w4 = w3;
+assign out = w4;
+f14_mybuf _f14_mybuf(w2, w3);
+endmodule
+
+module f14_mybuf(in, out);
+input in;
+output out;
+wire w1, w2, w3, w4;
+
+assign w1 = in;
+assign w2 = w1;
+assign out = w2;
+endmodule
+
+
+// test_intermout_bufrm_7_test.v
+module f15_test(in1, in2, out);
+input in1, in2;
+output out;
+// Y with cluster of f15_mybuf instances at the junction
+
+wire w1, w2, w3, w4, w5, w6, w7, w8, w9, w10;
+assign w1 = in1;
+assign w2 = w1;
+assign w5 = in2;
+assign w6 = w5;
+assign w10 = w9;
+assign out = w10;
+
+f15_mybuf _f15_mybuf0(w2, w3);
+f15_mybuf _f15_mybuf1(w3, w4);
+
+f15_mybuf _f15_mybuf2(w6, w7);
+f15_mybuf _f15_mybuf3(w7, w4);
+
+f15_mybuf _f15_mybuf4(w4, w8);
+f15_mybuf _f15_mybuf5(w8, w9);
+endmodule
+
+module f15_mybuf(in, out);
+input in;
+output out;
+wire w1, w2, w3, w4;
+
+assign w1 = in;
+assign w2 = w1;
+assign out = w2;
+endmodule
+
+
+// test_intermout_exprs_add_test.v
+module f16_test(out, in1, in2, vin1, vin2, vout1);
+output out;
+input in1, in2;
+input [1:0] vin1;
+input [2:0] vin2;
+output [3:0] vout1;
+
+assign out = in1 + in2;
+assign vout1 = vin1 + vin2;
+endmodule
+
+// test_intermout_exprs_binlogic_test.v
+module f17_test(in1, in2, vin1, vin2, out, vout, vin3, vin4, vout1 );
+input in1, in2;
+input [1:0] vin1;
+input [3:0] vin2;
+input [1:0] vin3;
+input [3:0] vin4;
+output vout, vout1;
+output out;
+
+assign out = in1 && in2;
+assign vout = vin1 && vin2;
+assign vout1 = vin3 || vin4;
+endmodule
+
+// test_intermout_exprs_bitwiseneg_test.v
+module f18_test(output out, input in, output [1:0] vout, input [1:0] vin);
+
+assign out = ~in;
+assign vout = ~vin;
+endmodule
+
+// test_intermout_exprs_buffer_test.v
+module f19_buffer(in, out, vin, vout);
+input in;
+output out;
+input [1:0] vin;
+output [1:0] vout;
+
+assign out = in;
+assign vout = vin;
+endmodule
+
+// test_intermout_exprs_condexpr_mux_test.v
+module f20_test(in1, in2, out, vin1, vin2, vin3, vin4, vout1, vout2, en1, ven1, ven2);
+input in1, in2, en1, ven1;
+input [1:0] ven2;
+output out;
+input [1:0] vin1, vin2, vin3, vin4;
+output [1:0] vout1, vout2;
+
+assign out = en1 ? in1 : in2;
+assign vout1 = ven1 ? vin1 : vin2;
+assign vout2 = ven2 ? vin3 : vin4;
+endmodule
+
+// test_intermout_exprs_condexpr_tribuf_test.v
+module f21_test(in, out, en, vin1, vout1, en1);
+input in, en, en1;
+output out;
+input [1:0] vin1;
+output [1:0] vout1;
+
+assign out = en ? in : 1'bz;
+assign vout1 = en1 ? vin1 : 2'bzz;
+endmodule
+
+// test_intermout_exprs_constshift_test.v
+module f22_test(in, out, vin, vout, vin1, vout1, vin2, vout2);
+
+input in;
+input [3:0] vin, vin1, vin2;
+output [3:0] vout, vout1, vout2;
+output out;
+
+assign out = in << 1;
+assign vout = vin << 2;
+assign vout1 = vin1 >> 2;
+assign vout2 = vin2 >>> 2;
+endmodule
+
+// test_intermout_exprs_const_test.v
+module f23_test (out, vout);
+output out;
+output [7:0] vout;
+
+assign out = 1'b1;
+assign vout = 9;
+endmodule
+
+// test_intermout_exprs_div_test.v
+module f24_test(out, in1, in2, vin1, vin2, vout1);
+output out;
+input in1, in2;
+input [1:0] vin1;
+input [2:0] vin2;
+output [3:0] vout1;
+
+assign out = in1 / in2;
+assign vout1 = vin1 / vin2;
+endmodule
+
+// test_intermout_exprs_logicneg_test.v
+module f25_test(out, vout, in, vin);
+output out, vout;
+input in;
+input [3:0] vin;
+assign out = !in;
+assign vout = !vin;
+endmodule
+
+// test_intermout_exprs_mod_test.v
+module f26_test(out, in1, in2, vin1, vin2, vout1);
+output out;
+input in1, in2;
+input [1:0] vin1;
+input [2:0] vin2;
+output [3:0] vout1;
+
+assign out = in1 % in2;
+assign vout1 = vin1 % vin2;
+endmodule
+
+// test_intermout_exprs_mul_test.v
+module f27_test(out, in1, in2, vin1, vin2, vout1);
+output out;
+input in1, in2;
+input [1:0] vin1;
+input [2:0] vin2;
+output [3:0] vout1;
+
+assign out = in1 * in2;
+assign vout1 = vin1 * vin2;
+endmodule
+
+// test_intermout_exprs_redand_test.v
+module f28_test(output out, input [1:0] vin, output out1, input [3:0] vin1);
+
+assign out = &vin;
+assign out1 = &vin1;
+endmodule
+
+// test_intermout_exprs_redop_test.v
+module f29_Reduction (A1, A2, A3, A4, A5, A6, Y1, Y2, Y3, Y4, Y5, Y6);
+input [1:0] A1;
+input [1:0] A2;
+input [1:0] A3;
+input [1:0] A4;
+input [1:0] A5;
+input [1:0] A6;
+output Y1, Y2, Y3, Y4, Y5, Y6;
+//reg Y1, Y2, Y3, Y4, Y5, Y6;
+assign Y1=&A1; //reduction AND
+assign Y2=|A2; //reduction OR
+assign Y3=~&A3; //reduction NAND
+assign Y4=~|A4; //reduction NOR
+assign Y5=^A5; //reduction XOR
+assign Y6=~^A6; //reduction XNOR
+endmodule
+
+// test_intermout_exprs_sub_test.v
+module f30_test(out, in1, in2, vin1, vin2, vout1);
+output out;
+input in1, in2;
+input [1:0] vin1;
+input [2:0] vin2;
+output [3:0] vout1;
+
+assign out = in1 - in2;
+assign vout1 = vin1 - vin2;
+endmodule
+
+// test_intermout_exprs_unaryminus_test.v
+module f31_test(output out, input in, output [31:0] vout, input [31:0] vin);
+
+assign out = -in;
+assign vout = -vin;
+endmodule
+
+// test_intermout_exprs_unaryplus_test.v
+module f32_test(output out, input in);
+
+assign out = +in;
+endmodule
+
+// test_intermout_exprs_varshift_test.v
+module f33_test(vin0, vout0);
+input [2:0] vin0;
+output reg [7:0] vout0;
+
+wire [7:0] myreg0, myreg1, myreg2;
+integer i;
+assign myreg0 = vout0 << vin0;
+
+assign myreg1 = myreg2 >> i;
+endmodule
diff --git a/tests/hana/test_intermout_always_comb_1_test.v b/tests/hana/test_intermout_always_comb_1_test.v
deleted file mode 100644
index 2d5abc4a..00000000
--- a/tests/hana/test_intermout_always_comb_1_test.v
+++ /dev/null
@@ -1,13 +0,0 @@
-module test(a, b, c, d, z);
-input a, b, c, d;
-output z;
-reg z, temp1, temp2;
-
-always @(a or b or c or d)
-begin
- temp1 = a ^ b;
- temp2 = c ^ d;
- z = temp1 ^ temp2;
-end
-
-endmodule
diff --git a/tests/hana/test_intermout_always_comb_3_test.v b/tests/hana/test_intermout_always_comb_3_test.v
deleted file mode 100644
index 234407ef..00000000
--- a/tests/hana/test_intermout_always_comb_3_test.v
+++ /dev/null
@@ -1,10 +0,0 @@
-module test (in1, in2, out);
-input in1, in2;
-output reg out;
-
-always @ ( in1 or in2)
- if(in1 > in2)
- out = in1;
- else
- out = in2;
-endmodule
diff --git a/tests/hana/test_intermout_always_comb_4_test.v b/tests/hana/test_intermout_always_comb_4_test.v
deleted file mode 100644
index b0a94f29..00000000
--- a/tests/hana/test_intermout_always_comb_4_test.v
+++ /dev/null
@@ -1,9 +0,0 @@
-module test(a, b, c);
-input b, c;
-output reg a;
-
-always @(b or c) begin
-a = b;
-a = c;
-end
-endmodule
diff --git a/tests/hana/test_intermout_always_comb_5_test.v b/tests/hana/test_intermout_always_comb_5_test.v
deleted file mode 100644
index 5152781d..00000000
--- a/tests/hana/test_intermout_always_comb_5_test.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module test(ctrl, in1, in2, out);
-input ctrl;
-input in1, in2;
-output reg out;
-
-always @ (ctrl or in1 or in2)
- if(ctrl)
- out = in1 & in2;
- else
- out = in1 | in2;
-endmodule
diff --git a/tests/hana/test_intermout_always_ff_3_test.v b/tests/hana/test_intermout_always_ff_3_test.v
deleted file mode 100644
index ed8630c3..00000000
--- a/tests/hana/test_intermout_always_ff_3_test.v
+++ /dev/null
@@ -1,15 +0,0 @@
-module NonBlockingEx(clk, merge, er, xmit, fddi, claim);
-input clk, merge, er, xmit, fddi;
-output reg claim;
-reg fcr;
-
-always @(posedge clk)
-begin
- fcr = er | xmit;
-
- if(merge)
- claim = fcr & fddi;
- else
- claim = fddi;
-end
-endmodule
diff --git a/tests/hana/test_intermout_always_ff_4_test.v b/tests/hana/test_intermout_always_ff_4_test.v
deleted file mode 100644
index cac420a4..00000000
--- a/tests/hana/test_intermout_always_ff_4_test.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module FlipFlop(clk, cs, ns);
-input clk;
-input [31:0] cs;
-output [31:0] ns;
-integer is;
-
-always @(posedge clk)
- is <= cs;
-
-assign ns = is;
-endmodule
diff --git a/tests/hana/test_intermout_always_ff_5_test.v b/tests/hana/test_intermout_always_ff_5_test.v
deleted file mode 100644
index 669b2a5f..00000000
--- a/tests/hana/test_intermout_always_ff_5_test.v
+++ /dev/null
@@ -1,13 +0,0 @@
-module FlipFlop(clock, cs, ns);
-input clock;
-input [3:0] cs;
-output reg [3:0] ns;
-reg [3:0] temp;
-
-always @(posedge clock)
-begin
- temp = cs;
- ns = temp;
-end
-
-endmodule
diff --git a/tests/hana/test_intermout_always_ff_6_test.v b/tests/hana/test_intermout_always_ff_6_test.v
deleted file mode 100644
index ad0a0df6..00000000
--- a/tests/hana/test_intermout_always_ff_6_test.v
+++ /dev/null
@@ -1,7 +0,0 @@
-module inc(clock, counter);
-
-input clock;
-output reg [3:0] counter;
-always @(posedge clock)
- counter <= counter + 1;
-endmodule
diff --git a/tests/hana/test_intermout_always_ff_8_test.v b/tests/hana/test_intermout_always_ff_8_test.v
deleted file mode 100644
index 0f29ea0a..00000000
--- a/tests/hana/test_intermout_always_ff_8_test.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module NegEdgeClock(q, d, clk, reset);
-input d, clk, reset;
-output reg q;
-
-always @(negedge clk or negedge reset)
- if(!reset)
- q <= 1'b0;
- else
- q <= d;
-
-endmodule
diff --git a/tests/hana/test_intermout_always_ff_9_test.v b/tests/hana/test_intermout_always_ff_9_test.v
deleted file mode 100644
index f1f13bbe..00000000
--- a/tests/hana/test_intermout_always_ff_9_test.v
+++ /dev/null
@@ -1,14 +0,0 @@
-module MyCounter (clock, preset, updown, presetdata, counter);
-input clock, preset, updown;
-input [1: 0] presetdata;
-output reg [1:0] counter;
-
-always @(posedge clock)
- if(preset)
- counter <= presetdata;
- else
- if(updown)
- counter <= counter + 1;
- else
- counter <= counter - 1;
-endmodule
diff --git a/tests/hana/test_intermout_always_latch_1_test.v b/tests/hana/test_intermout_always_latch_1_test.v
deleted file mode 100644
index a83be20d..00000000
--- a/tests/hana/test_intermout_always_latch_1_test.v
+++ /dev/null
@@ -1,9 +0,0 @@
-module test(en, in, out);
-input en;
-input [1:0] in;
-output reg [2:0] out;
-
-always @ (en or in)
- if(en)
- out = in + 1;
-endmodule
diff --git a/tests/hana/test_intermout_bufrm_1_test.v b/tests/hana/test_intermout_bufrm_1_test.v
deleted file mode 100644
index 8e3d4222..00000000
--- a/tests/hana/test_intermout_bufrm_1_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input in, output out);
-//no buffer removal
-assign out = in;
-endmodule
diff --git a/tests/hana/test_intermout_bufrm_2_test.v b/tests/hana/test_intermout_bufrm_2_test.v
deleted file mode 100644
index 853f1dc9..00000000
--- a/tests/hana/test_intermout_bufrm_2_test.v
+++ /dev/null
@@ -1,7 +0,0 @@
-module test(input in, output out);
-//intermediate buffers should be removed
-wire w1, w2;
-assign w1 = in;
-assign w2 = w1;
-assign out = w2;
-endmodule
diff --git a/tests/hana/test_intermout_bufrm_6_test.v b/tests/hana/test_intermout_bufrm_6_test.v
deleted file mode 100644
index d4f3878d..00000000
--- a/tests/hana/test_intermout_bufrm_6_test.v
+++ /dev/null
@@ -1,22 +0,0 @@
-module test(in, out);
-input in;
-output out;
-
-wire w1, w2, w3, w4;
-assign w1 = in;
-assign w2 = w1;
-assign w4 = w3;
-assign out = w4;
-mybuf _mybuf(w2, w3);
-endmodule
-
-module mybuf(in, out);
-input in;
-output out;
-wire w1, w2, w3, w4;
-
-assign w1 = in;
-assign w2 = w1;
-assign out = w2;
-endmodule
-
diff --git a/tests/hana/test_intermout_bufrm_7_test.v b/tests/hana/test_intermout_bufrm_7_test.v
deleted file mode 100644
index 7b651302..00000000
--- a/tests/hana/test_intermout_bufrm_7_test.v
+++ /dev/null
@@ -1,33 +0,0 @@
-module test(in1, in2, out);
-input in1, in2;
-output out;
-// Y with cluster of mybuf instances at the junction
-
-wire w1, w2, w3, w4, w5, w6, w7, w8, w9, w10;
-assign w1 = in1;
-assign w2 = w1;
-assign w5 = in2;
-assign w6 = w5;
-assign w10 = w9;
-assign out = w10;
-
-mybuf _mybuf0(w2, w3);
-mybuf _mybuf1(w3, w4);
-
-mybuf _mybuf2(w6, w7);
-mybuf _mybuf3(w7, w4);
-
-mybuf _mybuf4(w4, w8);
-mybuf _mybuf5(w8, w9);
-endmodule
-
-module mybuf(in, out);
-input in;
-output out;
-wire w1, w2, w3, w4;
-
-assign w1 = in;
-assign w2 = w1;
-assign out = w2;
-endmodule
-
diff --git a/tests/hana/test_intermout_exprs_add_test.v b/tests/hana/test_intermout_exprs_add_test.v
deleted file mode 100644
index ec70f347..00000000
--- a/tests/hana/test_intermout_exprs_add_test.v
+++ /dev/null
@@ -1,10 +0,0 @@
-module test(out, in1, in2, vin1, vin2, vout1);
-output out;
-input in1, in2;
-input [1:0] vin1;
-input [2:0] vin2;
-output [3:0] vout1;
-
-assign out = in1 + in2;
-assign vout1 = vin1 + vin2;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_binlogic_test.v b/tests/hana/test_intermout_exprs_binlogic_test.v
deleted file mode 100644
index eec8c4b1..00000000
--- a/tests/hana/test_intermout_exprs_binlogic_test.v
+++ /dev/null
@@ -1,13 +0,0 @@
-module test(in1, in2, vin1, vin2, out, vout, vin3, vin4, vout1 );
-input in1, in2;
-input [1:0] vin1;
-input [3:0] vin2;
-input [1:0] vin3;
-input [3:0] vin4;
-output vout, vout1;
-output out;
-
-assign out = in1 && in2;
-assign vout = vin1 && vin2;
-assign vout1 = vin3 || vin4;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_bitwiseneg_test.v b/tests/hana/test_intermout_exprs_bitwiseneg_test.v
deleted file mode 100644
index 5b62bef0..00000000
--- a/tests/hana/test_intermout_exprs_bitwiseneg_test.v
+++ /dev/null
@@ -1,5 +0,0 @@
-module test(output out, input in, output [1:0] vout, input [1:0] vin);
-
-assign out = ~in;
-assign vout = ~vin;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_buffer_test.v b/tests/hana/test_intermout_exprs_buffer_test.v
deleted file mode 100644
index 2b4cbc3e..00000000
--- a/tests/hana/test_intermout_exprs_buffer_test.v
+++ /dev/null
@@ -1,9 +0,0 @@
-module buffer(in, out, vin, vout);
-input in;
-output out;
-input [1:0] vin;
-output [1:0] vout;
-
-assign out = in;
-assign vout = vin;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_condexpr_mux_test.v b/tests/hana/test_intermout_exprs_condexpr_mux_test.v
deleted file mode 100644
index 11006e8b..00000000
--- a/tests/hana/test_intermout_exprs_condexpr_mux_test.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module test(in1, in2, out, vin1, vin2, vin3, vin4, vout1, vout2, en1, ven1, ven2);
-input in1, in2, en1, ven1;
-input [1:0] ven2;
-output out;
-input [1:0] vin1, vin2, vin3, vin4;
-output [1:0] vout1, vout2;
-
-assign out = en1 ? in1 : in2;
-assign vout1 = ven1 ? vin1 : vin2;
-assign vout2 = ven2 ? vin3 : vin4;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_condexpr_tribuf_test.v b/tests/hana/test_intermout_exprs_condexpr_tribuf_test.v
deleted file mode 100644
index 5b778fe9..00000000
--- a/tests/hana/test_intermout_exprs_condexpr_tribuf_test.v
+++ /dev/null
@@ -1,9 +0,0 @@
-module test(in, out, en, vin1, vout1, en1);
-input in, en, en1;
-output out;
-input [1:0] vin1;
-output [1:0] vout1;
-
-assign out = en ? in : 1'bz;
-assign vout1 = en1 ? vin1 : 2'bzz;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_const_test.v b/tests/hana/test_intermout_exprs_const_test.v
deleted file mode 100644
index 484d8103..00000000
--- a/tests/hana/test_intermout_exprs_const_test.v
+++ /dev/null
@@ -1,7 +0,0 @@
-module test (out, vout);
-output out;
-output [7:0] vout;
-
-assign out = 1'b1;
-assign vout = 9;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_constshift_test.v b/tests/hana/test_intermout_exprs_constshift_test.v
deleted file mode 100644
index eb21315d..00000000
--- a/tests/hana/test_intermout_exprs_constshift_test.v
+++ /dev/null
@@ -1,12 +0,0 @@
-module test(in, out, vin, vout, vin1, vout1, vin2, vout2);
-
-input in;
-input [3:0] vin, vin1, vin2;
-output [3:0] vout, vout1, vout2;
-output out;
-
-assign out = in << 1;
-assign vout = vin << 2;
-assign vout1 = vin1 >> 2;
-assign vout2 = vin2 >>> 2;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_div_test.v b/tests/hana/test_intermout_exprs_div_test.v
deleted file mode 100644
index 21765fcd..00000000
--- a/tests/hana/test_intermout_exprs_div_test.v
+++ /dev/null
@@ -1,10 +0,0 @@
-module test(out, in1, in2, vin1, vin2, vout1);
-output out;
-input in1, in2;
-input [1:0] vin1;
-input [2:0] vin2;
-output [3:0] vout1;
-
-assign out = in1 / in2;
-assign vout1 = vin1 / vin2;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_logicneg_test.v b/tests/hana/test_intermout_exprs_logicneg_test.v
deleted file mode 100644
index b45b32b9..00000000
--- a/tests/hana/test_intermout_exprs_logicneg_test.v
+++ /dev/null
@@ -1,7 +0,0 @@
-module test(out, vout, in, vin);
-output out, vout;
-input in;
-input [3:0] vin;
-assign out = !in;
-assign vout = !vin;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_mod_test.v b/tests/hana/test_intermout_exprs_mod_test.v
deleted file mode 100644
index cea6b02d..00000000
--- a/tests/hana/test_intermout_exprs_mod_test.v
+++ /dev/null
@@ -1,10 +0,0 @@
-module test(out, in1, in2, vin1, vin2, vout1);
-output out;
-input in1, in2;
-input [1:0] vin1;
-input [2:0] vin2;
-output [3:0] vout1;
-
-assign out = in1 % in2;
-assign vout1 = vin1 % vin2;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_mul_test.v b/tests/hana/test_intermout_exprs_mul_test.v
deleted file mode 100644
index f9973dad..00000000
--- a/tests/hana/test_intermout_exprs_mul_test.v
+++ /dev/null
@@ -1,10 +0,0 @@
-module test(out, in1, in2, vin1, vin2, vout1);
-output out;
-input in1, in2;
-input [1:0] vin1;
-input [2:0] vin2;
-output [3:0] vout1;
-
-assign out = in1 * in2;
-assign vout1 = vin1 * vin2;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_redand_test.v b/tests/hana/test_intermout_exprs_redand_test.v
deleted file mode 100644
index 35fdf73a..00000000
--- a/tests/hana/test_intermout_exprs_redand_test.v
+++ /dev/null
@@ -1,5 +0,0 @@
-module test(output out, input [1:0] vin, output out1, input [3:0] vin1);
-
-assign out = &vin;
-assign out1 = &vin1;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_redop_test.v b/tests/hana/test_intermout_exprs_redop_test.v
deleted file mode 100644
index 93fdb2e5..00000000
--- a/tests/hana/test_intermout_exprs_redop_test.v
+++ /dev/null
@@ -1,16 +0,0 @@
-module Reduction (A1, A2, A3, A4, A5, A6, Y1, Y2, Y3, Y4, Y5, Y6);
-input [1:0] A1;
-input [1:0] A2;
-input [1:0] A3;
-input [1:0] A4;
-input [1:0] A5;
-input [1:0] A6;
-output Y1, Y2, Y3, Y4, Y5, Y6;
-//reg Y1, Y2, Y3, Y4, Y5, Y6;
-assign Y1=&A1; //reduction AND
-assign Y2=|A2; //reduction OR
-assign Y3=~&A3; //reduction NAND
-assign Y4=~|A4; //reduction NOR
-assign Y5=^A5; //reduction XOR
-assign Y6=~^A6; //reduction XNOR
-endmodule
diff --git a/tests/hana/test_intermout_exprs_sub_test.v b/tests/hana/test_intermout_exprs_sub_test.v
deleted file mode 100644
index 06e3a814..00000000
--- a/tests/hana/test_intermout_exprs_sub_test.v
+++ /dev/null
@@ -1,10 +0,0 @@
-module test(out, in1, in2, vin1, vin2, vout1);
-output out;
-input in1, in2;
-input [1:0] vin1;
-input [2:0] vin2;
-output [3:0] vout1;
-
-assign out = in1 - in2;
-assign vout1 = vin1 - vin2;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_unaryminus_test.v b/tests/hana/test_intermout_exprs_unaryminus_test.v
deleted file mode 100644
index ee3f229a..00000000
--- a/tests/hana/test_intermout_exprs_unaryminus_test.v
+++ /dev/null
@@ -1,5 +0,0 @@
-module test(output out, input in, output [31:0] vout, input [31:0] vin);
-
-assign out = -in;
-assign vout = -vin;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_unaryplus_test.v b/tests/hana/test_intermout_exprs_unaryplus_test.v
deleted file mode 100644
index 07be5b24..00000000
--- a/tests/hana/test_intermout_exprs_unaryplus_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(output out, input in);
-
-assign out = +in;
-endmodule
diff --git a/tests/hana/test_intermout_exprs_varshift_test.v b/tests/hana/test_intermout_exprs_varshift_test.v
deleted file mode 100644
index 2ca35c09..00000000
--- a/tests/hana/test_intermout_exprs_varshift_test.v
+++ /dev/null
@@ -1,10 +0,0 @@
-module test(vin0, vout0);
-input [2:0] vin0;
-output reg [7:0] vout0;
-
-wire [7:0] myreg0, myreg1, myreg2;
-integer i;
-assign myreg0 = vout0 << vin0;
-
-assign myreg1 = myreg2 >> i;
-endmodule
diff --git a/tests/hana/test_parse2synthtrans.v b/tests/hana/test_parse2synthtrans.v
new file mode 100644
index 00000000..a1c0bfdb
--- /dev/null
+++ b/tests/hana/test_parse2synthtrans.v
@@ -0,0 +1,117 @@
+
+// test_parse2synthtrans_behavopt_1_test.v
+module f1_test(in, out, clk, reset);
+input in, reset;
+output reg out;
+input clk;
+reg signed [3:0] a;
+reg signed [3:0] b;
+reg signed [3:0] c;
+reg [5:0] d;
+reg [5:0] e;
+
+always @(clk or reset) begin
+ a = -4;
+ b = 2;
+ c = a + b;
+ d = a + b + c;
+ d = d*d;
+ if(b)
+ e = d*d;
+ else
+ e = d + d;
+end
+endmodule
+
+// test_parse2synthtrans_case_1_test.v
+module f2_demultiplexer1_to_4 (out0, out1, out2, out3, in, s1, s0);
+output out0, out1, out2, out3;
+reg out0, out1, out2, out3;
+input in;
+input s1, s0;
+reg [3:0] encoding;
+reg [1:0] state;
+ always @(encoding) begin
+ case (encoding)
+ 4'bxx11: state = 1;
+ 4'bx0xx: state = 3;
+ 4'b11xx: state = 4;
+ 4'bx1xx: state = 2;
+ 4'bxx1x: state = 1;
+ 4'bxxx1: state = 0;
+ default: state = 0;
+ endcase
+ end
+
+ always @(encoding) begin
+ case (encoding)
+ 4'b0000: state = 1;
+ default: state = 0;
+ endcase
+ end
+endmodule
+
+// test_parse2synthtrans_contassign_1_test.v
+module f3_test(in, out);
+
+input wire in;
+output out;
+assign out = (in+in);
+assign out = 74;
+endmodule
+
+// test_parse2synthtrans_module_basic0_test.v
+module f4_test;
+endmodule
+
+// test_parse2synthtrans_operators_1_test.v
+module f5_test(in, out);
+input in;
+output out;
+parameter p1 = 10;
+parameter p2 = 5;
+
+assign out = +p1;
+assign out = -p2;
+assign out = p1 + p2;
+assign out = p1 - p2;
+endmodule
+
+// test_parse2synthtrans_param_1_test.v
+module f6_test(in, out);
+input in;
+output out;
+parameter p = 10;
+
+assign out = p;
+endmodule
+
+// test_parse2synthtrans_port_scalar_1_test.v
+module f7_test(in, out, io);
+inout io;
+output out;
+input in;
+
+endmodule
+
+// test_parse2synthtrans_port_vector_1_test.v
+module f8_test(in1, in2, out1, out2, io1, io2);
+inout [1:0] io1;
+inout [0:1] io2;
+output [1:0] out1;
+output [0:1] out2;
+input [1:0] in1;
+input [0:1] in2;
+
+endmodule
+
+// test_parse2synthtrans_v2k_comb_logic_sens_list_test.v
+module f9_test(q, d, clk, reset);
+output reg q;
+input d, clk, reset;
+
+always @ (posedge clk, negedge reset)
+ if(!reset) q <= 0;
+ else q <= d;
+
+endmodule
diff --git a/tests/hana/test_parse2synthtrans_behavopt_1_test.v b/tests/hana/test_parse2synthtrans_behavopt_1_test.v
deleted file mode 100644
index c825739c..00000000
--- a/tests/hana/test_parse2synthtrans_behavopt_1_test.v
+++ /dev/null
@@ -1,22 +0,0 @@
-module test(in, out, clk, reset);
-input in, reset;
-output reg out;
-input clk;
-reg signed [3:0] a;
-reg signed [3:0] b;
-reg signed [3:0] c;
-reg [5:0] d;
-reg [5:0] e;
-
-always @(clk or reset) begin
- a = -4;
- b = 2;
- c = a + b;
- d = a + b + c;
- d = d*d;
- if(b)
- e = d*d;
- else
- e = d + d;
-end
-endmodule
diff --git a/tests/hana/test_parse2synthtrans_case_1_test.v b/tests/hana/test_parse2synthtrans_case_1_test.v
deleted file mode 100644
index 348c566a..00000000
--- a/tests/hana/test_parse2synthtrans_case_1_test.v
+++ /dev/null
@@ -1,26 +0,0 @@
-module demultiplexer1_to_4 (out0, out1, out2, out3, in, s1, s0);
-output out0, out1, out2, out3;
-reg out0, out1, out2, out3;
-input in;
-input s1, s0;
-reg [3:0] encoding;
-reg [1:0] state;
- always @(encoding) begin
- case (encoding)
- 4'bxx11: state = 1;
- 4'bx0xx: state = 3;
- 4'b11xx: state = 4;
- 4'bx1xx: state = 2;
- 4'bxx1x: state = 1;
- 4'bxxx1: state = 0;
- default: state = 0;
- endcase
- end
-
- always @(encoding) begin
- case (encoding)
- 4'b0000: state = 1;
- default: state = 0;
- endcase
- end
-endmodule
diff --git a/tests/hana/test_parse2synthtrans_contassign_1_test.v b/tests/hana/test_parse2synthtrans_contassign_1_test.v
deleted file mode 100644
index 78bf0077..00000000
--- a/tests/hana/test_parse2synthtrans_contassign_1_test.v
+++ /dev/null
@@ -1,7 +0,0 @@
-module test(in, out);
-
-input wire in;
-output out;
-assign out = (in+in);
-assign out = 74;
-endmodule
diff --git a/tests/hana/test_parse2synthtrans_module_basic0_test.v b/tests/hana/test_parse2synthtrans_module_basic0_test.v
deleted file mode 100644
index 67a272df..00000000
--- a/tests/hana/test_parse2synthtrans_module_basic0_test.v
+++ /dev/null
@@ -1,2 +0,0 @@
-module test;
-endmodule
diff --git a/tests/hana/test_parse2synthtrans_operators_1_test.v b/tests/hana/test_parse2synthtrans_operators_1_test.v
deleted file mode 100644
index 93b5691f..00000000
--- a/tests/hana/test_parse2synthtrans_operators_1_test.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module test(in, out);
-input in;
-output out;
-parameter p1 = 10;
-parameter p2 = 5;
-
-assign out = +p1;
-assign out = -p2;
-assign out = p1 + p2;
-assign out = p1 - p2;
-endmodule
diff --git a/tests/hana/test_parse2synthtrans_param_1_test.v b/tests/hana/test_parse2synthtrans_param_1_test.v
deleted file mode 100644
index 146eedf4..00000000
--- a/tests/hana/test_parse2synthtrans_param_1_test.v
+++ /dev/null
@@ -1,7 +0,0 @@
-module test(in, out);
-input in;
-output out;
-parameter p = 10;
-
-assign out = p;
-endmodule
diff --git a/tests/hana/test_parse2synthtrans_port_scalar_1_test.v b/tests/hana/test_parse2synthtrans_port_scalar_1_test.v
deleted file mode 100644
index 8cdf495a..00000000
--- a/tests/hana/test_parse2synthtrans_port_scalar_1_test.v
+++ /dev/null
@@ -1,6 +0,0 @@
-module test(in, out, io);
-inout io;
-output out;
-input in;
-
-endmodule
diff --git a/tests/hana/test_parse2synthtrans_port_vector_1_test.v b/tests/hana/test_parse2synthtrans_port_vector_1_test.v
deleted file mode 100644
index a740282b..00000000
--- a/tests/hana/test_parse2synthtrans_port_vector_1_test.v
+++ /dev/null
@@ -1,9 +0,0 @@
-module test(in1, in2, out1, out2, io1, io2);
-inout [1:0] io1;
-inout [0:1] io2;
-output [1:0] out1;
-output [0:1] out2;
-input [1:0] in1;
-input [0:1] in2;
-
-endmodule
diff --git a/tests/hana/test_parse2synthtrans_v2k_comb_logic_sens_list_test.v b/tests/hana/test_parse2synthtrans_v2k_comb_logic_sens_list_test.v
deleted file mode 100644
index 50f1d353..00000000
--- a/tests/hana/test_parse2synthtrans_v2k_comb_logic_sens_list_test.v
+++ /dev/null
@@ -1,9 +0,0 @@
-module test(q, d, clk, reset);
-output reg q;
-input d, clk, reset;
-
-always @ (posedge clk, negedge reset)
- if(!reset) q <= 0;
- else q <= d;
-
-endmodule
diff --git a/tests/hana/test_parser.v b/tests/hana/test_parser.v
new file mode 100644
index 00000000..c7305356
--- /dev/null
+++ b/tests/hana/test_parser.v
@@ -0,0 +1,87 @@
+
+// test_parser_constructs_module_basic1_test.v
+module f1_test;
+endmodule
+
+// test_parser_constructs_param_basic0_test.v
+module f2_test #( parameter v2kparam = 5)
+(in, out, io, vin, vout, vio);
+input in;
+output out;
+inout io;
+input [3:0] vin;
+output [v2kparam:0] vout;
+inout [0:3] vio;
+parameter myparam = 10;
+endmodule
+
+// test_parser_constructs_port_basic0_test.v
+module f3_test(in, out, io, vin, vout, vio);
+input in;
+output out;
+inout io;
+input [3:0] vin;
+output [3:0] vout;
+inout [0:3] vio;
+endmodule
+
+// test_parser_directives_define_simpledef_test.v
+`define parvez ahmad
+`define WIRE wire
+`define TEN 10
+
+module f4_`parvez();
+parameter param = `TEN;
+`WIRE w;
+assign w = `TEN;
+endmodule
+
+// test_parser_misc_operators_test.v
+module f5_test(out, i0, i1, i2, i3, s1, s0);
+output out;
+input i0, i1, i2, i3;
+input s1, s0;
+
+assign out = (~s1 & s0 & i0) |
+ (~s1 & s0 & i1) |
+ (s1 & ~s0 & i2) |
+ (s1 & s0 & i3);
+
+endmodule
+
+module f5_ternaryop(out, i0, i1, i2, i3, s1, s0);
+output out;
+input i0, i1, i2, i3;
+input s1, s0;
+
+assign out = s1 ? (s0 ? i3 : i2) : (s0 ? i1 : i0);
+
+endmodule
+
+module f5_fulladd4(sum, c_out, a, b, c_in);
+output [3:0] sum;
+output c_out;
+input [3:0] a, b;
+input c_in;
+
+assign {c_out, sum} = a + b + c_in;
+endmodule
+
+// test_parser_v2k_comb_port_data_type_test.v
+module f6_adder(sum , co, a, b, ci);
+output reg [31:0] sum;
+output reg co;
+input wire [31:0] a, b;
+input wire ci;
+endmodule
+
+// test_parser_v2k_comma_sep_sens_list_test.v
+module f7_test(q, d, clk, reset);
+output reg q;
+input d, clk, reset;
+
+always @ (posedge clk, negedge reset)
+ if(!reset) q <= 0;
+ else q <= d;
+
+endmodule
diff --git a/tests/hana/test_parser_constructs_module_basic1_test.v b/tests/hana/test_parser_constructs_module_basic1_test.v
deleted file mode 100644
index 67a272df..00000000
--- a/tests/hana/test_parser_constructs_module_basic1_test.v
+++ /dev/null
@@ -1,2 +0,0 @@
-module test;
-endmodule
diff --git a/tests/hana/test_parser_constructs_param_basic0_test.v b/tests/hana/test_parser_constructs_param_basic0_test.v
deleted file mode 100644
index fd679230..00000000
--- a/tests/hana/test_parser_constructs_param_basic0_test.v
+++ /dev/null
@@ -1,10 +0,0 @@
-module test #( parameter v2kparam = 5)
-(in, out, io, vin, vout, vio);
-input in;
-output out;
-inout io;
-input [3:0] vin;
-output [v2kparam:0] vout;
-inout [0:3] vio;
-parameter myparam = 10;
-endmodule
diff --git a/tests/hana/test_parser_constructs_port_basic0_test.v b/tests/hana/test_parser_constructs_port_basic0_test.v
deleted file mode 100644
index 8478e31d..00000000
--- a/tests/hana/test_parser_constructs_port_basic0_test.v
+++ /dev/null
@@ -1,8 +0,0 @@
-module test(in, out, io, vin, vout, vio);
-input in;
-output out;
-inout io;
-input [3:0] vin;
-output [3:0] vout;
-inout [0:3] vio;
-endmodule
diff --git a/tests/hana/test_parser_directives_define_simpledef_test.v b/tests/hana/test_parser_directives_define_simpledef_test.v
deleted file mode 100644
index 4a5d2345..00000000
--- a/tests/hana/test_parser_directives_define_simpledef_test.v
+++ /dev/null
@@ -1,9 +0,0 @@
-`define parvez ahmad
-`define WIRE wire
-`define TEN 10
-
-module `parvez();
-parameter param = `TEN;
-`WIRE w;
-assign w = `TEN;
-endmodule
diff --git a/tests/hana/test_parser_misc_operators_test.v b/tests/hana/test_parser_misc_operators_test.v
deleted file mode 100644
index 8fe8e7ba..00000000
--- a/tests/hana/test_parser_misc_operators_test.v
+++ /dev/null
@@ -1,29 +0,0 @@
-module test(out, i0, i1, i2, i3, s1, s0);
-output out;
-input i0, i1, i2, i3;
-input s1, s0;
-
-assign out = (~s1 & s0 & i0) |
- (~s1 & s0 & i1) |
- (s1 & ~s0 & i2) |
- (s1 & s0 & i3);
-
-endmodule
-
-module ternaryop(out, i0, i1, i2, i3, s1, s0);
-output out;
-input i0, i1, i2, i3;
-input s1, s0;
-
-assign out = s1 ? (s0 ? i3 : i2) : (s0 ? i1 : i0);
-
-endmodule
-
-module fulladd4(sum, c_out, a, b, c_in);
-output [3:0] sum;
-output c_out;
-input [3:0] a, b;
-input c_in;
-
-assign {c_out, sum} = a + b + c_in;
-endmodule
diff --git a/tests/hana/test_parser_v2k_comb_port_data_type_test.v b/tests/hana/test_parser_v2k_comb_port_data_type_test.v
deleted file mode 100644
index 099585b5..00000000
--- a/tests/hana/test_parser_v2k_comb_port_data_type_test.v
+++ /dev/null
@@ -1,6 +0,0 @@
-module adder(sum , co, a, b, ci);
-output reg [31:0] sum;
-output reg co;
-input wire [31:0] a, b;
-input wire ci;
-endmodule
diff --git a/tests/hana/test_parser_v2k_comma_sep_sens_list_test.v b/tests/hana/test_parser_v2k_comma_sep_sens_list_test.v
deleted file mode 100644
index 50f1d353..00000000
--- a/tests/hana/test_parser_v2k_comma_sep_sens_list_test.v
+++ /dev/null
@@ -1,9 +0,0 @@
-module test(q, d, clk, reset);
-output reg q;
-input d, clk, reset;
-
-always @ (posedge clk, negedge reset)
- if(!reset) q <= 0;
- else q <= d;
-
-endmodule
diff --git a/tests/hana/test_simulation_always.v b/tests/hana/test_simulation_always.v
new file mode 100644
index 00000000..3ee75313
--- /dev/null
+++ b/tests/hana/test_simulation_always.v
@@ -0,0 +1,135 @@
+
+// test_simulation_always_15_test.v
+module f1_test(input [1:0] in, output reg [1:0] out);
+
+always @(in)
+ out = in;
+endmodule
+
+// test_simulation_always_17_test.v
+module f2_test(a, b, c, d, z);
+input a, b, c, d;
+output z;
+reg z, temp1, temp2;
+
+always @(a or b or c or d)
+begin
+ temp1 = a ^ b;
+ temp2 = c ^ d;
+ z = temp1 ^ temp2;
+end
+
+endmodule
+
+// test_simulation_always_18_test.v
+module f3_test (in1, in2, out);
+input in1, in2;
+output reg out;
+
+always @ ( in1 or in2)
+ if(in1 > in2)
+ out = in1;
+ else
+ out = in2;
+endmodule
+
+// test_simulation_always_19_test.v
+module f4_test(ctrl, in1, in2, out);
+input ctrl;
+input in1, in2;
+output reg out;
+
+always @ (ctrl or in1 or in2)
+ if(ctrl)
+ out = in1 & in2;
+ else
+ out = in1 | in2;
+endmodule
+
+// test_simulation_always_1_test.v
+module f5_test(input in, output reg out);
+
+always @(in)
+ out = in;
+endmodule
+
+// test_simulation_always_20_test.v
+module f6_NonBlockingEx(clk, merge, er, xmit, fddi, claim);
+input clk, merge, er, xmit, fddi;
+output reg claim;
+reg fcr;
+
+always @(posedge clk)
+begin
+ fcr <= er | xmit;
+
+ if(merge)
+ claim <= fcr & fddi;
+ else
+ claim <= fddi;
+end
+endmodule
+
+// test_simulation_always_21_test.v
+module f7_FlipFlop(clk, cs, ns);
+input clk;
+input [7:0] cs;
+output [7:0] ns;
+integer is;
+
+always @(posedge clk)
+ is <= cs;
+
+assign ns = is;
+endmodule
+
+// test_simulation_always_22_test.v
+module f8_inc(clock, counter);
+
+input clock;
+output reg [7:0] counter;
+always @(posedge clock)
+ counter <= counter + 1;
+endmodule
+
+// test_simulation_always_23_test.v
+module f9_MyCounter (clock, preset, updown, presetdata, counter);
+input clock, preset, updown;
+input [1: 0] presetdata;
+output reg [1:0] counter;
+
+always @(posedge clock)
+ if(preset)
+ counter <= presetdata;
+ else
+ if(updown)
+ counter <= counter + 1;
+ else
+ counter <= counter - 1;
+endmodule
+
+// test_simulation_always_27_test.v
+module f10_FlipFlop(clock, cs, ns);
+input clock;
+input cs;
+output reg ns;
+reg temp;
+
+always @(posedge clock)
+begin
+ temp <= cs;
+ ns <= temp;
+end
+
+endmodule
+
+// test_simulation_always_29_test.v
+module f11_test(input in, output reg [1:0] out);
+
+ always @(in)
+ begin
+ out = in;
+ out = out + in;
+ end
+
+endmodule
diff --git a/tests/hana/test_simulation_always_15_test.v b/tests/hana/test_simulation_always_15_test.v
deleted file mode 100644
index 5c5fed5b..00000000
--- a/tests/hana/test_simulation_always_15_test.v
+++ /dev/null
@@ -1,5 +0,0 @@
-module test(input [1:0] in, output reg [1:0] out);
-
-always @(in)
- out = in;
-endmodule
diff --git a/tests/hana/test_simulation_always_17_test.v b/tests/hana/test_simulation_always_17_test.v
deleted file mode 100644
index 2d5abc4a..00000000
--- a/tests/hana/test_simulation_always_17_test.v
+++ /dev/null
@@ -1,13 +0,0 @@
-module test(a, b, c, d, z);
-input a, b, c, d;
-output z;
-reg z, temp1, temp2;
-
-always @(a or b or c or d)
-begin
- temp1 = a ^ b;
- temp2 = c ^ d;
- z = temp1 ^ temp2;
-end
-
-endmodule
diff --git a/tests/hana/test_simulation_always_18_test.v b/tests/hana/test_simulation_always_18_test.v
deleted file mode 100644
index 234407ef..00000000
--- a/tests/hana/test_simulation_always_18_test.v
+++ /dev/null
@@ -1,10 +0,0 @@
-module test (in1, in2, out);
-input in1, in2;
-output reg out;
-
-always @ ( in1 or in2)
- if(in1 > in2)
- out = in1;
- else
- out = in2;
-endmodule
diff --git a/tests/hana/test_simulation_always_19_test.v b/tests/hana/test_simulation_always_19_test.v
deleted file mode 100644
index 5152781d..00000000
--- a/tests/hana/test_simulation_always_19_test.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module test(ctrl, in1, in2, out);
-input ctrl;
-input in1, in2;
-output reg out;
-
-always @ (ctrl or in1 or in2)
- if(ctrl)
- out = in1 & in2;
- else
- out = in1 | in2;
-endmodule
diff --git a/tests/hana/test_simulation_always_1_test.v b/tests/hana/test_simulation_always_1_test.v
deleted file mode 100644
index 211369cb..00000000
--- a/tests/hana/test_simulation_always_1_test.v
+++ /dev/null
@@ -1,5 +0,0 @@
-module test(input in, output reg out);
-
-always @(in)
- out = in;
-endmodule
diff --git a/tests/hana/test_simulation_always_20_test.v b/tests/hana/test_simulation_always_20_test.v
deleted file mode 100644
index 6b3e861d..00000000
--- a/tests/hana/test_simulation_always_20_test.v
+++ /dev/null
@@ -1,15 +0,0 @@
-module NonBlockingEx(clk, merge, er, xmit, fddi, claim);
-input clk, merge, er, xmit, fddi;
-output reg claim;
-reg fcr;
-
-always @(posedge clk)
-begin
- fcr <= er | xmit;
-
- if(merge)
- claim <= fcr & fddi;
- else
- claim <= fddi;
-end
-endmodule
diff --git a/tests/hana/test_simulation_always_21_test.v b/tests/hana/test_simulation_always_21_test.v
deleted file mode 100644
index 6c47b4bd..00000000
--- a/tests/hana/test_simulation_always_21_test.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module FlipFlop(clk, cs, ns);
-input clk;
-input [7:0] cs;
-output [7:0] ns;
-integer is;
-
-always @(posedge clk)
- is <= cs;
-
-assign ns = is;
-endmodule
diff --git a/tests/hana/test_simulation_always_22_test.v b/tests/hana/test_simulation_always_22_test.v
deleted file mode 100644
index 8d91f815..00000000
--- a/tests/hana/test_simulation_always_22_test.v
+++ /dev/null
@@ -1,7 +0,0 @@
-module inc(clock, counter);
-
-input clock;
-output reg [7:0] counter;
-always @(posedge clock)
- counter <= counter + 1;
-endmodule
diff --git a/tests/hana/test_simulation_always_23_test.v b/tests/hana/test_simulation_always_23_test.v
deleted file mode 100644
index f1f13bbe..00000000
--- a/tests/hana/test_simulation_always_23_test.v
+++ /dev/null
@@ -1,14 +0,0 @@
-module MyCounter (clock, preset, updown, presetdata, counter);
-input clock, preset, updown;
-input [1: 0] presetdata;
-output reg [1:0] counter;
-
-always @(posedge clock)
- if(preset)
- counter <= presetdata;
- else
- if(updown)
- counter <= counter + 1;
- else
- counter <= counter - 1;
-endmodule
diff --git a/tests/hana/test_simulation_always_27_test.v b/tests/hana/test_simulation_always_27_test.v
deleted file mode 100644
index 577378fd..00000000
--- a/tests/hana/test_simulation_always_27_test.v
+++ /dev/null
@@ -1,13 +0,0 @@
-module FlipFlop(clock, cs, ns);
-input clock;
-input cs;
-output reg ns;
-reg temp;
-
-always @(posedge clock)
-begin
- temp <= cs;
- ns <= temp;
-end
-
-endmodule
diff --git a/tests/hana/test_simulation_always_29_test.v b/tests/hana/test_simulation_always_29_test.v
deleted file mode 100644
index 55606832..00000000
--- a/tests/hana/test_simulation_always_29_test.v
+++ /dev/null
@@ -1,9 +0,0 @@
-module test(input in, output reg [1:0] out);
-
- always @(in)
- begin
- out = in;
- out = out + in;
- end
-
-endmodule
diff --git a/tests/hana/test_simulation_and.v b/tests/hana/test_simulation_and.v
new file mode 100644
index 00000000..480e733d
--- /dev/null
+++ b/tests/hana/test_simulation_and.v
@@ -0,0 +1,35 @@
+
+// test_simulation_and_1_test.v
+module f1_test(input [1:0] in, output out);
+assign out = in[0] & in[1];
+endmodule
+
+// test_simulation_and_2_test.v
+module f2_test(input [1:0] in, output out);
+assign out = in[0] && in[1];
+endmodule
+
+// test_simulation_and_3_test.v
+module f3_test(input [2:0] in, output out);
+assign out = in[0] & in[1] & in[2];
+endmodule
+
+// test_simulation_and_4_test.v
+module f4_test(input [2:0] in, output out);
+assign out = in[0] && in[1] && in[2];
+endmodule
+
+// test_simulation_and_5_test.v
+module f5_test(input [3:0] in, output out);
+assign out = in[0] & in[1] & in[2] & in[3];
+endmodule
+
+// test_simulation_and_6_test.v
+module f6_test(input [3:0] in, output out);
+assign out = in[0] && in[1] && in[2] && in[3];
+endmodule
+
+// test_simulation_and_7_test.v
+module f7_test(input [3:0] in, output out);
+and myand(out, in[0], in[1], in[2], in[3]);
+endmodule
diff --git a/tests/hana/test_simulation_and_1_test.v b/tests/hana/test_simulation_and_1_test.v
deleted file mode 100644
index fba639ca..00000000
--- a/tests/hana/test_simulation_and_1_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [1:0] in, output out);
-assign out = in[0] & in[1];
-endmodule
diff --git a/tests/hana/test_simulation_and_2_test.v b/tests/hana/test_simulation_and_2_test.v
deleted file mode 100644
index 715bc7ca..00000000
--- a/tests/hana/test_simulation_and_2_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [1:0] in, output out);
-assign out = in[0] && in[1];
-endmodule
diff --git a/tests/hana/test_simulation_and_3_test.v b/tests/hana/test_simulation_and_3_test.v
deleted file mode 100644
index 74dccabf..00000000
--- a/tests/hana/test_simulation_and_3_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [2:0] in, output out);
-assign out = in[0] & in[1] & in[2];
-endmodule
diff --git a/tests/hana/test_simulation_and_4_test.v b/tests/hana/test_simulation_and_4_test.v
deleted file mode 100644
index 48ed9102..00000000
--- a/tests/hana/test_simulation_and_4_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [2:0] in, output out);
-assign out = in[0] && in[1] && in[2];
-endmodule
diff --git a/tests/hana/test_simulation_and_5_test.v b/tests/hana/test_simulation_and_5_test.v
deleted file mode 100644
index 29a35578..00000000
--- a/tests/hana/test_simulation_and_5_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [3:0] in, output out);
-assign out = in[0] & in[1] & in[2] & in[3];
-endmodule
diff --git a/tests/hana/test_simulation_and_6_test.v b/tests/hana/test_simulation_and_6_test.v
deleted file mode 100644
index ebce4eeb..00000000
--- a/tests/hana/test_simulation_and_6_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [3:0] in, output out);
-assign out = in[0] && in[1] && in[2] && in[3];
-endmodule
diff --git a/tests/hana/test_simulation_and_7_test.v b/tests/hana/test_simulation_and_7_test.v
deleted file mode 100644
index d394adad..00000000
--- a/tests/hana/test_simulation_and_7_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [3:0] in, output out);
-and myand(out, in[0], in[1], in[2], in[3]);
-endmodule
diff --git a/tests/hana/test_simulation_buffer.v b/tests/hana/test_simulation_buffer.v
new file mode 100644
index 00000000..d674b05c
--- /dev/null
+++ b/tests/hana/test_simulation_buffer.v
@@ -0,0 +1,17 @@
+
+// test_simulation_buffer_1_test.v
+module f1_test(input in, output out);
+assign out = in;
+endmodule
+
+// test_simulation_buffer_2_test.v
+module f2_test(input [1:0] in, output [1:0] out);
+assign out[0] = in[0];
+assign out[1] = in[1];
+endmodule
+
+// test_simulation_buffer_3_test.v
+module f3_test(input in, output [1:0] out);
+assign out[0] = in;
+assign out[1] = in;
+endmodule
diff --git a/tests/hana/test_simulation_buffer_1_test.v b/tests/hana/test_simulation_buffer_1_test.v
deleted file mode 100644
index e9bb7f61..00000000
--- a/tests/hana/test_simulation_buffer_1_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input in, output out);
-assign out = in;
-endmodule
diff --git a/tests/hana/test_simulation_buffer_2_test.v b/tests/hana/test_simulation_buffer_2_test.v
deleted file mode 100644
index 9a3f5aa3..00000000
--- a/tests/hana/test_simulation_buffer_2_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input [1:0] in, output [1:0] out);
-assign out[0] = in[0];
-assign out[1] = in[1];
-endmodule
diff --git a/tests/hana/test_simulation_buffer_3_test.v b/tests/hana/test_simulation_buffer_3_test.v
deleted file mode 100644
index 9bca426d..00000000
--- a/tests/hana/test_simulation_buffer_3_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input in, output [1:0] out);
-assign out[0] = in;
-assign out[1] = in;
-endmodule
diff --git a/tests/hana/test_simulation_decoder_8_test.v b/tests/hana/test_simulation_decoder.v
index 751d60f6..ef9045aa 100644
--- a/tests/hana/test_simulation_decoder_8_test.v
+++ b/tests/hana/test_simulation_decoder.v
@@ -1,4 +1,147 @@
-module test (input [5:0] in, input enable, output reg [63:0] out);
+
+// test_simulation_decoder_2_test.v
+module f1_test (input [1:0] in, input enable, output reg out);
+
+always @(in or enable)
+ if(!enable)
+ out = 4'b0000;
+ else begin
+ case (in)
+ 2'b00 : out = 0 ;
+ 2'b01 : out = 1;
+ 2'b10 : out = 0;
+ 2'b11 : out = 1;
+ endcase
+ end
+endmodule
+
+// test_simulation_decoder_3_test.v
+module f2_test (input [1:0] in, input enable, output reg [2:0] out);
+
+always @(in or enable)
+ if(!enable)
+ out = 3'b000;
+ else begin
+ case (in)
+ 2'b00 : out = 3'b001 ;
+ 2'b01 : out = 3'b010;
+ 2'b10 : out = 3'b010;
+ 2'b11 : out = 3'b100;
+ endcase
+ end
+endmodule
+
+// test_simulation_decoder_4_test.v
+module f3_test (input [2:0] in, output reg [7:0] out);
+
+always @(in )
+ case (in)
+ 3'b000 : out = 8'b00000001;
+ 3'b001 : out = 8'b00000010;
+ 3'b010 : out = 8'b00000100;
+ 3'b011 : out = 8'b00001000;
+ 3'b100 : out = 8'b00010000;
+ 3'b101 : out = 8'b00100000;
+ 3'b110 : out = 8'b01000000;
+ 3'b111 : out = 8'b10000000;
+ endcase
+endmodule
+
+// test_simulation_decoder_5_test.v
+module f4_test (input [2:0] in, input enable, output reg [7:0] out);
+
+always @(in or enable )
+ if(!enable)
+ out = 8'b00000000;
+ else
+ case (in)
+ 3'b000 : out = 8'b00000001;
+ 3'b001 : out = 8'b00000010;
+ 3'b010 : out = 8'b00000100;
+ 3'b011 : out = 8'b00001000;
+ 3'b100 : out = 8'b00010000;
+ 3'b101 : out = 8'b00100000;
+ 3'b110 : out = 8'b01000000;
+ 3'b111 : out = 8'b10000000;
+ endcase
+endmodule
+
+// test_simulation_decoder_6_test.v
+module f5_test (input [3:0] in, input enable, output reg [15:0] out);
+
+always @(in or enable)
+ if(!enable)
+ out = 16'b0000000000000000;
+ else begin
+ case (in)
+ 4'b0000 : out = 16'b0000000000000001;
+ 4'b0001 : out = 16'b0000000000000010;
+ 4'b0010 : out = 16'b0000000000000100;
+ 4'b0011 : out = 16'b0000000000001000;
+ 4'b0100 : out = 16'b0000000000010000;
+ 4'b0101 : out = 16'b0000000000100000;
+ 4'b0110 : out = 16'b0000000001000000;
+ 4'b0111 : out = 16'b0000000010000000;
+ 4'b1000 : out = 16'b0000000100000000;
+ 4'b1001 : out = 16'b0000001000000000;
+ 4'b1010 : out = 16'b0000010000000000;
+ 4'b1011 : out = 16'b0000100000000000;
+ 4'b1100 : out = 16'b0001000000000000;
+ 4'b1101 : out = 16'b0010000000000000;
+ 4'b1110 : out = 16'b0100000000000000;
+ 4'b1111 : out = 16'b1000000000000000;
+ endcase
+ end
+endmodule
+
+
+// test_simulation_decoder_7_test.v
+module f6_test (input [4:0] in, input enable, output reg [31:0] out);
+
+always @(in or enable)
+ if(!enable)
+ out = 32'b00000000000000000000000000000000;
+ else begin
+ case (in)
+ 5'b00000 : out = 32'b00000000000000000000000000000001;
+ 5'b00001 : out = 32'b00000000000000000000000000000010;
+ 5'b00010 : out = 32'b00000000000000000000000000000100;
+ 5'b00011 : out = 32'b00000000000000000000000000001000;
+ 5'b00100 : out = 32'b00000000000000000000000000010000;
+ 5'b00101 : out = 32'b00000000000000000000000000100000;
+ 5'b00110 : out = 32'b00000000000000000000000001000000;
+ 5'b00111 : out = 32'b00000000000000000000000010000000;
+ 5'b01000 : out = 32'b00000000000000000000000100000000;
+ 5'b01001 : out = 32'b00000000000000000000001000000000;
+ 5'b01010 : out = 32'b00000000000000000000010000000000;
+ 5'b01011 : out = 32'b00000000000000000000100000000000;
+ 5'b01100 : out = 32'b00000000000000000001000000000000;
+ 5'b01101 : out = 32'b00000000000000000010000000000000;
+ 5'b01110 : out = 32'b00000000000000000100000000000000;
+ 5'b01111 : out = 32'b00000000000000001000000000000000;
+ 5'b10000 : out = 32'b00000000000000010000000000000000;
+ 5'b10001 : out = 32'b00000000000000100000000000000000;
+ 5'b10010 : out = 32'b00000000000001000000000000000000;
+ 5'b10011 : out = 32'b00000000000010000000000000000000;
+ 5'b10100 : out = 32'b00000000000100000000000000000000;
+ 5'b10101 : out = 32'b00000000001000000000000000000000;
+ 5'b10110 : out = 32'b00000000010000000000000000000000;
+ 5'b10111 : out = 32'b00000000100000000000000000000000;
+ 5'b11000 : out = 32'b00000001000000000000000000000000;
+ 5'b11001 : out = 32'b00000010000000000000000000000000;
+ 5'b11010 : out = 32'b00000100000000000000000000000000;
+ 5'b11011 : out = 32'b00001000000000000000000000000000;
+ 5'b11100 : out = 32'b00010000000000000000000000000000;
+ 5'b11101 : out = 32'b00100000000000000000000000000000;
+ 5'b11110 : out = 32'b01000000000000000000000000000000;
+ 5'b11111 : out = 32'b10000000000000000000000000000000;
+ endcase
+ end
+endmodule
+
+
+// test_simulation_decoder_8_test.v
+module f7_test (input [5:0] in, input enable, output reg [63:0] out);
always @(in or enable)
if(!enable)
diff --git a/tests/hana/test_simulation_decoder_2_test.v b/tests/hana/test_simulation_decoder_2_test.v
deleted file mode 100644
index 5bdf1971..00000000
--- a/tests/hana/test_simulation_decoder_2_test.v
+++ /dev/null
@@ -1,14 +0,0 @@
-module test (input [1:0] in, input enable, output reg out);
-
-always @(in or enable)
- if(!enable)
- out = 4'b0000;
- else begin
- case (in)
- 2'b00 : out = 0 ;
- 2'b01 : out = 1;
- 2'b10 : out = 0;
- 2'b11 : out = 1;
- endcase
- end
-endmodule
diff --git a/tests/hana/test_simulation_decoder_3_test.v b/tests/hana/test_simulation_decoder_3_test.v
deleted file mode 100644
index 44f5de12..00000000
--- a/tests/hana/test_simulation_decoder_3_test.v
+++ /dev/null
@@ -1,14 +0,0 @@
-module test (input [1:0] in, input enable, output reg [2:0] out);
-
-always @(in or enable)
- if(!enable)
- out = 3'b000;
- else begin
- case (in)
- 2'b00 : out = 3'b001 ;
- 2'b01 : out = 3'b010;
- 2'b10 : out = 3'b010;
- 2'b11 : out = 3'b100;
- endcase
- end
-endmodule
diff --git a/tests/hana/test_simulation_decoder_4_test.v b/tests/hana/test_simulation_decoder_4_test.v
deleted file mode 100644
index 871a5bbf..00000000
--- a/tests/hana/test_simulation_decoder_4_test.v
+++ /dev/null
@@ -1,14 +0,0 @@
-module test (input [2:0] in, output reg [7:0] out);
-
-always @(in )
- case (in)
- 3'b000 : out = 8'b00000001;
- 3'b001 : out = 8'b00000010;
- 3'b010 : out = 8'b00000100;
- 3'b011 : out = 8'b00001000;
- 3'b100 : out = 8'b00010000;
- 3'b101 : out = 8'b00100000;
- 3'b110 : out = 8'b01000000;
- 3'b111 : out = 8'b10000000;
- endcase
-endmodule
diff --git a/tests/hana/test_simulation_decoder_5_test.v b/tests/hana/test_simulation_decoder_5_test.v
deleted file mode 100644
index 497fa4bf..00000000
--- a/tests/hana/test_simulation_decoder_5_test.v
+++ /dev/null
@@ -1,17 +0,0 @@
-module test (input [2:0] in, input enable, output reg [7:0] out);
-
-always @(in or enable )
- if(!enable)
- out = 8'b00000000;
- else
- case (in)
- 3'b000 : out = 8'b00000001;
- 3'b001 : out = 8'b00000010;
- 3'b010 : out = 8'b00000100;
- 3'b011 : out = 8'b00001000;
- 3'b100 : out = 8'b00010000;
- 3'b101 : out = 8'b00100000;
- 3'b110 : out = 8'b01000000;
- 3'b111 : out = 8'b10000000;
- endcase
-endmodule
diff --git a/tests/hana/test_simulation_decoder_6_test.v b/tests/hana/test_simulation_decoder_6_test.v
deleted file mode 100644
index fd19ad60..00000000
--- a/tests/hana/test_simulation_decoder_6_test.v
+++ /dev/null
@@ -1,27 +0,0 @@
-module test (input [3:0] in, input enable, output reg [15:0] out);
-
-always @(in or enable)
- if(!enable)
- out = 16'b0000000000000000;
- else begin
- case (in)
- 4'b0000 : out = 16'b0000000000000001;
- 4'b0001 : out = 16'b0000000000000010;
- 4'b0010 : out = 16'b0000000000000100;
- 4'b0011 : out = 16'b0000000000001000;
- 4'b0100 : out = 16'b0000000000010000;
- 4'b0101 : out = 16'b0000000000100000;
- 4'b0110 : out = 16'b0000000001000000;
- 4'b0111 : out = 16'b0000000010000000;
- 4'b1000 : out = 16'b0000000100000000;
- 4'b1001 : out = 16'b0000001000000000;
- 4'b1010 : out = 16'b0000010000000000;
- 4'b1011 : out = 16'b0000100000000000;
- 4'b1100 : out = 16'b0001000000000000;
- 4'b1101 : out = 16'b0010000000000000;
- 4'b1110 : out = 16'b0100000000000000;
- 4'b1111 : out = 16'b1000000000000000;
- endcase
- end
-endmodule
-
diff --git a/tests/hana/test_simulation_decoder_7_test.v b/tests/hana/test_simulation_decoder_7_test.v
deleted file mode 100644
index 462e9419..00000000
--- a/tests/hana/test_simulation_decoder_7_test.v
+++ /dev/null
@@ -1,43 +0,0 @@
-module test (input [4:0] in, input enable, output reg [31:0] out);
-
-always @(in or enable)
- if(!enable)
- out = 32'b00000000000000000000000000000000;
- else begin
- case (in)
- 5'b00000 : out = 32'b00000000000000000000000000000001;
- 5'b00001 : out = 32'b00000000000000000000000000000010;
- 5'b00010 : out = 32'b00000000000000000000000000000100;
- 5'b00011 : out = 32'b00000000000000000000000000001000;
- 5'b00100 : out = 32'b00000000000000000000000000010000;
- 5'b00101 : out = 32'b00000000000000000000000000100000;
- 5'b00110 : out = 32'b00000000000000000000000001000000;
- 5'b00111 : out = 32'b00000000000000000000000010000000;
- 5'b01000 : out = 32'b00000000000000000000000100000000;
- 5'b01001 : out = 32'b00000000000000000000001000000000;
- 5'b01010 : out = 32'b00000000000000000000010000000000;
- 5'b01011 : out = 32'b00000000000000000000100000000000;
- 5'b01100 : out = 32'b00000000000000000001000000000000;
- 5'b01101 : out = 32'b00000000000000000010000000000000;
- 5'b01110 : out = 32'b00000000000000000100000000000000;
- 5'b01111 : out = 32'b00000000000000001000000000000000;
- 5'b10000 : out = 32'b00000000000000010000000000000000;
- 5'b10001 : out = 32'b00000000000000100000000000000000;
- 5'b10010 : out = 32'b00000000000001000000000000000000;
- 5'b10011 : out = 32'b00000000000010000000000000000000;
- 5'b10100 : out = 32'b00000000000100000000000000000000;
- 5'b10101 : out = 32'b00000000001000000000000000000000;
- 5'b10110 : out = 32'b00000000010000000000000000000000;
- 5'b10111 : out = 32'b00000000100000000000000000000000;
- 5'b11000 : out = 32'b00000001000000000000000000000000;
- 5'b11001 : out = 32'b00000010000000000000000000000000;
- 5'b11010 : out = 32'b00000100000000000000000000000000;
- 5'b11011 : out = 32'b00001000000000000000000000000000;
- 5'b11100 : out = 32'b00010000000000000000000000000000;
- 5'b11101 : out = 32'b00100000000000000000000000000000;
- 5'b11110 : out = 32'b01000000000000000000000000000000;
- 5'b11111 : out = 32'b10000000000000000000000000000000;
- endcase
- end
-endmodule
-
diff --git a/tests/hana/test_simulation_inc.v b/tests/hana/test_simulation_inc.v
new file mode 100644
index 00000000..f8f54870
--- /dev/null
+++ b/tests/hana/test_simulation_inc.v
@@ -0,0 +1,42 @@
+
+// test_simulation_inc_16_test.v
+module f1_test(input [15:0] in, output [15:0] out);
+
+assign out = -in;
+
+endmodule
+
+// test_simulation_inc_1_test.v
+module f2_test(input in, output out);
+
+assign out = -in;
+
+endmodule
+
+// test_simulation_inc_2_test.v
+module f3_test(input [1:0] in, output [1:0] out);
+
+assign out = -in;
+
+endmodule
+
+// test_simulation_inc_32_test.v
+module f4_test(input [31:0] in, output [31:0] out);
+
+assign out = -in;
+
+endmodule
+
+// test_simulation_inc_4_test.v
+module f5_test(input [3:0] in, output [3:0] out);
+
+assign out = -in;
+
+endmodule
+
+// test_simulation_inc_8_test.v
+module f6_test(input [7:0] in, output [7:0] out);
+
+assign out = -in;
+
+endmodule
diff --git a/tests/hana/test_simulation_inc_16_test.v b/tests/hana/test_simulation_inc_16_test.v
deleted file mode 100644
index 7ff42ff5..00000000
--- a/tests/hana/test_simulation_inc_16_test.v
+++ /dev/null
@@ -1,5 +0,0 @@
-module test(input [15:0] in, output [15:0] out);
-
-assign out = -in;
-
-endmodule
diff --git a/tests/hana/test_simulation_inc_1_test.v b/tests/hana/test_simulation_inc_1_test.v
deleted file mode 100644
index 02bec2c2..00000000
--- a/tests/hana/test_simulation_inc_1_test.v
+++ /dev/null
@@ -1,5 +0,0 @@
-module test(input in, output out);
-
-assign out = -in;
-
-endmodule
diff --git a/tests/hana/test_simulation_inc_2_test.v b/tests/hana/test_simulation_inc_2_test.v
deleted file mode 100644
index b96e05a2..00000000
--- a/tests/hana/test_simulation_inc_2_test.v
+++ /dev/null
@@ -1,5 +0,0 @@
-module test(input [1:0] in, output [1:0] out);
-
-assign out = -in;
-
-endmodule
diff --git a/tests/hana/test_simulation_inc_32_test.v b/tests/hana/test_simulation_inc_32_test.v
deleted file mode 100644
index 5700d0ce..00000000
--- a/tests/hana/test_simulation_inc_32_test.v
+++ /dev/null
@@ -1,5 +0,0 @@
-module test(input [31:0] in, output [31:0] out);
-
-assign out = -in;
-
-endmodule
diff --git a/tests/hana/test_simulation_inc_4_test.v b/tests/hana/test_simulation_inc_4_test.v
deleted file mode 100644
index 34940d63..00000000
--- a/tests/hana/test_simulation_inc_4_test.v
+++ /dev/null
@@ -1,5 +0,0 @@
-module test(input [3:0] in, output [3:0] out);
-
-assign out = -in;
-
-endmodule
diff --git a/tests/hana/test_simulation_inc_8_test.v b/tests/hana/test_simulation_inc_8_test.v
deleted file mode 100644
index c36d69f0..00000000
--- a/tests/hana/test_simulation_inc_8_test.v
+++ /dev/null
@@ -1,5 +0,0 @@
-module test(input [7:0] in, output [7:0] out);
-
-assign out = -in;
-
-endmodule
diff --git a/tests/hana/test_simulation_mod_1_xx.v b/tests/hana/test_simulation_mod_1_xx.v
deleted file mode 100644
index 75144a8e..00000000
--- a/tests/hana/test_simulation_mod_1_xx.v
+++ /dev/null
@@ -1,13 +0,0 @@
-module test(in1, in2, out);
-input in1;
-input in2;
-output out;
-
-wire synth_net_0;
-wire synth_net_1;
-BUF synth_BUF_0(.in(synth_net_1), .out(out
- ));
-DIV1 synth_DIV(.in1(in1), .in2(in2), .rem(synth_net_0), .out(synth_net_1
- ));
-endmodule
-
diff --git a/tests/hana/test_simulation_mux.v b/tests/hana/test_simulation_mux.v
new file mode 100644
index 00000000..085387ef
--- /dev/null
+++ b/tests/hana/test_simulation_mux.v
@@ -0,0 +1,176 @@
+
+// test_simulation_mux_16_test.v
+module f1_test(input [15:0] in, input [3:0] select, output reg out);
+
+always @( in or select)
+ case (select)
+ 0: out = in[0];
+ 1: out = in[1];
+ 2: out = in[2];
+ 3: out = in[3];
+ 4: out = in[4];
+ 5: out = in[5];
+ 6: out = in[6];
+ 7: out = in[7];
+ 8: out = in[8];
+ 9: out = in[9];
+ 10: out = in[10];
+ 11: out = in[11];
+ 12: out = in[12];
+ 13: out = in[13];
+ 14: out = in[14];
+ 15: out = in[15];
+ endcase
+endmodule
+
+// test_simulation_mux_2_test.v
+module f2_test(input [1:0] in, input select, output reg out);
+
+always @( in or select)
+ case (select)
+ 0: out = in[0];
+ 1: out = in[1];
+ endcase
+endmodule
+
+// test_simulation_mux_32_test.v
+module f3_test(input [31:0] in, input [4:0] select, output reg out);
+
+always @( in or select)
+ case (select)
+ 0: out = in[0];
+ 1: out = in[1];
+ 2: out = in[2];
+ 3: out = in[3];
+ 4: out = in[4];
+ 5: out = in[5];
+ 6: out = in[6];
+ 7: out = in[7];
+ 8: out = in[8];
+ 9: out = in[9];
+ 10: out = in[10];
+ 11: out = in[11];
+ 12: out = in[12];
+ 13: out = in[13];
+ 14: out = in[14];
+ 15: out = in[15];
+ 16: out = in[16];
+ 17: out = in[17];
+ 18: out = in[18];
+ 19: out = in[19];
+ 20: out = in[20];
+ 21: out = in[21];
+ 22: out = in[22];
+ 23: out = in[23];
+ 24: out = in[24];
+ 25: out = in[25];
+ 26: out = in[26];
+ 27: out = in[27];
+ 28: out = in[28];
+ 29: out = in[29];
+ 30: out = in[30];
+ 31: out = in[31];
+ endcase
+endmodule
+
+
+// test_simulation_mux_4_test.v
+module f4_test(input [3:0] in, input [1:0] select, output reg out);
+
+always @( in or select)
+ case (select)
+ 0: out = in[0];
+ 1: out = in[1];
+ 2: out = in[2];
+ 3: out = in[3];
+ endcase
+endmodule
+
+// test_simulation_mux_64_test.v
+module f5_test(input [63:0] in, input [5:0] select, output reg out);
+
+always @( in or select)
+ case (select)
+ 0: out = in[0];
+ 1: out = in[1];
+ 2: out = in[2];
+ 3: out = in[3];
+ 4: out = in[4];
+ 5: out = in[5];
+ 6: out = in[6];
+ 7: out = in[7];
+ 8: out = in[8];
+ 9: out = in[9];
+ 10: out = in[10];
+ 11: out = in[11];
+ 12: out = in[12];
+ 13: out = in[13];
+ 14: out = in[14];
+ 15: out = in[15];
+ 16: out = in[16];
+ 17: out = in[17];
+ 18: out = in[18];
+ 19: out = in[19];
+ 20: out = in[20];
+ 21: out = in[21];
+ 22: out = in[22];
+ 23: out = in[23];
+ 24: out = in[24];
+ 25: out = in[25];
+ 26: out = in[26];
+ 27: out = in[27];
+ 28: out = in[28];
+ 29: out = in[29];
+ 30: out = in[30];
+ 31: out = in[31];
+ 32: out = in[32];
+ 33: out = in[33];
+ 34: out = in[34];
+ 35: out = in[35];
+ 36: out = in[36];
+ 37: out = in[37];
+ 38: out = in[38];
+ 39: out = in[39];
+ 40: out = in[40];
+ 41: out = in[41];
+ 42: out = in[42];
+ 43: out = in[43];
+ 44: out = in[44];
+ 45: out = in[45];
+ 46: out = in[46];
+ 47: out = in[47];
+ 48: out = in[48];
+ 49: out = in[49];
+ 50: out = in[50];
+ 51: out = in[51];
+ 52: out = in[52];
+ 53: out = in[53];
+ 54: out = in[54];
+ 55: out = in[55];
+ 56: out = in[56];
+ 57: out = in[57];
+ 58: out = in[58];
+ 59: out = in[59];
+ 60: out = in[60];
+ 61: out = in[61];
+ 62: out = in[62];
+ 63: out = in[63];
+ endcase
+endmodule
+
+
+// test_simulation_mux_8_test.v
+module f6_test(input [7:0] in, input [2:0] select, output reg out);
+
+always @( in or select)
+ case (select)
+ 0: out = in[0];
+ 1: out = in[1];
+ 2: out = in[2];
+ 3: out = in[3];
+ 4: out = in[4];
+ 5: out = in[5];
+ 6: out = in[6];
+ 7: out = in[7];
+ endcase
+endmodule
diff --git a/tests/hana/test_simulation_mux_16_test.v b/tests/hana/test_simulation_mux_16_test.v
deleted file mode 100644
index de4b6f8e..00000000
--- a/tests/hana/test_simulation_mux_16_test.v
+++ /dev/null
@@ -1,22 +0,0 @@
-module test(input [15:0] in, input [3:0] select, output reg out);
-
-always @( in or select)
- case (select)
- 0: out = in[0];
- 1: out = in[1];
- 2: out = in[2];
- 3: out = in[3];
- 4: out = in[4];
- 5: out = in[5];
- 6: out = in[6];
- 7: out = in[7];
- 8: out = in[8];
- 9: out = in[9];
- 10: out = in[10];
- 11: out = in[11];
- 12: out = in[12];
- 13: out = in[13];
- 14: out = in[14];
- 15: out = in[15];
- endcase
-endmodule
diff --git a/tests/hana/test_simulation_mux_2_test.v b/tests/hana/test_simulation_mux_2_test.v
deleted file mode 100644
index bc676c70..00000000
--- a/tests/hana/test_simulation_mux_2_test.v
+++ /dev/null
@@ -1,8 +0,0 @@
-module test(input [1:0] in, input select, output reg out);
-
-always @( in or select)
- case (select)
- 0: out = in[0];
- 1: out = in[1];
- endcase
-endmodule
diff --git a/tests/hana/test_simulation_mux_32_test.v b/tests/hana/test_simulation_mux_32_test.v
deleted file mode 100644
index 16de4d7f..00000000
--- a/tests/hana/test_simulation_mux_32_test.v
+++ /dev/null
@@ -1,39 +0,0 @@
-module test(input [31:0] in, input [4:0] select, output reg out);
-
-always @( in or select)
- case (select)
- 0: out = in[0];
- 1: out = in[1];
- 2: out = in[2];
- 3: out = in[3];
- 4: out = in[4];
- 5: out = in[5];
- 6: out = in[6];
- 7: out = in[7];
- 8: out = in[8];
- 9: out = in[9];
- 10: out = in[10];
- 11: out = in[11];
- 12: out = in[12];
- 13: out = in[13];
- 14: out = in[14];
- 15: out = in[15];
- 16: out = in[16];
- 17: out = in[17];
- 18: out = in[18];
- 19: out = in[19];
- 20: out = in[20];
- 21: out = in[21];
- 22: out = in[22];
- 23: out = in[23];
- 24: out = in[24];
- 25: out = in[25];
- 26: out = in[26];
- 27: out = in[27];
- 28: out = in[28];
- 29: out = in[29];
- 30: out = in[30];
- 31: out = in[31];
- endcase
-endmodule
-
diff --git a/tests/hana/test_simulation_mux_4_test.v b/tests/hana/test_simulation_mux_4_test.v
deleted file mode 100644
index 6a112c6a..00000000
--- a/tests/hana/test_simulation_mux_4_test.v
+++ /dev/null
@@ -1,10 +0,0 @@
-module test(input [3:0] in, input [1:0] select, output reg out);
-
-always @( in or select)
- case (select)
- 0: out = in[0];
- 1: out = in[1];
- 2: out = in[2];
- 3: out = in[3];
- endcase
-endmodule
diff --git a/tests/hana/test_simulation_mux_64_test.v b/tests/hana/test_simulation_mux_64_test.v
deleted file mode 100644
index 420239c6..00000000
--- a/tests/hana/test_simulation_mux_64_test.v
+++ /dev/null
@@ -1,71 +0,0 @@
-module test(input [63:0] in, input [5:0] select, output reg out);
-
-always @( in or select)
- case (select)
- 0: out = in[0];
- 1: out = in[1];
- 2: out = in[2];
- 3: out = in[3];
- 4: out = in[4];
- 5: out = in[5];
- 6: out = in[6];
- 7: out = in[7];
- 8: out = in[8];
- 9: out = in[9];
- 10: out = in[10];
- 11: out = in[11];
- 12: out = in[12];
- 13: out = in[13];
- 14: out = in[14];
- 15: out = in[15];
- 16: out = in[16];
- 17: out = in[17];
- 18: out = in[18];
- 19: out = in[19];
- 20: out = in[20];
- 21: out = in[21];
- 22: out = in[22];
- 23: out = in[23];
- 24: out = in[24];
- 25: out = in[25];
- 26: out = in[26];
- 27: out = in[27];
- 28: out = in[28];
- 29: out = in[29];
- 30: out = in[30];
- 31: out = in[31];
- 32: out = in[32];
- 33: out = in[33];
- 34: out = in[34];
- 35: out = in[35];
- 36: out = in[36];
- 37: out = in[37];
- 38: out = in[38];
- 39: out = in[39];
- 40: out = in[40];
- 41: out = in[41];
- 42: out = in[42];
- 43: out = in[43];
- 44: out = in[44];
- 45: out = in[45];
- 46: out = in[46];
- 47: out = in[47];
- 48: out = in[48];
- 49: out = in[49];
- 50: out = in[50];
- 51: out = in[51];
- 52: out = in[52];
- 53: out = in[53];
- 54: out = in[54];
- 55: out = in[55];
- 56: out = in[56];
- 57: out = in[57];
- 58: out = in[58];
- 59: out = in[59];
- 60: out = in[60];
- 61: out = in[61];
- 62: out = in[62];
- 63: out = in[63];
- endcase
-endmodule
-
diff --git a/tests/hana/test_simulation_mux_8_test.v b/tests/hana/test_simulation_mux_8_test.v
deleted file mode 100644
index f53a2c57..00000000
--- a/tests/hana/test_simulation_mux_8_test.v
+++ /dev/null
@@ -1,14 +0,0 @@
-module test(input [7:0] in, input [2:0] select, output reg out);
-
-always @( in or select)
- case (select)
- 0: out = in[0];
- 1: out = in[1];
- 2: out = in[2];
- 3: out = in[3];
- 4: out = in[4];
- 5: out = in[5];
- 6: out = in[6];
- 7: out = in[7];
- endcase
-endmodule
diff --git a/tests/hana/test_simulation_nand.v b/tests/hana/test_simulation_nand.v
new file mode 100644
index 00000000..5e6e0f1f
--- /dev/null
+++ b/tests/hana/test_simulation_nand.v
@@ -0,0 +1,25 @@
+
+// test_simulation_nand_1_test.v
+module f1_test(input [1:0] in, output out);
+assign out = ~(in[0] & in[1]);
+endmodule
+
+// test_simulation_nand_3_test.v
+module f2_test(input [2:0] in, output out);
+assign out = !(in[0] & in[1] & in[2]);
+endmodule
+
+// test_simulation_nand_4_test.v
+module f3_test(input [2:0] in, output out);
+assign out = ~(in[0] && in[1] && in[2]);
+endmodule
+
+// test_simulation_nand_5_test.v
+module f4_test(input [3:0] in, output out);
+assign out = !(in[0] & in[1] & in[2] & in[3]);
+endmodule
+
+// test_simulation_nand_6_test.v
+module f5_test(input [3:0] in, output out);
+assign out = !(in[0] && in[1] && in[2] && in[3]);
+endmodule
diff --git a/tests/hana/test_simulation_nand_1_test.v b/tests/hana/test_simulation_nand_1_test.v
deleted file mode 100644
index d8f34ee1..00000000
--- a/tests/hana/test_simulation_nand_1_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [1:0] in, output out);
-assign out = ~(in[0] & in[1]);
-endmodule
diff --git a/tests/hana/test_simulation_nand_3_test.v b/tests/hana/test_simulation_nand_3_test.v
deleted file mode 100644
index 8926cebb..00000000
--- a/tests/hana/test_simulation_nand_3_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [2:0] in, output out);
-assign out = !(in[0] & in[1] & in[2]);
-endmodule
diff --git a/tests/hana/test_simulation_nand_4_test.v b/tests/hana/test_simulation_nand_4_test.v
deleted file mode 100644
index 703a2de4..00000000
--- a/tests/hana/test_simulation_nand_4_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [2:0] in, output out);
-assign out = ~(in[0] && in[1] && in[2]);
-endmodule
diff --git a/tests/hana/test_simulation_nand_5_test.v b/tests/hana/test_simulation_nand_5_test.v
deleted file mode 100644
index adef3c90..00000000
--- a/tests/hana/test_simulation_nand_5_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [3:0] in, output out);
-assign out = !(in[0] & in[1] & in[2] & in[3]);
-endmodule
diff --git a/tests/hana/test_simulation_nand_6_test.v b/tests/hana/test_simulation_nand_6_test.v
deleted file mode 100644
index a2136f21..00000000
--- a/tests/hana/test_simulation_nand_6_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [3:0] in, output out);
-assign out = !(in[0] && in[1] && in[2] && in[3]);
-endmodule
diff --git a/tests/hana/test_simulation_nor.v b/tests/hana/test_simulation_nor.v
new file mode 100644
index 00000000..d7d2bc0e
--- /dev/null
+++ b/tests/hana/test_simulation_nor.v
@@ -0,0 +1,20 @@
+
+// test_simulation_nor_1_test.v
+module f1_test(input [1:0] in, output out);
+assign out = ~(in[0] | in[1]);
+endmodule
+
+// test_simulation_nor_2_test.v
+module f2_test(input [2:0] in, output out);
+assign out = ~(in[0] | in[1] | in[2]);
+endmodule
+
+// test_simulation_nor_3_test.v
+module f3_test(input [3:0] in, output out);
+assign out = ~(in[0] | in[1] | in[2] | in[3]);
+endmodule
+
+// test_simulation_nor_4_test.v
+module f4_test(input [3:0] in, output out);
+nor mynor(out, in[0], in[1], in[2], in[3]);
+endmodule
diff --git a/tests/hana/test_simulation_nor_1_test.v b/tests/hana/test_simulation_nor_1_test.v
deleted file mode 100644
index df4e8bfa..00000000
--- a/tests/hana/test_simulation_nor_1_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [1:0] in, output out);
-assign out = ~(in[0] | in[1]);
-endmodule
diff --git a/tests/hana/test_simulation_nor_2_test.v b/tests/hana/test_simulation_nor_2_test.v
deleted file mode 100644
index 2cfffc45..00000000
--- a/tests/hana/test_simulation_nor_2_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [2:0] in, output out);
-assign out = ~(in[0] | in[1] | in[2]);
-endmodule
diff --git a/tests/hana/test_simulation_nor_3_test.v b/tests/hana/test_simulation_nor_3_test.v
deleted file mode 100644
index 9f1ef8fe..00000000
--- a/tests/hana/test_simulation_nor_3_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [3:0] in, output out);
-assign out = ~(in[0] | in[1] | in[2] | in[3]);
-endmodule
diff --git a/tests/hana/test_simulation_nor_4_test.v b/tests/hana/test_simulation_nor_4_test.v
deleted file mode 100644
index d8e68504..00000000
--- a/tests/hana/test_simulation_nor_4_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [3:0] in, output out);
-nor mynor(out, in[0], in[1], in[2], in[3]);
-endmodule
diff --git a/tests/hana/test_simulation_opt_constprop_contassign_1_test.v b/tests/hana/test_simulation_opt_constprop_contassign_1_test.v
deleted file mode 100644
index a39b58b4..00000000
--- a/tests/hana/test_simulation_opt_constprop_contassign_1_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input in, output out);
-assign out = 1'b1;
-endmodule
diff --git a/tests/hana/test_simulation_or.v b/tests/hana/test_simulation_or.v
new file mode 100644
index 00000000..9217db80
--- /dev/null
+++ b/tests/hana/test_simulation_or.v
@@ -0,0 +1,30 @@
+
+// test_simulation_or_1_test.v
+module f1_test(input [1:0] in, output out);
+assign out = in[0] | in[1];
+endmodule
+
+// test_simulation_or_2_test.v
+module f2_test(input [1:0] in, output out);
+assign out = in[0] || in[1];
+endmodule
+
+// test_simulation_or_3_test.v
+module f3_test(input [2:0] in, output out);
+assign out = in[0] | in[1] | in[2];
+endmodule
+
+// test_simulation_or_4_test.v
+module f4_test(input [2:0] in, output out);
+assign out = in[0] || in[1] || in[2];
+endmodule
+
+// test_simulation_or_5_test.v
+module f5_test(input [3:0] in, output out);
+assign out = in[0] | in[1] | in[2] | in[3];
+endmodule
+
+// test_simulation_or_6_test.v
+module f6_test(input [3:0] in, output out);
+assign out = in[0] || in[1] || in[2] || in[3];
+endmodule
diff --git a/tests/hana/test_simulation_or_1_test.v b/tests/hana/test_simulation_or_1_test.v
deleted file mode 100644
index bdfffd3d..00000000
--- a/tests/hana/test_simulation_or_1_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [1:0] in, output out);
-assign out = in[0] | in[1];
-endmodule
diff --git a/tests/hana/test_simulation_or_2_test.v b/tests/hana/test_simulation_or_2_test.v
deleted file mode 100644
index 291c8c76..00000000
--- a/tests/hana/test_simulation_or_2_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [1:0] in, output out);
-assign out = in[0] || in[1];
-endmodule
diff --git a/tests/hana/test_simulation_or_3_test.v b/tests/hana/test_simulation_or_3_test.v
deleted file mode 100644
index ad00c708..00000000
--- a/tests/hana/test_simulation_or_3_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [2:0] in, output out);
-assign out = in[0] | in[1] | in[2];
-endmodule
diff --git a/tests/hana/test_simulation_or_4_test.v b/tests/hana/test_simulation_or_4_test.v
deleted file mode 100644
index 2ec57fa9..00000000
--- a/tests/hana/test_simulation_or_4_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [2:0] in, output out);
-assign out = in[0] || in[1] || in[2];
-endmodule
diff --git a/tests/hana/test_simulation_or_5_test.v b/tests/hana/test_simulation_or_5_test.v
deleted file mode 100644
index f6a2d14d..00000000
--- a/tests/hana/test_simulation_or_5_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [3:0] in, output out);
-assign out = in[0] | in[1] | in[2] | in[3];
-endmodule
diff --git a/tests/hana/test_simulation_or_6_test.v b/tests/hana/test_simulation_or_6_test.v
deleted file mode 100644
index ecd85c36..00000000
--- a/tests/hana/test_simulation_or_6_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [3:0] in, output out);
-assign out = in[0] || in[1] || in[2] || in[3];
-endmodule
diff --git a/tests/hana/test_simulation_seq.v b/tests/hana/test_simulation_seq.v
new file mode 100644
index 00000000..eba4e88e
--- /dev/null
+++ b/tests/hana/test_simulation_seq.v
@@ -0,0 +1,12 @@
+
+// test_simulation_seq_ff_1_test.v
+module f1_test(input in, input clk, output reg out);
+always @(posedge clk)
+ out <= in;
+endmodule
+
+// test_simulation_seq_ff_2_test.v
+module f2_test(input in, input clk, output reg out);
+always @(negedge clk)
+ out <= in;
+endmodule
diff --git a/tests/hana/test_simulation_seq_ff_1_test.v b/tests/hana/test_simulation_seq_ff_1_test.v
deleted file mode 100644
index 5aac49c0..00000000
--- a/tests/hana/test_simulation_seq_ff_1_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input in, input clk, output reg out);
-always @(posedge clk)
- out <= in;
-endmodule
diff --git a/tests/hana/test_simulation_seq_ff_2_test.v b/tests/hana/test_simulation_seq_ff_2_test.v
deleted file mode 100644
index f1d2b7b4..00000000
--- a/tests/hana/test_simulation_seq_ff_2_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input in, input clk, output reg out);
-always @(negedge clk)
- out <= in;
-endmodule
diff --git a/tests/hana/test_simulation_shifter.v b/tests/hana/test_simulation_shifter.v
new file mode 100644
index 00000000..8864fb0e
--- /dev/null
+++ b/tests/hana/test_simulation_shifter.v
@@ -0,0 +1,60 @@
+
+// test_simulation_shifter_left_16_test.v
+module f1_test(input [15:0] IN, input [4:0] SHIFT, output [15:0] OUT);
+
+assign OUT = IN << SHIFT;
+endmodule
+
+// test_simulation_shifter_left_32_test.v
+module f2_test(input [31:0] IN, input [5:0] SHIFT, output [31:0] OUT);
+
+assign OUT = IN << SHIFT;
+endmodule
+
+// test_simulation_shifter_left_4_test.v
+module f3_test(input [3:0] IN, input [2:0] SHIFT, output [3:0] OUT);
+
+assign OUT = IN << SHIFT;
+endmodule
+
+// test_simulation_shifter_left_64_test.v
+module f4_test(input [63:0] IN, input [6:0] SHIFT, output [63:0] OUT);
+
+assign OUT = IN << SHIFT;
+endmodule
+
+// test_simulation_shifter_left_8_test.v
+module f5_test(input [7:0] IN, input [3:0] SHIFT, output [7:0] OUT);
+
+assign OUT = IN << SHIFT;
+endmodule
+
+// test_simulation_shifter_right_16_test.v
+module f6_test(input [15:0] IN, input [4:0] SHIFT, output [15:0] OUT);
+
+assign OUT = IN >> SHIFT;
+endmodule
+
+// test_simulation_shifter_right_32_test.v
+module f7_test(input [31:0] IN, input [5:0] SHIFT, output [31:0] OUT);
+
+assign OUT = IN >> SHIFT;
+endmodule
+
+// test_simulation_shifter_right_4_test.v
+module f8_test(input [3:0] IN, input [2:0] SHIFT, output [3:0] OUT);
+
+assign OUT = IN >> SHIFT;
+endmodule
+
+// test_simulation_shifter_right_64_test.v
+module f9_test(input [63:0] IN, input [6:0] SHIFT, output [63:0] OUT);
+
+assign OUT = IN >> SHIFT;
+endmodule
+
+// test_simulation_shifter_right_8_test.v
+module f10_test(input [7:0] IN, input [3:0] SHIFT, output [7:0] OUT);
+
+assign OUT = IN >> SHIFT;
+endmodule
diff --git a/tests/hana/test_simulation_shifter_left_16_test.v b/tests/hana/test_simulation_shifter_left_16_test.v
deleted file mode 100644
index a57dac49..00000000
--- a/tests/hana/test_simulation_shifter_left_16_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input [15:0] IN, input [4:0] SHIFT, output [15:0] OUT);
-
-assign OUT = IN << SHIFT;
-endmodule
diff --git a/tests/hana/test_simulation_shifter_left_32_test.v b/tests/hana/test_simulation_shifter_left_32_test.v
deleted file mode 100644
index 672938ac..00000000
--- a/tests/hana/test_simulation_shifter_left_32_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input [31:0] IN, input [5:0] SHIFT, output [31:0] OUT);
-
-assign OUT = IN << SHIFT;
-endmodule
diff --git a/tests/hana/test_simulation_shifter_left_4_test.v b/tests/hana/test_simulation_shifter_left_4_test.v
deleted file mode 100644
index c525401f..00000000
--- a/tests/hana/test_simulation_shifter_left_4_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input [3:0] IN, input [2:0] SHIFT, output [3:0] OUT);
-
-assign OUT = IN << SHIFT;
-endmodule
diff --git a/tests/hana/test_simulation_shifter_left_64_test.v b/tests/hana/test_simulation_shifter_left_64_test.v
deleted file mode 100644
index 276a7c5a..00000000
--- a/tests/hana/test_simulation_shifter_left_64_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input [63:0] IN, input [6:0] SHIFT, output [63:0] OUT);
-
-assign OUT = IN << SHIFT;
-endmodule
diff --git a/tests/hana/test_simulation_shifter_left_8_test.v b/tests/hana/test_simulation_shifter_left_8_test.v
deleted file mode 100644
index c1727700..00000000
--- a/tests/hana/test_simulation_shifter_left_8_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input [7:0] IN, input [3:0] SHIFT, output [7:0] OUT);
-
-assign OUT = IN << SHIFT;
-endmodule
diff --git a/tests/hana/test_simulation_shifter_right_16_test.v b/tests/hana/test_simulation_shifter_right_16_test.v
deleted file mode 100644
index 6152adc0..00000000
--- a/tests/hana/test_simulation_shifter_right_16_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input [15:0] IN, input [4:0] SHIFT, output [15:0] OUT);
-
-assign OUT = IN >> SHIFT;
-endmodule
diff --git a/tests/hana/test_simulation_shifter_right_32_test.v b/tests/hana/test_simulation_shifter_right_32_test.v
deleted file mode 100644
index e910cdd6..00000000
--- a/tests/hana/test_simulation_shifter_right_32_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input [31:0] IN, input [5:0] SHIFT, output [31:0] OUT);
-
-assign OUT = IN >> SHIFT;
-endmodule
diff --git a/tests/hana/test_simulation_shifter_right_4_test.v b/tests/hana/test_simulation_shifter_right_4_test.v
deleted file mode 100644
index 608c196d..00000000
--- a/tests/hana/test_simulation_shifter_right_4_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input [3:0] IN, input [2:0] SHIFT, output [3:0] OUT);
-
-assign OUT = IN >> SHIFT;
-endmodule
diff --git a/tests/hana/test_simulation_shifter_right_64_test.v b/tests/hana/test_simulation_shifter_right_64_test.v
deleted file mode 100644
index c26d5938..00000000
--- a/tests/hana/test_simulation_shifter_right_64_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input [63:0] IN, input [6:0] SHIFT, output [63:0] OUT);
-
-assign OUT = IN >> SHIFT;
-endmodule
diff --git a/tests/hana/test_simulation_shifter_right_8_test.v b/tests/hana/test_simulation_shifter_right_8_test.v
deleted file mode 100644
index a91c594e..00000000
--- a/tests/hana/test_simulation_shifter_right_8_test.v
+++ /dev/null
@@ -1,4 +0,0 @@
-module test(input [7:0] IN, input [3:0] SHIFT, output [7:0] OUT);
-
-assign OUT = IN >> SHIFT;
-endmodule
diff --git a/tests/hana/test_simulation_sop.v b/tests/hana/test_simulation_sop.v
new file mode 100644
index 00000000..79870cf0
--- /dev/null
+++ b/tests/hana/test_simulation_sop.v
@@ -0,0 +1,65 @@
+
+// test_simulation_sop_basic_10_test.v
+module f1_test(input [1:0] in, input select, output reg out);
+
+always @( in or select)
+ case (select)
+ 0: out = in[0];
+ 1: out = in[1];
+ endcase
+endmodule
+
+// test_simulation_sop_basic_11_test.v
+module f2_test(input [3:0] in, input [1:0] select, output reg out);
+
+always @( in or select)
+ case (select)
+ 0: out = in[0];
+ 1: out = in[1];
+ 2: out = in[2];
+ 3: out = in[3];
+ endcase
+endmodule
+
+// test_simulation_sop_basic_12_test.v
+module f3_test(input [7:0] in, input [2:0] select, output reg out);
+
+always @( in or select)
+ case (select)
+ 0: out = in[0];
+ 1: out = in[1];
+ 2: out = in[2];
+ 3: out = in[3];
+ 4: out = in[4];
+ 5: out = in[5];
+ 6: out = in[6];
+ 7: out = in[7];
+ endcase
+endmodule
+
+// test_simulation_sop_basic_18_test.v
+module f4_test(input [7:0] in, output out);
+
+assign out = ~^in;
+
+endmodule
+
+// test_simulation_sop_basic_3_test.v
+module f5_test(input in, output out);
+assign out = ~in;
+endmodule
+
+// test_simulation_sop_basic_7_test.v
+module f6_test(input in, output out);
+assign out = in;
+endmodule
+
+// test_simulation_sop_basic_8_test.v
+module f7_test(output out);
+assign out = 1'b0;
+endmodule
+
+// test_simulation_sop_basic_9_test.v
+module f8_test(input in, output out);
+assign out = ~in;
+endmodule
diff --git a/tests/hana/test_simulation_sop_basic_10_test.v b/tests/hana/test_simulation_sop_basic_10_test.v
deleted file mode 100644
index bc676c70..00000000
--- a/tests/hana/test_simulation_sop_basic_10_test.v
+++ /dev/null
@@ -1,8 +0,0 @@
-module test(input [1:0] in, input select, output reg out);
-
-always @( in or select)
- case (select)
- 0: out = in[0];
- 1: out = in[1];
- endcase
-endmodule
diff --git a/tests/hana/test_simulation_sop_basic_11_test.v b/tests/hana/test_simulation_sop_basic_11_test.v
deleted file mode 100644
index 6a112c6a..00000000
--- a/tests/hana/test_simulation_sop_basic_11_test.v
+++ /dev/null
@@ -1,10 +0,0 @@
-module test(input [3:0] in, input [1:0] select, output reg out);
-
-always @( in or select)
- case (select)
- 0: out = in[0];
- 1: out = in[1];
- 2: out = in[2];
- 3: out = in[3];
- endcase
-endmodule
diff --git a/tests/hana/test_simulation_sop_basic_12_test.v b/tests/hana/test_simulation_sop_basic_12_test.v
deleted file mode 100644
index f53a2c57..00000000
--- a/tests/hana/test_simulation_sop_basic_12_test.v
+++ /dev/null
@@ -1,14 +0,0 @@
-module test(input [7:0] in, input [2:0] select, output reg out);
-
-always @( in or select)
- case (select)
- 0: out = in[0];
- 1: out = in[1];
- 2: out = in[2];
- 3: out = in[3];
- 4: out = in[4];
- 5: out = in[5];
- 6: out = in[6];
- 7: out = in[7];
- endcase
-endmodule
diff --git a/tests/hana/test_simulation_sop_basic_18_test.v b/tests/hana/test_simulation_sop_basic_18_test.v
deleted file mode 100644
index 03fc35b3..00000000
--- a/tests/hana/test_simulation_sop_basic_18_test.v
+++ /dev/null
@@ -1,5 +0,0 @@
-module test(input [7:0] in, output out);
-
-assign out = ~^in;
-
-endmodule
diff --git a/tests/hana/test_simulation_sop_basic_3_test.v b/tests/hana/test_simulation_sop_basic_3_test.v
deleted file mode 100644
index 81759c25..00000000
--- a/tests/hana/test_simulation_sop_basic_3_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input in, output out);
-assign out = ~in;
-endmodule
diff --git a/tests/hana/test_simulation_sop_basic_7_test.v b/tests/hana/test_simulation_sop_basic_7_test.v
deleted file mode 100644
index e9bb7f61..00000000
--- a/tests/hana/test_simulation_sop_basic_7_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input in, output out);
-assign out = in;
-endmodule
diff --git a/tests/hana/test_simulation_sop_basic_8_test.v b/tests/hana/test_simulation_sop_basic_8_test.v
deleted file mode 100644
index a51ead0b..00000000
--- a/tests/hana/test_simulation_sop_basic_8_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(output out);
-assign out = 1'b0;
-endmodule
diff --git a/tests/hana/test_simulation_sop_basic_9_test.v b/tests/hana/test_simulation_sop_basic_9_test.v
deleted file mode 100644
index 81759c25..00000000
--- a/tests/hana/test_simulation_sop_basic_9_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input in, output out);
-assign out = ~in;
-endmodule
diff --git a/tests/hana/test_simulation_techmap_mux_128_test.v b/tests/hana/test_simulation_techmap.v
index 544c016a..88e24d0e 100644
--- a/tests/hana/test_simulation_techmap_mux_128_test.v
+++ b/tests/hana/test_simulation_techmap.v
@@ -1,4 +1,26 @@
-module test(input [127:0] in, input [6:0] select, output reg out);
+
+// test_simulation_techmap_buf_test.v
+module f1_test(input in, output out);
+assign out = in;
+endmodule
+
+// test_simulation_techmap_inv_test.v
+module f2_test(input in, output out);
+assign out = ~in;
+endmodule
+
+// test_simulation_techmap_mux_0_test.v
+module f3_test(input [1:0] in, input select, output reg out);
+
+always @( in or select)
+ case (select)
+ 0: out = in[0];
+ 1: out = in[1];
+ endcase
+endmodule
+
+// test_simulation_techmap_mux_128_test.v
+module f4_test(input [127:0] in, input [6:0] select, output reg out);
always @( in or select)
case (select)
@@ -132,3 +154,19 @@ always @( in or select)
127: out = in[127];
endcase
endmodule
+
+// test_simulation_techmap_mux_8_test.v
+module f5_test(input [7:0] in, input [2:0] select, output reg out);
+
+always @( in or select)
+ case (select)
+ 0: out = in[0];
+ 1: out = in[1];
+ 2: out = in[2];
+ 3: out = in[3];
+ 4: out = in[4];
+ 5: out = in[5];
+ 6: out = in[6];
+ 7: out = in[7];
+ endcase
+endmodule
diff --git a/tests/hana/test_simulation_techmap_and_19_tech.v b/tests/hana/test_simulation_techmap_and_19_tech.v
deleted file mode 100644
index 2491087c..00000000
--- a/tests/hana/test_simulation_techmap_and_19_tech.v
+++ /dev/null
@@ -1,7 +0,0 @@
-module TECH_AND18(input [17:0] in, output out);
-assign out = &in;
-endmodule
-
-module TECH_AND4(input [3:0] in, output out);
-assign out = &in;
-endmodule
diff --git a/tests/hana/test_simulation_techmap_and_5_tech.v b/tests/hana/test_simulation_techmap_and_5_tech.v
deleted file mode 100644
index 6ec6a61c..00000000
--- a/tests/hana/test_simulation_techmap_and_5_tech.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module TECH_AND5(input [4:0] in, output out);
-assign out = &in;
-endmodule
diff --git a/tests/hana/test_simulation_techmap_buf_test.v b/tests/hana/test_simulation_techmap_buf_test.v
deleted file mode 100644
index e9bb7f61..00000000
--- a/tests/hana/test_simulation_techmap_buf_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input in, output out);
-assign out = in;
-endmodule
diff --git a/tests/hana/test_simulation_techmap_inv_test.v b/tests/hana/test_simulation_techmap_inv_test.v
deleted file mode 100644
index 81759c25..00000000
--- a/tests/hana/test_simulation_techmap_inv_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input in, output out);
-assign out = ~in;
-endmodule
diff --git a/tests/hana/test_simulation_techmap_mux_0_test.v b/tests/hana/test_simulation_techmap_mux_0_test.v
deleted file mode 100644
index bc676c70..00000000
--- a/tests/hana/test_simulation_techmap_mux_0_test.v
+++ /dev/null
@@ -1,8 +0,0 @@
-module test(input [1:0] in, input select, output reg out);
-
-always @( in or select)
- case (select)
- 0: out = in[0];
- 1: out = in[1];
- endcase
-endmodule
diff --git a/tests/hana/test_simulation_techmap_mux_8_test.v b/tests/hana/test_simulation_techmap_mux_8_test.v
deleted file mode 100644
index f53a2c57..00000000
--- a/tests/hana/test_simulation_techmap_mux_8_test.v
+++ /dev/null
@@ -1,14 +0,0 @@
-module test(input [7:0] in, input [2:0] select, output reg out);
-
-always @( in or select)
- case (select)
- 0: out = in[0];
- 1: out = in[1];
- 2: out = in[2];
- 3: out = in[3];
- 4: out = in[4];
- 5: out = in[5];
- 6: out = in[6];
- 7: out = in[7];
- endcase
-endmodule
diff --git a/tests/hana/test_simulation_techmap_nand_19_tech.v b/tests/hana/test_simulation_techmap_nand_19_tech.v
deleted file mode 100644
index 6a119e1e..00000000
--- a/tests/hana/test_simulation_techmap_nand_19_tech.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module TECH_NAND18(input [17:0] in, output out);
-assign out = ~(&in);
-endmodule
-
-module TECH_NAND4(input [3:0] in, output out);
-assign out = ~(&in);
-endmodule
-
-module TECH_NAND2(input [1:0] in, output out);
-assign out = ~(&in);
-endmodule
diff --git a/tests/hana/test_simulation_techmap_nand_2_tech.v b/tests/hana/test_simulation_techmap_nand_2_tech.v
deleted file mode 100644
index 6a119e1e..00000000
--- a/tests/hana/test_simulation_techmap_nand_2_tech.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module TECH_NAND18(input [17:0] in, output out);
-assign out = ~(&in);
-endmodule
-
-module TECH_NAND4(input [3:0] in, output out);
-assign out = ~(&in);
-endmodule
-
-module TECH_NAND2(input [1:0] in, output out);
-assign out = ~(&in);
-endmodule
diff --git a/tests/hana/test_simulation_techmap_nand_5_tech.v b/tests/hana/test_simulation_techmap_nand_5_tech.v
deleted file mode 100644
index 6a119e1e..00000000
--- a/tests/hana/test_simulation_techmap_nand_5_tech.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module TECH_NAND18(input [17:0] in, output out);
-assign out = ~(&in);
-endmodule
-
-module TECH_NAND4(input [3:0] in, output out);
-assign out = ~(&in);
-endmodule
-
-module TECH_NAND2(input [1:0] in, output out);
-assign out = ~(&in);
-endmodule
diff --git a/tests/hana/test_simulation_techmap_nor_19_tech.v b/tests/hana/test_simulation_techmap_nor_19_tech.v
deleted file mode 100644
index 89fb2c7e..00000000
--- a/tests/hana/test_simulation_techmap_nor_19_tech.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module TECH_NOR18(input [17:0] in, output out);
-assign out = ~(|in);
-endmodule
-
-module TECH_NOR4(input [3:0] in, output out);
-assign out = ~(|in);
-endmodule
-
-module TECH_NOR2(input [1:0] in, output out);
-assign out = ~(|in);
-endmodule
diff --git a/tests/hana/test_simulation_techmap_nor_2_tech.v b/tests/hana/test_simulation_techmap_nor_2_tech.v
deleted file mode 100644
index 89fb2c7e..00000000
--- a/tests/hana/test_simulation_techmap_nor_2_tech.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module TECH_NOR18(input [17:0] in, output out);
-assign out = ~(|in);
-endmodule
-
-module TECH_NOR4(input [3:0] in, output out);
-assign out = ~(|in);
-endmodule
-
-module TECH_NOR2(input [1:0] in, output out);
-assign out = ~(|in);
-endmodule
diff --git a/tests/hana/test_simulation_techmap_nor_5_tech.v b/tests/hana/test_simulation_techmap_nor_5_tech.v
deleted file mode 100644
index 89fb2c7e..00000000
--- a/tests/hana/test_simulation_techmap_nor_5_tech.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module TECH_NOR18(input [17:0] in, output out);
-assign out = ~(|in);
-endmodule
-
-module TECH_NOR4(input [3:0] in, output out);
-assign out = ~(|in);
-endmodule
-
-module TECH_NOR2(input [1:0] in, output out);
-assign out = ~(|in);
-endmodule
diff --git a/tests/hana/test_simulation_techmap_or_19_tech.v b/tests/hana/test_simulation_techmap_or_19_tech.v
deleted file mode 100644
index 745d7b71..00000000
--- a/tests/hana/test_simulation_techmap_or_19_tech.v
+++ /dev/null
@@ -1,7 +0,0 @@
-module TECH_OR18(input [17:0] in, output out);
-assign out = |in;
-endmodule
-
-module TECH_OR4(input [3:0] in, output out);
-assign out = |in;
-endmodule
diff --git a/tests/hana/test_simulation_techmap_or_5_tech.v b/tests/hana/test_simulation_techmap_or_5_tech.v
deleted file mode 100644
index 05c38b67..00000000
--- a/tests/hana/test_simulation_techmap_or_5_tech.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module TECH_OR5(input [4:0] in, output out);
-assign out = |in;
-endmodule
diff --git a/tests/hana/test_simulation_techmap_tech.v b/tests/hana/test_simulation_techmap_tech.v
new file mode 100644
index 00000000..60aeca5c
--- /dev/null
+++ b/tests/hana/test_simulation_techmap_tech.v
@@ -0,0 +1,143 @@
+
+// test_simulation_techmap_and_19_tech.v
+module f1_TECH_AND18(input [17:0] in, output out);
+assign out = &in;
+endmodule
+
+module f1_TECH_AND4(input [3:0] in, output out);
+assign out = &in;
+endmodule
+
+// test_simulation_techmap_and_5_tech.v
+module f2_TECH_AND5(input [4:0] in, output out);
+assign out = &in;
+endmodule
+
+// test_simulation_techmap_nand_19_tech.v
+module f3_TECH_NAND18(input [17:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+module f3_TECH_NAND4(input [3:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+module f3_TECH_NAND2(input [1:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+// test_simulation_techmap_nand_2_tech.v
+module f4_TECH_NAND18(input [17:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+module f4_TECH_NAND4(input [3:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+module f4_TECH_NAND2(input [1:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+// test_simulation_techmap_nand_5_tech.v
+module f5_TECH_NAND18(input [17:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+module f5_TECH_NAND4(input [3:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+module f5_TECH_NAND2(input [1:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+// test_simulation_techmap_nor_19_tech.v
+module f6_TECH_NOR18(input [17:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+module f6_TECH_NOR4(input [3:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+module f6_TECH_NOR2(input [1:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+// test_simulation_techmap_nor_2_tech.v
+module f7_TECH_NOR18(input [17:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+module f7_TECH_NOR4(input [3:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+module f7_TECH_NOR2(input [1:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+// test_simulation_techmap_nor_5_tech.v
+module f8_TECH_NOR18(input [17:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+module f8_TECH_NOR4(input [3:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+module f8_TECH_NOR2(input [1:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+// test_simulation_techmap_or_19_tech.v
+module f9_TECH_OR18(input [17:0] in, output out);
+assign out = |in;
+endmodule
+
+module f9_TECH_OR4(input [3:0] in, output out);
+assign out = |in;
+endmodule
+
+// test_simulation_techmap_or_5_tech.v
+module f10_TECH_OR5(input [4:0] in, output out);
+assign out = |in;
+endmodule
+
+// test_simulation_techmap_xnor_2_tech.v
+module f11_TECH_XOR5(input [4:0] in, output out);
+assign out = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4];
+endmodule
+module f11_TECH_XOR2(input [1:0] in, output out);
+assign out = in[0] ^ in[1];
+endmodule
+
+// test_simulation_techmap_xnor_5_tech.v
+module f12_TECH_XOR5(input [4:0] in, output out);
+assign out = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4];
+endmodule
+module f12_TECH_XOR2(input [1:0] in, output out);
+assign out = in[0] ^ in[1];
+endmodule
+
+// test_simulation_techmap_xor_19_tech.v
+module f13_TECH_XOR2(input [1:0] in, output out);
+assign out = in[0] ^ in[1];
+endmodule
+
+// test_simulation_techmap_xor_2_tech.v
+module f14_TECH_XOR5(input [4:0] in, output out);
+assign out = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4];
+endmodule
+module f14_TECH_XOR2(input [1:0] in, output out);
+assign out = in[0] ^ in[1];
+endmodule
+
+// test_simulation_techmap_xor_5_tech.v
+module f15_TECH_XOR5(input [4:0] in, output out);
+assign out = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4];
+endmodule
+module f15_TECH_XOR2(input [1:0] in, output out);
+assign out = in[0] ^ in[1];
+endmodule
diff --git a/tests/hana/test_simulation_techmap_xnor_2_tech.v b/tests/hana/test_simulation_techmap_xnor_2_tech.v
deleted file mode 100644
index 4eb05683..00000000
--- a/tests/hana/test_simulation_techmap_xnor_2_tech.v
+++ /dev/null
@@ -1,6 +0,0 @@
-module TECH_XOR5(input [4:0] in, output out);
-assign out = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4];
-endmodule
-module TECH_XOR2(input [1:0] in, output out);
-assign out = in[0] ^ in[1];
-endmodule
diff --git a/tests/hana/test_simulation_techmap_xnor_5_tech.v b/tests/hana/test_simulation_techmap_xnor_5_tech.v
deleted file mode 100644
index 4eb05683..00000000
--- a/tests/hana/test_simulation_techmap_xnor_5_tech.v
+++ /dev/null
@@ -1,6 +0,0 @@
-module TECH_XOR5(input [4:0] in, output out);
-assign out = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4];
-endmodule
-module TECH_XOR2(input [1:0] in, output out);
-assign out = in[0] ^ in[1];
-endmodule
diff --git a/tests/hana/test_simulation_techmap_xor_19_tech.v b/tests/hana/test_simulation_techmap_xor_19_tech.v
deleted file mode 100644
index 2042a0ad..00000000
--- a/tests/hana/test_simulation_techmap_xor_19_tech.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module TECH_XOR2(input [1:0] in, output out);
-assign out = in[0] ^ in[1];
-endmodule
diff --git a/tests/hana/test_simulation_techmap_xor_2_tech.v b/tests/hana/test_simulation_techmap_xor_2_tech.v
deleted file mode 100644
index 4eb05683..00000000
--- a/tests/hana/test_simulation_techmap_xor_2_tech.v
+++ /dev/null
@@ -1,6 +0,0 @@
-module TECH_XOR5(input [4:0] in, output out);
-assign out = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4];
-endmodule
-module TECH_XOR2(input [1:0] in, output out);
-assign out = in[0] ^ in[1];
-endmodule
diff --git a/tests/hana/test_simulation_techmap_xor_5_tech.v b/tests/hana/test_simulation_techmap_xor_5_tech.v
deleted file mode 100644
index 4eb05683..00000000
--- a/tests/hana/test_simulation_techmap_xor_5_tech.v
+++ /dev/null
@@ -1,6 +0,0 @@
-module TECH_XOR5(input [4:0] in, output out);
-assign out = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4];
-endmodule
-module TECH_XOR2(input [1:0] in, output out);
-assign out = in[0] ^ in[1];
-endmodule
diff --git a/tests/hana/test_simulation_tribuf_2_test.v b/tests/hana/test_simulation_tribuf_2_test.v
deleted file mode 100644
index 1e82aaf0..00000000
--- a/tests/hana/test_simulation_tribuf_2_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [1:0] in, input enable, output [1:0] out);
-assign out = enable ? in : 2'bzz;
-endmodule
diff --git a/tests/hana/test_simulation_always_31_tt.v b/tests/hana/test_simulation_vlib.v
index 299c0ca4..7d3af09c 100644
--- a/tests/hana/test_simulation_always_31_tt.v
+++ b/tests/hana/test_simulation_vlib.v
@@ -1,4 +1,19 @@
-module test(clk, cond, data);
+// test_simulation_mod_1_xx.v
+module f1_test(in1, in2, out);
+input in1;
+input in2;
+output out;
+
+wire synth_net_0;
+wire synth_net_1;
+BUF synth_BUF_0(.in(synth_net_1), .out(out
+ ));
+DIV1 synth_DIV(.in1(in1), .in2(in2), .rem(synth_net_0), .out(synth_net_1
+ ));
+endmodule
+
+// test_simulation_always_31_tt.v
+module f2_test(clk, cond, data);
input cond;
input clk;
output data;
diff --git a/tests/hana/test_simulation_xnor.v b/tests/hana/test_simulation_xnor.v
new file mode 100644
index 00000000..7286d134
--- /dev/null
+++ b/tests/hana/test_simulation_xnor.v
@@ -0,0 +1,20 @@
+
+// test_simulation_xnor_1_test.v
+module f1_test(input [1:0] in, output out);
+assign out = ~(in[0] ^ in[1]);
+endmodule
+
+// test_simulation_xnor_2_test.v
+module f2_test(input [2:0] in, output out);
+assign out = ~(in[0] ^ in[1] ^ in[2]);
+endmodule
+
+// test_simulation_xnor_3_test.v
+module f3_test(input [3:0] in, output out);
+assign out = ~(in[0] ^ in[1] ^ in[2] ^ in[3]);
+endmodule
+
+// test_simulation_xnor_4_test.v
+module f4_test(input [3:0] in, output out);
+xnor myxnor(out, in[0], in[1], in[2], in[3]);
+endmodule
diff --git a/tests/hana/test_simulation_xnor_1_test.v b/tests/hana/test_simulation_xnor_1_test.v
deleted file mode 100644
index adc6ae5c..00000000
--- a/tests/hana/test_simulation_xnor_1_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [1:0] in, output out);
-assign out = ~(in[0] ^ in[1]);
-endmodule
diff --git a/tests/hana/test_simulation_xnor_2_test.v b/tests/hana/test_simulation_xnor_2_test.v
deleted file mode 100644
index 701bcc77..00000000
--- a/tests/hana/test_simulation_xnor_2_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [2:0] in, output out);
-assign out = ~(in[0] ^ in[1] ^ in[2]);
-endmodule
diff --git a/tests/hana/test_simulation_xnor_3_test.v b/tests/hana/test_simulation_xnor_3_test.v
deleted file mode 100644
index a8c87cc6..00000000
--- a/tests/hana/test_simulation_xnor_3_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [3:0] in, output out);
-assign out = ~(in[0] ^ in[1] ^ in[2] ^ in[3]);
-endmodule
diff --git a/tests/hana/test_simulation_xnor_4_test.v b/tests/hana/test_simulation_xnor_4_test.v
deleted file mode 100644
index fa671ff9..00000000
--- a/tests/hana/test_simulation_xnor_4_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [3:0] in, output out);
-xnor myxnor(out, in[0], in[1], in[2], in[3]);
-endmodule
diff --git a/tests/hana/test_simulation_xor.v b/tests/hana/test_simulation_xor.v
new file mode 100644
index 00000000..e181dd83
--- /dev/null
+++ b/tests/hana/test_simulation_xor.v
@@ -0,0 +1,20 @@
+
+// test_simulation_xor_1_test.v
+module f1_test(input [1:0] in, output out);
+assign out = (in[0] ^ in[1]);
+endmodule
+
+// test_simulation_xor_2_test.v
+module f2_test(input [2:0] in, output out);
+assign out = (in[0] ^ in[1] ^ in[2]);
+endmodule
+
+// test_simulation_xor_3_test.v
+module f3_test(input [3:0] in, output out);
+assign out = (in[0] ^ in[1] ^ in[2] ^ in[3]);
+endmodule
+
+// test_simulation_xor_4_test.v
+module f4_test(input [3:0] in, output out);
+xor myxor(out, in[0], in[1], in[2], in[3]);
+endmodule
diff --git a/tests/hana/test_simulation_xor_1_test.v b/tests/hana/test_simulation_xor_1_test.v
deleted file mode 100644
index f6447f81..00000000
--- a/tests/hana/test_simulation_xor_1_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [1:0] in, output out);
-assign out = (in[0] ^ in[1]);
-endmodule
diff --git a/tests/hana/test_simulation_xor_2_test.v b/tests/hana/test_simulation_xor_2_test.v
deleted file mode 100644
index d94081df..00000000
--- a/tests/hana/test_simulation_xor_2_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [2:0] in, output out);
-assign out = (in[0] ^ in[1] ^ in[2]);
-endmodule
diff --git a/tests/hana/test_simulation_xor_3_test.v b/tests/hana/test_simulation_xor_3_test.v
deleted file mode 100644
index cfa13187..00000000
--- a/tests/hana/test_simulation_xor_3_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [3:0] in, output out);
-assign out = (in[0] ^ in[1] ^ in[2] ^ in[3]);
-endmodule
diff --git a/tests/hana/test_simulation_xor_4_test.v b/tests/hana/test_simulation_xor_4_test.v
deleted file mode 100644
index be6cab63..00000000
--- a/tests/hana/test_simulation_xor_4_test.v
+++ /dev/null
@@ -1,3 +0,0 @@
-module test(input [3:0] in, output out);
-xor myxor(out, in[0], in[1], in[2], in[3]);
-endmodule
diff --git a/tests/memories/.gitignore b/tests/memories/.gitignore
new file mode 100644
index 00000000..90a0983a
--- /dev/null
+++ b/tests/memories/.gitignore
@@ -0,0 +1,3 @@
+*.log
+*.out
+*.dmp
diff --git a/tests/memories/amber23_sram_byte_en.v b/tests/memories/amber23_sram_byte_en.v
new file mode 100644
index 00000000..3554af88
--- /dev/null
+++ b/tests/memories/amber23_sram_byte_en.v
@@ -0,0 +1,84 @@
+//////////////////////////////////////////////////////////////////
+// //
+// Generic Library SRAM with per byte write enable //
+// //
+// This file is part of the Amber project //
+// http://www.opencores.org/project,amber //
+// //
+// Description //
+// Configurable depth and width. The DATA_WIDTH must be a //
+// multiple of 8. //
+// //
+// Author(s): //
+// - Conor Santifort, csantifort.amber@gmail.com //
+// //
+//////////////////////////////////////////////////////////////////
+// //
+// Copyright (C) 2010 Authors and OPENCORES.ORG //
+// //
+// This source file may be used and distributed without //
+// restriction provided that this copyright statement is not //
+// removed from the file and that any derivative work contains //
+// the original copyright notice and the associated disclaimer. //
+// //
+// This source file is free software; you can redistribute it //
+// and/or modify it under the terms of the GNU Lesser General //
+// Public License as published by the Free Software Foundation; //
+// either version 2.1 of the License, or (at your option) any //
+// later version. //
+// //
+// This source is distributed in the hope that it will be //
+// useful, but WITHOUT ANY WARRANTY; without even the implied //
+// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
+// PURPOSE. See the GNU Lesser General Public License for more //
+// details. //
+// //
+// You should have received a copy of the GNU Lesser General //
+// Public License along with this source; if not, download it //
+// from http://www.opencores.org/lgpl.shtml //
+// //
+//////////////////////////////////////////////////////////////////
+
+// expect-wr-ports 1
+// expect-rd-ports 1
+
+module generic_sram_byte_en
+#(
+parameter DATA_WIDTH = 32,
+parameter ADDRESS_WIDTH = 4
+)
+
+(
+input i_clk,
+input [DATA_WIDTH-1:0] i_write_data,
+input i_write_enable,
+input [ADDRESS_WIDTH-1:0] i_address,
+input [DATA_WIDTH/8-1:0] i_byte_enable,
+output reg [DATA_WIDTH-1:0] o_read_data
+ );
+
+reg [DATA_WIDTH-1:0] mem [0:2**ADDRESS_WIDTH-1];
+integer i;
+
+always @(posedge i_clk)
+ begin
+ // read
+ o_read_data <= i_write_enable ? {DATA_WIDTH{1'd0}} : mem[i_address];
+
+ // write
+ if (i_write_enable)
+ for (i=0;i<DATA_WIDTH/8;i=i+1)
+ begin
+ mem[i_address][i*8+0] <= i_byte_enable[i] ? i_write_data[i*8+0] : mem[i_address][i*8+0] ;
+ mem[i_address][i*8+1] <= i_byte_enable[i] ? i_write_data[i*8+1] : mem[i_address][i*8+1] ;
+ mem[i_address][i*8+2] <= i_byte_enable[i] ? i_write_data[i*8+2] : mem[i_address][i*8+2] ;
+ mem[i_address][i*8+3] <= i_byte_enable[i] ? i_write_data[i*8+3] : mem[i_address][i*8+3] ;
+ mem[i_address][i*8+4] <= i_byte_enable[i] ? i_write_data[i*8+4] : mem[i_address][i*8+4] ;
+ mem[i_address][i*8+5] <= i_byte_enable[i] ? i_write_data[i*8+5] : mem[i_address][i*8+5] ;
+ mem[i_address][i*8+6] <= i_byte_enable[i] ? i_write_data[i*8+6] : mem[i_address][i*8+6] ;
+ mem[i_address][i*8+7] <= i_byte_enable[i] ? i_write_data[i*8+7] : mem[i_address][i*8+7] ;
+ end
+ end
+
+endmodule
+
diff --git a/tests/memories/implicit_en.v b/tests/memories/implicit_en.v
new file mode 100644
index 00000000..cfce378b
--- /dev/null
+++ b/tests/memories/implicit_en.v
@@ -0,0 +1,24 @@
+// expect-wr-ports 1
+// expect-rd-ports 1
+
+module test(clk, rd_addr, rd_data, wr_addr, wr_en, wr_data);
+
+input clk;
+
+input [3:0] rd_addr;
+output reg [31:0] rd_data;
+
+input [3:0] wr_addr, wr_en;
+input [31:0] wr_data;
+
+reg [31:0] mem [0:15];
+
+always @(posedge clk) begin
+ mem[wr_addr][ 7: 0] <= wr_en[0] ? wr_data[ 7: 0] : mem[wr_addr][ 7: 0];
+ mem[wr_addr][15: 8] <= wr_en[1] ? wr_data[15: 8] : mem[wr_addr][15: 8];
+ mem[wr_addr][23:16] <= wr_en[2] ? wr_data[23:16] : mem[wr_addr][23:16];
+ mem[wr_addr][31:24] <= wr_en[3] ? wr_data[31:24] : mem[wr_addr][31:24];
+ rd_data <= mem[rd_addr];
+end
+
+endmodule
diff --git a/tests/memories/no_implicit_en.v b/tests/memories/no_implicit_en.v
new file mode 100644
index 00000000..0e96e4ae
--- /dev/null
+++ b/tests/memories/no_implicit_en.v
@@ -0,0 +1,24 @@
+// expect-wr-ports 1
+// expect-rd-ports 2
+
+module test(clk, rd_addr, rd_data, cp_addr, wr_addr, wr_en, wr_data);
+
+input clk;
+
+input [3:0] rd_addr;
+output reg [31:0] rd_data;
+
+input [3:0] cp_addr, wr_addr, wr_en;
+input [31:0] wr_data;
+
+reg [31:0] mem [0:15];
+
+always @(posedge clk) begin
+ mem[wr_addr][ 7: 0] <= wr_en[0] ? wr_data[ 7: 0] : mem[cp_addr][ 7: 0];
+ mem[wr_addr][15: 8] <= wr_en[1] ? wr_data[15: 8] : mem[cp_addr][15: 8];
+ mem[wr_addr][23:16] <= wr_en[2] ? wr_data[23:16] : mem[cp_addr][23:16];
+ mem[wr_addr][31:24] <= wr_en[3] ? wr_data[31:24] : mem[cp_addr][31:24];
+ rd_data <= mem[rd_addr];
+end
+
+endmodule
diff --git a/tests/memories/run-test.sh b/tests/memories/run-test.sh
new file mode 100755
index 00000000..c3b19618
--- /dev/null
+++ b/tests/memories/run-test.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+bash ../tools/autotest.sh -G *.v
+
+for f in `egrep -l 'expect-(wr|rd)-ports' *.v`; do
+ echo -n "Testing expectations for $f .."
+ ../../yosys -qp "proc; opt; memory -nomap;; dump -outfile ${f%.v}.dmp t:\$mem" $f
+ if grep -q expect-wr-ports $f; then
+ grep -q "parameter \\\\WR_PORTS $(gawk '/expect-wr-ports/ { print $3; }' $f)\$" ${f%.v}.dmp ||
+ { echo " ERROR: Unexpected number of write ports."; false; }
+ fi
+ if grep -q expect-rd-ports $f; then
+ grep -q "parameter \\\\RD_PORTS $(gawk '/expect-rd-ports/ { print $3; }' $f)\$" ${f%.v}.dmp ||
+ { echo " ERROR: Unexpected number of read ports."; false; }
+ fi
+ echo " ok."
+done
+
diff --git a/tests/memories/shared_ports.v b/tests/memories/shared_ports.v
new file mode 100644
index 00000000..94bad53e
--- /dev/null
+++ b/tests/memories/shared_ports.v
@@ -0,0 +1,25 @@
+// expect-wr-ports 1
+// expect-rd-ports 1
+
+module test(
+ input clk,
+ input wr_en1, wr_en2, wr_en3,
+ input [3:0] wr_addr1, wr_addr2, wr_addr3,
+ input [15:0] wr_data,
+ input [3:0] rd_addr,
+ output reg [31:0] rd_data
+);
+
+reg [31:0] mem [0:15];
+
+always @(posedge clk) begin
+ if (wr_en1)
+ mem[wr_addr1][15:0] <= wr_data;
+ else if (wr_en2)
+ mem[wr_addr2][23:8] <= wr_data;
+ else if (wr_en3)
+ mem[wr_addr3][31:16] <= wr_data;
+ rd_data <= mem[rd_addr];
+end
+
+endmodule
diff --git a/tests/memories/simple_sram_byte_en.v b/tests/memories/simple_sram_byte_en.v
new file mode 100644
index 00000000..dee1d228
--- /dev/null
+++ b/tests/memories/simple_sram_byte_en.v
@@ -0,0 +1,26 @@
+// expect-wr-ports 1
+// expect-rd-ports 1
+
+module generic_sram_byte_en #(
+ parameter DATA_WIDTH = 32,
+ parameter ADDRESS_WIDTH = 4
+) (
+ input i_clk,
+ input [DATA_WIDTH-1:0] i_write_data,
+ input i_write_enable,
+ input [ADDRESS_WIDTH-1:0] i_address,
+ input [DATA_WIDTH/8-1:0] i_byte_enable,
+ output reg [DATA_WIDTH-1:0] o_read_data
+);
+
+reg [DATA_WIDTH-1:0] mem [0:2**ADDRESS_WIDTH-1];
+integer i;
+
+always @(posedge i_clk) begin
+ for (i=0;i<DATA_WIDTH/8;i=i+1)
+ if (i_write_enable && i_byte_enable[i])
+ mem[i_address][i*8 +: 8] <= i_write_data[i*8 +: 8];
+ o_read_data <= mem[i_address];
+end
+
+endmodule
diff --git a/tests/realmath/.gitignore b/tests/realmath/.gitignore
new file mode 100644
index 00000000..9c595a6f
--- /dev/null
+++ b/tests/realmath/.gitignore
@@ -0,0 +1 @@
+temp
diff --git a/tests/realmath/generate.py b/tests/realmath/generate.py
new file mode 100644
index 00000000..972021dc
--- /dev/null
+++ b/tests/realmath/generate.py
@@ -0,0 +1,91 @@
+#!/usr/bin/python
+
+from __future__ import division
+from __future__ import print_function
+
+import sys
+import random
+from contextlib import contextmanager
+
+@contextmanager
+def redirect_stdout(new_target):
+ old_target, sys.stdout = sys.stdout, new_target
+ try:
+ yield new_target
+ finally:
+ sys.stdout = old_target
+
+def random_expression(depth = 3, maxparam = 0):
+ def recursion():
+ return random_expression(depth = depth-1, maxparam = maxparam)
+ if depth == 0:
+ if maxparam != 0 and random.randint(0, 1) != 0:
+ return 'p%02d' % random.randint(0, maxparam-1)
+ return random.choice([ '%e', '%f', '%g' ]) % random.uniform(-2, +2)
+ if random.randint(0, 4) == 0:
+ return recursion() + random.choice([ ' < ', ' <= ', ' == ', ' != ', ' >= ', ' > ' ]) + recursion() + ' ? ' + recursion() + ' : ' + recursion()
+ op_prefix = [ '+(', '-(' ]
+ op_infix = [ ' + ', ' - ', ' * ', ' / ' ]
+ op_func1 = [ '$ln', '$log10', '$exp', '$sqrt', '$floor', '$ceil', '$sin', '$cos', '$tan', '$asin', '$acos', '$atan', '$sinh', '$cosh', '$tanh', '$asinh', '$acosh', '$atanh' ]
+ op_func2 = [ '$pow', '$atan2', '$hypot' ]
+ op = random.choice(op_prefix + op_infix + op_func1 + op_func2)
+ if op in op_prefix:
+ return op + recursion() + ')'
+ if op in op_infix:
+ return '(' + recursion() + op + recursion() + ')'
+ if op in op_func1:
+ return op + '(' + recursion() + ')'
+ if op in op_func2:
+ return op + '(' + recursion() + ', ' + recursion() + ')'
+ raise
+
+for idx in range(100):
+ with file('temp/uut_%05d.v' % idx, 'w') as f, redirect_stdout(f):
+ print('module uut_%05d(output [63:0] %s);\n' % (idx, ', '.join(['y%02d' % i for i in range(100)])))
+ for i in range(30):
+ if idx < 10:
+ print('localparam p%02d = %s;' % (i, random_expression()))
+ else:
+ print('localparam%s p%02d = %s;' % (random.choice(['', ' real', ' integer']), i, random_expression()))
+ for i in range(30, 60):
+ if idx < 10:
+ print('localparam p%02d = %s;' % (i, random_expression(maxparam = 30)))
+ else:
+ print('localparam%s p%02d = %s;' % (random.choice(['', ' real', ' integer']), i, random_expression(maxparam = 30)))
+ for i in range(100):
+ print('assign y%02d = 65536 * (%s);' % (i, random_expression(maxparam = 60)))
+ print('endmodule')
+ with file('temp/uut_%05d.ys' % idx, 'w') as f, redirect_stdout(f):
+ print('read_verilog uut_%05d.v' % idx)
+ print('rename uut_%05d uut_%05d_syn' % (idx, idx))
+ print('write_verilog uut_%05d_syn.v' % idx)
+ with file('temp/uut_%05d_tb.v' % idx, 'w') as f, redirect_stdout(f):
+ print('module uut_%05d_tb;\n' % idx)
+ print('wire [63:0] %s;' % (', '.join(['r%02d' % i for i in range(100)])))
+ print('wire [63:0] %s;' % (', '.join(['s%02d' % i for i in range(100)])))
+ print('uut_%05d ref(%s);' % (idx, ', '.join(['r%02d' % i for i in range(100)])))
+ print('uut_%05d_syn syn(%s);' % (idx, ', '.join(['s%02d' % i for i in range(100)])))
+ print('task compare_ref_syn;')
+ print(' input [7:0] i;')
+ print(' input [63:0] r, s;')
+ print(' reg [64*8-1:0] buffer;')
+ print(' integer j;')
+ print(' begin')
+ print(' if (-1 <= $signed(r-s) && $signed(r-s) <= +1) begin')
+ print(' // $display("%d: %b %b", i, r, s);')
+ print(' end else if (r === s) begin ')
+ print(' // $display("%d: %b %b", i, r, s);')
+ print(' end else begin ')
+ print(' for (j = 0; j < 64; j = j+1)')
+ print(' buffer[j*8 +: 8] = r[j] !== s[j] ? "^" : " ";')
+ print(' $display("\\n%3d: %b %b", i, r, s);')
+ print(' $display(" %s %s", buffer, buffer);')
+ print(' end')
+ print(' end')
+ print('endtask')
+ print('initial begin #1;')
+ for i in range(100):
+ print(' compare_ref_syn(%2d, r%02d, s%02d);' % (i, i, i))
+ print('end')
+ print('endmodule')
+
diff --git a/tests/realmath/run-test.sh b/tests/realmath/run-test.sh
new file mode 100755
index 00000000..b8e222ad
--- /dev/null
+++ b/tests/realmath/run-test.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+set -e
+
+rm -rf temp
+mkdir -p temp
+echo "generating tests.."
+python generate.py
+
+cd temp
+echo "running tests.."
+for ((i = 0; i < 100; i++)); do
+ echo -n "[$i]"
+ idx=$( printf "%05d" $i )
+ ../../../yosys -q uut_${idx}.ys
+ iverilog -o uut_${idx}_tb uut_${idx}_tb.v uut_${idx}.v uut_${idx}_syn.v
+ ./uut_${idx}_tb | tee uut_${idx}.err
+ if test -s uut_${idx}.err; then
+ echo "Note: Make sure that 'iverilog' is an up-to-date git checkout of icarus verilog."
+ exit 1
+ fi
+ rm -f uut_${idx}.err
+done
+echo
+
diff --git a/tests/sat/asserts.ys b/tests/sat/asserts.ys
index de5e7c9a..d8f99492 100644
--- a/tests/sat/asserts.ys
+++ b/tests/sat/asserts.ys
@@ -1,3 +1,3 @@
-read_verilog asserts.v
+read_verilog -sv asserts.v
hierarchy; proc; opt
sat -verify -seq 1 -set-at 1 rst 1 -tempinduct -prove-asserts
diff --git a/tests/sat/asserts_seq.ys b/tests/sat/asserts_seq.ys
index c622ef61..e9768664 100644
--- a/tests/sat/asserts_seq.ys
+++ b/tests/sat/asserts_seq.ys
@@ -1,4 +1,4 @@
-read_verilog asserts_seq.v
+read_verilog -sv asserts_seq.v
hierarchy; proc; opt
sat -verify -prove-asserts -tempinduct -seq 1 test_001
diff --git a/tests/sat/initval.v b/tests/sat/initval.v
new file mode 100644
index 00000000..5b661f8d
--- /dev/null
+++ b/tests/sat/initval.v
@@ -0,0 +1,15 @@
+module test(input clk, input [3:0] bar, output [3:0] foo);
+ reg [3:0] foo = 0;
+ reg [3:0] last_bar = 0;
+
+ always @*
+ foo[1:0] <= bar[1:0];
+
+ always @(posedge clk)
+ foo[3:2] <= bar[3:2];
+
+ always @(posedge clk)
+ last_bar <= bar;
+
+ assert property (foo == {last_bar[3:2], bar[1:0]});
+endmodule
diff --git a/tests/sat/initval.ys b/tests/sat/initval.ys
new file mode 100644
index 00000000..2079d2f3
--- /dev/null
+++ b/tests/sat/initval.ys
@@ -0,0 +1,4 @@
+read_verilog -sv initval.v
+proc;;
+
+sat -seq 10 -prove-asserts
diff --git a/tests/sat/share.v b/tests/sat/share.v
new file mode 100644
index 00000000..e06fc8f1
--- /dev/null
+++ b/tests/sat/share.v
@@ -0,0 +1,32 @@
+module test_1(
+ input [7:0] a, b, c,
+ input s, x,
+ output [7:0] y1, y2
+);
+ wire [7:0] t1, t2;
+ assign t1 = s ? a*b : 0, t2 = !s ? b*c : 0;
+ assign y1 = x ? t2 : t1, y2 = x ? t1 : t2;
+endmodule
+
+
+module test_2(
+ input s,
+ input [7:0] a, b, c,
+ output reg [7:0] y
+);
+ always @* begin
+ y <= 'bx;
+ if (s) begin
+ if (a * b > 8)
+ y <= b / c;
+ else
+ y <= c / b;
+ end else begin
+ if (b * c > 8)
+ y <= a / b;
+ else
+ y <= b / a;
+ end
+ end
+endmodule
+
diff --git a/tests/sat/share.ys b/tests/sat/share.ys
new file mode 100644
index 00000000..f2f5d649
--- /dev/null
+++ b/tests/sat/share.ys
@@ -0,0 +1,17 @@
+read_verilog share.v
+proc;;
+
+copy test_1 gold_1
+copy test_2 gold_2
+share test_1 test_2;;
+
+select -assert-count 1 test_1/t:$mul
+select -assert-count 1 test_2/t:$mul
+select -assert-count 1 test_2/t:$div
+
+miter -equiv -flatten -make_outputs -make_outcmp gold_1 test_1 miter_1
+sat -verify -prove trigger 0 -show-inputs -show-outputs miter_1
+
+miter -equiv -flatten -make_outputs -make_outcmp gold_2 test_2 miter_2
+sat -verify -prove trigger 0 -show-inputs -show-outputs miter_2
+
diff --git a/tests/share/.gitignore b/tests/share/.gitignore
new file mode 100644
index 00000000..9c595a6f
--- /dev/null
+++ b/tests/share/.gitignore
@@ -0,0 +1 @@
+temp
diff --git a/tests/share/generate.py b/tests/share/generate.py
new file mode 100644
index 00000000..a06a642d
--- /dev/null
+++ b/tests/share/generate.py
@@ -0,0 +1,73 @@
+#!/usr/bin/python
+
+from __future__ import division
+from __future__ import print_function
+
+import sys
+import random
+from contextlib import contextmanager
+
+@contextmanager
+def redirect_stdout(new_target):
+ old_target, sys.stdout = sys.stdout, new_target
+ try:
+ yield new_target
+ finally:
+ sys.stdout = old_target
+
+def random_plus_x():
+ return "%s x" % random.choice(['+', '+', '+', '-', '-', '|', '&', '^'])
+
+def maybe_plus_x(expr):
+ if random.randint(0, 4) == 0:
+ return "(%s %s)" % (expr, random_plus_x())
+ else:
+ return expr
+
+for idx in range(100):
+ with file('temp/uut_%05d.v' % idx, 'w') as f, redirect_stdout(f):
+ if random.choice(['bin', 'uni']) == 'bin':
+ print('module uut_%05d(a, b, c, d, x, s, y);' % (idx))
+ op = random.choice([
+ random.choice(['+', '-', '*', '/', '%']),
+ random.choice(['<', '<=', '==', '!=', '===', '!==', '>=', '>' ]),
+ random.choice(['<<', '>>', '<<<', '>>>']),
+ random.choice(['|', '&', '^', '~^', '||', '&&']),
+ ])
+ print(' input%s [%d:0] a;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input%s [%d:0] b;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input%s [%d:0] c;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input%s [%d:0] d;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input%s [%d:0] x;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input s;')
+ print(' output [%d:0] y;' % random.randint(0, 8))
+ print(' assign y = (s ? %s(%s %s %s) : %s(%s %s %s))%s;' %
+ (random.choice(['', '$signed', '$unsigned']), maybe_plus_x('a'), op, maybe_plus_x('b'),
+ random.choice(['', '$signed', '$unsigned']), maybe_plus_x('c'), op, maybe_plus_x('d'),
+ random_plus_x() if random.randint(0, 4) == 0 else ''))
+ print('endmodule')
+ else:
+ print('module uut_%05d(a, b, x, s, y);' % (idx))
+ op = random.choice(['~', '-', '!'])
+ print(' input%s [%d:0] a;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input%s [%d:0] b;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input%s [%d:0] x;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input s;')
+ print(' output [%d:0] y;' % random.randint(0, 8))
+ print(' assign y = (s ? %s(%s%s) : %s(%s%s))%s;' %
+ (random.choice(['', '$signed', '$unsigned']), op, maybe_plus_x('a'),
+ random.choice(['', '$signed', '$unsigned']), op, maybe_plus_x('b'),
+ random_plus_x() if random.randint(0, 4) == 0 else ''))
+ print('endmodule')
+ with file('temp/uut_%05d.ys' % idx, 'w') as f, redirect_stdout(f):
+ print('read_verilog temp/uut_%05d.v' % idx)
+ print('proc;;')
+ print('copy uut_%05d gold' % idx)
+ print('rename uut_%05d gate' % idx)
+ print('tee -a temp/all_share_log.txt log')
+ print('tee -a temp/all_share_log.txt log #job# uut_%05d' % idx)
+ print('tee -a temp/all_share_log.txt wreduce')
+ print('tee -a temp/all_share_log.txt share -aggressive gate')
+ print('miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter')
+ print('sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter')
+
diff --git a/tests/share/run-test.sh b/tests/share/run-test.sh
new file mode 100755
index 00000000..203d6fcd
--- /dev/null
+++ b/tests/share/run-test.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# run this test many times:
+# time bash -c 'for ((i=0; i<100; i++)); do echo "-- $i --"; bash run-test.sh || exit 1; done'
+
+set -e
+
+rm -rf temp
+mkdir -p temp
+echo "generating tests.."
+python generate.py
+
+echo "running tests.."
+for i in $( ls temp/*.ys | sed 's,[^0-9],,g; s,^0*\(.\),\1,g;' ); do
+ echo -n "[$i]"
+ idx=$( printf "%05d" $i )
+ ../../yosys -ql temp/uut_${idx}.log temp/uut_${idx}.ys
+done
+echo
+
+failed_share=$( echo $( gawk '/^#job#/ { j=$2; db[j]=0; } /^Removing [24] cells/ { delete db[j]; } END { for (j in db) print(j); }' temp/all_share_log.txt ) )
+if [ -n "$failed_share" ]; then
+ echo "Resource sharing failed for the following test cases: $failed_share"
+ false
+fi
+
+exit 0
diff --git a/tests/simple/arraycells.v b/tests/simple/arraycells.v
new file mode 100644
index 00000000..704ca3fd
--- /dev/null
+++ b/tests/simple/arraycells.v
@@ -0,0 +1,15 @@
+
+module array_test001(a, b, c, y);
+ input a;
+ input [31:0] b, c;
+ input [31:0] y;
+
+ aoi12 p [31:0] (a, b, c, y);
+endmodule
+
+module aoi12(a, b, c, y);
+ input a, b, c;
+ output y;
+ assign y = ~((a & b) | c);
+endmodule
+
diff --git a/tests/simple/forgen01.v b/tests/simple/forgen01.v
index 70ee7e66..8b7aa279 100644
--- a/tests/simple/forgen01.v
+++ b/tests/simple/forgen01.v
@@ -1,3 +1,6 @@
+
+// VERIFIC-SKIP
+
module uut_forgen01(a, y);
input [4:0] a;
diff --git a/tests/simple/fsm.v b/tests/simple/fsm.v
index 79ca041d..2dba14bb 100644
--- a/tests/simple/fsm.v
+++ b/tests/simple/fsm.v
@@ -1,7 +1,7 @@
// `define ASYNC_RESET
-module test(clk, reset, button_a, button_b, red_a, green_a, red_b, green_b);
+module fsm_test(clk, reset, button_a, button_b, red_a, green_a, red_b, green_b);
input clk, reset, button_a, button_b;
output reg red_a, green_a, red_b, green_b;
diff --git a/tests/simple/generate.v b/tests/simple/generate.v
index 39e573a7..24eb4462 100644
--- a/tests/simple/generate.v
+++ b/tests/simple/generate.v
@@ -1,5 +1,5 @@
-module test1(clk, a, b, y);
+module gen_test1(clk, a, b, y);
input clk;
input [7:0] a, b;
@@ -40,7 +40,7 @@ endmodule
// ------------------------------------------
-module test2(clk, a, b, y);
+module gen_test2(clk, a, b, y);
input clk;
input [7:0] a, b;
@@ -67,7 +67,7 @@ endmodule
// ------------------------------------------
-module test3(a, b, sel, y, z);
+module gen_test3(a, b, sel, y, z);
input [3:0] a, b;
input sel;
diff --git a/tests/simple/i2c_master_tests.v b/tests/simple/i2c_master_tests.v
index f8f56408..3aa59663 100644
--- a/tests/simple/i2c_master_tests.v
+++ b/tests/simple/i2c_master_tests.v
@@ -3,7 +3,7 @@
// this core that triggered bugs in early versions of yosys.
// from i2c_master_bit_ctrl
-module test01(clk, rst, nReset, al);
+module i2c_test01(clk, rst, nReset, al);
input clk, rst, nReset;
output reg al;
@@ -26,7 +26,7 @@ module test01(clk, rst, nReset, al);
endmodule
// from i2c_master_bit_ctrl
-module test02(clk, slave_wait, clk_cnt, cmd, cmd_stop, cnt);
+module i2c_test02(clk, slave_wait, clk_cnt, cmd, cmd_stop, cnt);
input clk, slave_wait, clk_cnt;
input cmd;
diff --git a/tests/simple/macros.v b/tests/simple/macros.v
index cda46cb4..7b4d616e 100644
--- a/tests/simple/macros.v
+++ b/tests/simple/macros.v
@@ -235,3 +235,10 @@ always @* begin
end
endmodule
+
+`define SIZE 4 // comment supported in this part
+module test_comment_in_macro ( din_a, dout_a );
+input [`SIZE-1:0] din_a;
+output [`SIZE-1:0] dout_a;
+assign dout_a = din_a | `SIZE'ha;
+endmodule
diff --git a/tests/simple/mem2reg.v b/tests/simple/mem2reg.v
index e2c136dd..bed5528d 100644
--- a/tests/simple/mem2reg.v
+++ b/tests/simple/mem2reg.v
@@ -1,5 +1,5 @@
-module test1(in_addr, in_data, out_addr, out_data);
+module mem2reg_test1(in_addr, in_data, out_addr, out_data);
input [1:0] in_addr, out_addr;
input [3:0] in_data;
@@ -19,7 +19,7 @@ endmodule
// ------------------------------------------------------
-module test2(clk, mode, addr, data);
+module mem2reg_test2(clk, mode, addr, data);
input clk, mode;
input [2:0] addr;
@@ -43,3 +43,15 @@ end
endmodule
+// ------------------------------------------------------
+
+// http://www.reddit.com/r/yosys/comments/28d9lx/problem_with_concatenation_of_two_dimensional/
+module mem2reg_test3( input clk, input [8:0] din_a, output reg [7:0] dout_a, output [7:0] dout_b);
+reg [7:0] dint_c [0:7];
+always @(posedge clk)
+ begin
+ {dout_a[0], dint_c[3]} <= din_a;
+ end
+assign dout_b = dint_c[3];
+endmodule
+
diff --git a/tests/simple/mem_arst.v b/tests/simple/mem_arst.v
index 4022f57c..9bd38fcb 100644
--- a/tests/simple/mem_arst.v
+++ b/tests/simple/mem_arst.v
@@ -10,7 +10,7 @@ module MyMem #(
output [DataWidth-1:0] Data_o,
input WR_i);
- reg Data_o;
+ reg [DataWidth-1:0] Data_o;
localparam Size = 2**AddrWidth;
diff --git a/tests/simple/memory.v b/tests/simple/memory.v
index 927ee043..db06c56d 100644
--- a/tests/simple/memory.v
+++ b/tests/simple/memory.v
@@ -1,5 +1,5 @@
-module test00(clk, setA, setB, y);
+module memtest00(clk, setA, setB, y);
input clk, setA, setB;
output y;
@@ -16,7 +16,7 @@ endmodule
// ----------------------------------------------------------
-module test01(clk, wr_en, wr_addr, wr_value, rd_addr, rd_value);
+module memtest01(clk, wr_en, wr_addr, wr_value, rd_addr, rd_value);
input clk, wr_en;
input [3:0] wr_addr, rd_addr;
@@ -36,7 +36,7 @@ endmodule
// ----------------------------------------------------------
-module test02(clk, setA, setB, addr, bit, y1, y2, y3, y4);
+module memtest02(clk, setA, setB, addr, bit, y1, y2, y3, y4);
input clk, setA, setB;
input [1:0] addr;
@@ -77,7 +77,7 @@ endmodule
// ----------------------------------------------------------
-module test03(clk, wr_addr, wr_data, wr_enable, rd_addr, rd_data);
+module memtest03(clk, wr_addr, wr_data, wr_enable, rd_addr, rd_data);
input clk, wr_enable;
input [3:0] wr_addr, wr_data, rd_addr;
@@ -95,7 +95,7 @@ endmodule
// ----------------------------------------------------------
-module test04(clk, wr_addr, wr_data, wr_enable, rd_addr, rd_data);
+module memtest04(clk, wr_addr, wr_data, wr_enable, rd_addr, rd_data);
input clk, wr_enable;
input [3:0] wr_addr, wr_data, rd_addr;
@@ -114,3 +114,94 @@ assign rd_data = memory[rd_addr_buf];
endmodule
+// ----------------------------------------------------------
+
+module memtest05(clk, addr, wdata, rdata, wen);
+
+input clk;
+input [1:0] addr;
+input [7:0] wdata;
+output reg [7:0] rdata;
+input [3:0] wen;
+
+reg [7:0] mem [0:3];
+
+integer i;
+always @(posedge clk) begin
+ for (i = 0; i < 4; i = i+1)
+ if (wen[i]) mem[addr][i*2 +: 2] <= wdata[i*2 +: 2];
+ rdata <= mem[addr];
+end
+
+endmodule
+
+// ----------------------------------------------------------
+
+module memtest06_sync(input clk, input rst, input [2:0] idx, input [7:0] din, output [7:0] dout);
+ (* gentb_constant=0 *) wire rst;
+ reg [7:0] test [0:7];
+ integer i;
+ always @(posedge clk) begin
+ if (rst) begin
+ for (i=0; i<8; i=i+1)
+ test[i] <= 0;
+ end else begin
+ test[0][2] <= din[1];
+ test[0][5] <= test[0][2];
+ test[idx][3] <= din[idx];
+ test[idx][6] <= test[idx][2];
+ test[idx][idx] <= !test[idx][idx];
+ end
+ end
+ assign dout = test[idx];
+endmodule
+
+module memtest06_async(input clk, input rst, input [2:0] idx, input [7:0] din, output [7:0] dout);
+ (* gentb_constant=0 *) wire rst;
+ reg [7:0] test [0:7];
+ integer i;
+ always @(posedge clk or posedge rst) begin
+ if (rst) begin
+ for (i=0; i<8; i=i+1)
+ test[i] <= 0;
+ end else begin
+ test[0][2] <= din[1];
+ test[0][5] <= test[0][2];
+ test[idx][3] <= din[idx];
+ test[idx][6] <= test[idx][2];
+ test[idx][idx] <= !test[idx][idx];
+ end
+ end
+ assign dout = test[idx];
+endmodule
+
+// ----------------------------------------------------------
+
+module memtest07(clk, addr, woffset, wdata, rdata);
+
+input clk;
+input [1:0] addr;
+input [3:0] wdata;
+input [1:0] woffset;
+output reg [7:0] rdata;
+
+reg [7:0] mem [0:3];
+
+integer i;
+always @(posedge clk) begin
+ mem[addr][woffset +: 4] <= wdata;
+ rdata <= mem[addr];
+end
+
+endmodule
+
+// ----------------------------------------------------------
+
+module memtest08(input clk, input [3:0] a, b, c, output reg [3:0] y);
+ reg [3:0] mem [0:15] [0:15];
+ always @(posedge clk) begin
+ y <= mem[a][b];
+ mem[a][b] <= c;
+ end
+endmodule
+
diff --git a/tests/simple/operators.v b/tests/simple/operators.v
index 7439101c..2f0fdb82 100644
--- a/tests/simple/operators.v
+++ b/tests/simple/operators.v
@@ -1,4 +1,4 @@
-module test(clk, mode, u1, s1, u2, s2, y);
+module optest(clk, mode, u1, s1, u2, s2, y);
input clk;
input [6:0] mode;
diff --git a/tests/simple/paramods.v b/tests/simple/paramods.v
index 8d0134a6..23cb276f 100644
--- a/tests/simple/paramods.v
+++ b/tests/simple/paramods.v
@@ -1,5 +1,5 @@
-module test1(a, b, x, y);
+module pm_test1(a, b, x, y);
input [7:0] a, b;
output [7:0] x, y;
@@ -11,7 +11,7 @@ endmodule
// -----------------------------------
-module test2(a, b, x, y);
+module pm_test2(a, b, x, y);
input [7:0] a, b;
output [7:0] x, y;
@@ -23,7 +23,7 @@ endmodule
// -----------------------------------
-module test3(a, b, x, y);
+module pm_test3(a, b, x, y);
input [7:0] a, b;
output [7:0] x, y;
diff --git a/tests/simple/partsel.v b/tests/simple/partsel.v
index acfc1ca5..7461358a 100644
--- a/tests/simple/partsel.v
+++ b/tests/simple/partsel.v
@@ -1,5 +1,62 @@
-module test001(input [2:0] idx, input [31:0] data, output [3:0] slice_up, slice_down);
+module partsel_test001(input [2:0] idx, input [31:0] data, output [3:0] slice_up, slice_down);
wire [5:0] offset = idx << 2;
assign slice_up = data[offset +: 4];
assign slice_down = data[offset + 3 -: 4];
endmodule
+
+module partsel_test002 (
+ input clk, rst,
+ input [7:0] a,
+ input [0:7] b,
+ input [1:0] s,
+ output [7:0] x1, x2, x3,
+ output [0:7] x4, x5, x6,
+ output [7:0] y1, y2, y3,
+ output [0:7] y4, y5, y6,
+ output [7:0] z1, z2, z3,
+ output [0:7] z4, z5, z6,
+ output [7:0] w1, w2, w3,
+ output [0:7] w4, w5, w6,
+ output [7:0] p1, p2, p3, p4, p5, p6,
+ output [0:7] q1, q2, q3, q4, q5, q6,
+ output reg [7:0] r1,
+ output reg [0:7] r2
+);
+
+assign x1 = a, x2 = a + b, x3 = b;
+assign x4 = a, x5 = a + b, x6 = b;
+assign y1 = a[4 +: 3], y2 = a[4 +: 3] + b[4 +: 3], y3 = b[4 +: 3];
+assign y4 = a[4 +: 3], y5 = a[4 +: 3] + b[4 +: 3], y6 = b[4 +: 3];
+assign z1 = a[4 -: 3], z2 = a[4 -: 3] + b[4 -: 3], z3 = b[4 -: 3];
+assign z4 = a[4 -: 3], z5 = a[4 -: 3] + b[4 -: 3], z6 = b[4 -: 3];
+assign w1 = a[6:3], w2 = a[6:3] + b[3:6], w3 = b[3:6];
+assign w4 = a[6:3], w5 = a[6:3] + b[3:6], w6 = b[3:6];
+assign p1 = a[s], p2 = b[s], p3 = a[s+2 +: 2], p4 = b[s+2 +: 2], p5 = a[s+2 -: 2], p6 = b[s+2 -: 2];
+assign q1 = a[s], q2 = b[s], q3 = a[s+2 +: 2], q4 = b[s+2 +: 2], q5 = a[s+2 -: 2], q6 = b[s+2 -: 2];
+
+always @(posedge clk) begin
+ if (rst) begin
+ { r1, r2 } = 16'h1337 ^ {a, b};
+ end else begin
+ case (s)
+ 0: begin
+ r1[3:0] <= r2[0:3] ^ x1;
+ r2[4:7] <= r1[7:4] ^ x4;
+ end
+ 1: begin
+ r1[2 +: 3] <= r2[5 -: 3] + x1;
+ r2[3 +: 3] <= r1[6 -: 3] + x4;
+ end
+ 2: begin
+ r1[6 -: 3] <= r2[3 +: 3] - x1;
+ r2[7 -: 3] <= r1[4 +: 3] - x4;
+ end
+ 3: begin
+ r1 <= r2;
+ r2 <= r1;
+ end
+ endcase
+ end
+end
+
+endmodule
diff --git a/tests/simple/realexpr.v b/tests/simple/realexpr.v
new file mode 100644
index 00000000..5b756e6b
--- /dev/null
+++ b/tests/simple/realexpr.v
@@ -0,0 +1,24 @@
+
+module demo_001(y1, y2, y3, y4);
+ output [7:0] y1, y2, y3, y4;
+
+ localparam [7:0] p1 = 123.45;
+ localparam real p2 = 123.45;
+ localparam real p3 = 123;
+ localparam p4 = 123.45;
+
+ assign y1 = p1 + 0.2;
+ assign y2 = p2 + 0.2;
+ assign y3 = p3 + 0.2;
+ assign y4 = p4 + 0.2;
+endmodule
+
+module demo_002(y0, y1, y2, y3);
+ output [63:0] y0, y1, y2, y3;
+
+ assign y0 = 1'bx >= (-1 * -1.17);
+ assign y1 = 1 ? 1 ? -1 : 'd0 : 0.0;
+ assign y2 = 1 ? -1 : 1 ? 'd0 : 0.0;
+ assign y3 = 1 ? -1 : 'd0;
+endmodule
+
diff --git a/tests/simple/repwhile.v b/tests/simple/repwhile.v
new file mode 100644
index 00000000..5d0c75fa
--- /dev/null
+++ b/tests/simple/repwhile.v
@@ -0,0 +1,36 @@
+module repwhile_test001(input [5:0] a, output [7:0] y, output [31:0] x);
+
+ function [7:0] mylog2;
+ input [31:0] value;
+ begin
+ mylog2 = 0;
+ while (value > 0) begin
+ value = value >> 1;
+ mylog2 = mylog2 + 1;
+ end
+ end
+ endfunction
+
+ function [31:0] myexp2;
+ input [7:0] value;
+ begin
+ myexp2 = 1;
+ repeat (value)
+ myexp2 = myexp2 << 1;
+ end
+ endfunction
+
+ reg [7:0] y_table [63:0];
+ reg [31:0] x_table [63:0];
+
+ integer i;
+ initial begin
+ for (i = 0; i < 64; i = i+1) begin
+ y_table[i] <= mylog2(i);
+ x_table[i] <= myexp2(i);
+ end
+ end
+
+ assign y = y_table[a];
+ assign x = x_table[a];
+endmodule
diff --git a/tests/simple/run-test.sh b/tests/simple/run-test.sh
index eb6fd10b..6531d51a 100755
--- a/tests/simple/run-test.sh
+++ b/tests/simple/run-test.sh
@@ -6,5 +6,4 @@ if ! which iverilog > /dev/null ; then
exit 1
fi
-make -C ../.. || exit 1
-exec bash ../tools/autotest.sh *.v
+exec ${MAKE:-make} -f ../tools/autotest.mk *.v
diff --git a/tests/simple/scopes.v b/tests/simple/scopes.v
new file mode 100644
index 00000000..eecc1a0b
--- /dev/null
+++ b/tests/simple/scopes.v
@@ -0,0 +1,63 @@
+module scopes_test_01(input [3:0] k, output reg [15:0] x, y);
+ function [15:0] func_01;
+ input [15:0] x, y;
+ begin
+ func_01 = x + y;
+ begin:blk
+ reg [15:0] x;
+ x = y;
+ func_01 = func_01 ^ x;
+ end
+ func_01 = func_01 ^ x;
+ end
+ endfunction
+
+ function [15:0] func_02;
+ input [15:0] x, y;
+ begin
+ func_02 = x - y;
+ begin:blk
+ reg [15:0] func_02;
+ func_02 = 0;
+ end
+ end
+ endfunction
+
+ task task_01;
+ input [3:0] a;
+ reg [15:0] y;
+ begin
+ y = a * 23;
+ x = x + y;
+ end
+ endtask
+
+ task task_02;
+ input [3:0] a;
+ begin:foo
+ reg [15:0] x, z;
+ x = y;
+ begin:bar
+ reg [15:0] x;
+ x = 77 + a;
+ z = -x;
+ end
+ y = x ^ z;
+ end
+ endtask
+
+ always @* begin
+ x = func_01(11, 22);
+ y = func_02(33, 44);
+ task_01(k);
+ task_02(k);
+ begin:foo
+ reg [15:0] y;
+ y = x;
+ y = y + k;
+ x = y;
+ end
+ x = func_01(y, x);
+ y = func_02(y, x);
+ end
+endmodule
diff --git a/tests/simple/signedexpr.v b/tests/simple/signedexpr.v
index 3eb5e93d..8bba4a4b 100644
--- a/tests/simple/signedexpr.v
+++ b/tests/simple/signedexpr.v
@@ -1,4 +1,4 @@
-module test01(a, b, xu, xs, yu, ys, zu, zs);
+module signed_test01(a, b, xu, xs, yu, ys, zu, zs);
input signed [1:0] a;
input signed [2:0] b;
diff --git a/tests/simple/task_func.v b/tests/simple/task_func.v
index 3a09cbc3..51e31015 100644
--- a/tests/simple/task_func.v
+++ b/tests/simple/task_func.v
@@ -1,5 +1,5 @@
-module test01(clk, a, b, c, x, y, z, w);
+module task_func_test01(clk, a, b, c, x, y, z, w);
input clk;
input [7:0] a, b, c;
@@ -33,3 +33,16 @@ end
endmodule
+
+module task_func_test02( input [7:0] din_a, input [7:0] din_b, output [7:0] dout_a);
+ assign dout_a = test(din_a,din_b);
+ function [7:0] test;
+ input [7:0] a;
+ input [7:0] b;
+ begin : TEST
+ integer i;
+ for (i = 0; i <= 7; i = i + 1)
+ test[i] = a[i] & b[i];
+ end
+ endfunction
+endmodule
diff --git a/tests/simple/undef_eqx_nex.v b/tests/simple/undef_eqx_nex.v
index 63912a2f..b0178677 100644
--- a/tests/simple/undef_eqx_nex.v
+++ b/tests/simple/undef_eqx_nex.v
@@ -1,4 +1,4 @@
-module test(y);
+module undef_eqx_nex(y);
output [7:0] y;
assign y[0] = 0/0;
assign y[1] = 0/1;
diff --git a/tests/simple/usb_phy_tetsts.v b/tests/simple/usb_phy_tests.v
index 2375183d..bc45e71a 100644
--- a/tests/simple/usb_phy_tetsts.v
+++ b/tests/simple/usb_phy_tests.v
@@ -1,6 +1,6 @@
// from usb_rx_phy
-module test01(clk, rst, rx_en, fs_ce);
+module usb_phy_test01(clk, rst, rx_en, fs_ce);
input clk, rst;
input rx_en;
diff --git a/tests/techmap/.gitignore b/tests/techmap/.gitignore
new file mode 100644
index 00000000..397b4a76
--- /dev/null
+++ b/tests/techmap/.gitignore
@@ -0,0 +1 @@
+*.log
diff --git a/tests/techmap/mem_simple_4x1_cells.v b/tests/techmap/mem_simple_4x1_cells.v
new file mode 100644
index 00000000..7ecdd2de
--- /dev/null
+++ b/tests/techmap/mem_simple_4x1_cells.v
@@ -0,0 +1,13 @@
+module MEM4X1 (CLK, RD_ADDR, RD_DATA, WR_ADDR, WR_DATA, WR_EN);
+ input CLK, WR_DATA, WR_EN;
+ input [3:0] RD_ADDR, WR_ADDR;
+ output reg RD_DATA;
+
+ reg [15:0] memory;
+
+ always @(posedge CLK) begin
+ if (WR_EN)
+ memory[WR_ADDR] <= WR_DATA;
+ RD_DATA <= memory[RD_ADDR];
+ end
+endmodule
diff --git a/tests/techmap/mem_simple_4x1_map.v b/tests/techmap/mem_simple_4x1_map.v
new file mode 100644
index 00000000..820f89de
--- /dev/null
+++ b/tests/techmap/mem_simple_4x1_map.v
@@ -0,0 +1,140 @@
+
+module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
+ parameter MEMID = "";
+ parameter SIZE = 256;
+ parameter OFFSET = 0;
+ parameter ABITS = 8;
+ parameter WIDTH = 8;
+
+ parameter RD_PORTS = 1;
+ parameter RD_CLK_ENABLE = 1'b1;
+ parameter RD_CLK_POLARITY = 1'b1;
+ parameter RD_TRANSPARENT = 1'b1;
+
+ parameter WR_PORTS = 1;
+ parameter WR_CLK_ENABLE = 1'b1;
+ parameter WR_CLK_POLARITY = 1'b1;
+
+ input [RD_PORTS-1:0] RD_CLK;
+ input [RD_PORTS*ABITS-1:0] RD_ADDR;
+ output reg [RD_PORTS*WIDTH-1:0] RD_DATA;
+
+ input [WR_PORTS-1:0] WR_CLK;
+ input [WR_PORTS*WIDTH-1:0] WR_EN;
+ input [WR_PORTS*ABITS-1:0] WR_ADDR;
+ input [WR_PORTS*WIDTH-1:0] WR_DATA;
+
+ wire [1023:0] _TECHMAP_DO_ = "proc; clean";
+
+ parameter _TECHMAP_CONNMAP_RD_CLK_ = 0;
+ parameter _TECHMAP_CONNMAP_WR_CLK_ = 0;
+
+ parameter _TECHMAP_BITS_CONNMAP_ = 0;
+ parameter _TECHMAP_CONNMAP_WR_EN_ = 0;
+
+ reg _TECHMAP_FAIL_;
+ integer k;
+ initial begin
+ _TECHMAP_FAIL_ <= 0;
+
+ // only map cells with only one read and one write port
+ if (RD_PORTS > 1 || WR_PORTS > 1)
+ _TECHMAP_FAIL_ <= 1;
+
+ // we expect positive read clock and non-transparent reads
+ if (RD_TRANSPARENT || !RD_CLK_ENABLE || !RD_CLK_POLARITY)
+ _TECHMAP_FAIL_ <= 1;
+
+ // we expect positive write clock
+ if (!WR_CLK_ENABLE || !WR_CLK_POLARITY)
+ _TECHMAP_FAIL_ <= 1;
+
+ // only one global write enable bit is supported
+ for (k = 1; k < WR_PORTS*WIDTH; k = k+1)
+ if (_TECHMAP_CONNMAP_WR_EN_[0 +: _TECHMAP_BITS_CONNMAP_] !=
+ _TECHMAP_CONNMAP_WR_EN_[k*_TECHMAP_BITS_CONNMAP_ +: _TECHMAP_BITS_CONNMAP_])
+ _TECHMAP_FAIL_ <= 1;
+
+ // read and write must be in same clock domain
+ if (_TECHMAP_CONNMAP_RD_CLK_ != _TECHMAP_CONNMAP_WR_CLK_)
+ _TECHMAP_FAIL_ <= 1;
+
+ // we don't do small memories or memories with offsets
+ if (OFFSET != 0 || ABITS < 4 || SIZE < 16)
+ _TECHMAP_FAIL_ <= 1;
+ end
+
+ genvar i;
+ generate
+ for (i = 0; i < WIDTH; i=i+1) begin:slice
+ \$__mem_4x1_generator #(
+ .ABITS(ABITS),
+ .SIZE(SIZE)
+ ) bit_slice (
+ .CLK(RD_CLK),
+ .RD_ADDR(RD_ADDR),
+ .RD_DATA(RD_DATA[i]),
+ .WR_ADDR(WR_ADDR),
+ .WR_DATA(WR_DATA[i]),
+ .WR_EN(WR_EN[0])
+ );
+ end
+ endgenerate
+endmodule
+
+module \$__mem_4x1_generator (CLK, RD_ADDR, RD_DATA, WR_ADDR, WR_DATA, WR_EN);
+ parameter ABITS = 4;
+ parameter SIZE = 16;
+
+ input CLK, WR_DATA, WR_EN;
+ input [ABITS-1:0] RD_ADDR, WR_ADDR;
+ output RD_DATA;
+
+ wire [1023:0] _TECHMAP_DO_ = "proc; clean";
+
+ generate
+ if (ABITS > 4) begin
+ wire high_rd_data, low_rd_data;
+ if (SIZE > 2**(ABITS-1)) begin
+ \$__mem_4x1_generator #(
+ .ABITS(ABITS-1),
+ .SIZE(SIZE - 2**(ABITS-1))
+ ) part_high (
+ .CLK(CLK),
+ .RD_ADDR(RD_ADDR[ABITS-2:0]),
+ .RD_DATA(high_rd_data),
+ .WR_ADDR(WR_ADDR[ABITS-2:0]),
+ .WR_DATA(WR_DATA),
+ .WR_EN(WR_EN && WR_ADDR[ABITS-1])
+ );
+ end else begin
+ assign high_rd_data = 1'bx;
+ end
+ \$__mem_4x1_generator #(
+ .ABITS(ABITS-1),
+ .SIZE(SIZE > 2**(ABITS-1) ? 2**(ABITS-1) : SIZE)
+ ) part_low (
+ .CLK(CLK),
+ .RD_ADDR(RD_ADDR[ABITS-2:0]),
+ .RD_DATA(low_rd_data),
+ .WR_ADDR(WR_ADDR[ABITS-2:0]),
+ .WR_DATA(WR_DATA),
+ .WR_EN(WR_EN && !WR_ADDR[ABITS-1])
+ );
+ reg delayed_abit;
+ always @(posedge CLK)
+ delayed_abit <= RD_ADDR[ABITS-1];
+ assign RD_DATA = delayed_abit ? high_rd_data : low_rd_data;
+ end else begin
+ MEM4X1 _TECHMAP_REPLACE_ (
+ .CLK(CLK),
+ .RD_ADDR(RD_ADDR),
+ .RD_DATA(RD_DATA),
+ .WR_ADDR(WR_ADDR),
+ .WR_DATA(WR_DATA),
+ .WR_EN(WR_EN)
+ );
+ end
+ endgenerate
+endmodule
+
diff --git a/tests/techmap/mem_simple_4x1_runtest.sh b/tests/techmap/mem_simple_4x1_runtest.sh
new file mode 100644
index 00000000..e2c6303d
--- /dev/null
+++ b/tests/techmap/mem_simple_4x1_runtest.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -ev
+
+../../yosys -b 'verilog -noattr' -o mem_simple_4x1_synth.v -p 'proc; opt; memory -nomap; techmap -map mem_simple_4x1_map.v;; techmap; opt; abc;; stat' mem_simple_4x1_uut.v
+
+iverilog -o mem_simple_4x1_gold_tb mem_simple_4x1_tb.v mem_simple_4x1_uut.v
+iverilog -o mem_simple_4x1_gate_tb mem_simple_4x1_tb.v mem_simple_4x1_synth.v mem_simple_4x1_cells.v
+
+./mem_simple_4x1_gold_tb > mem_simple_4x1_gold_tb.out
+./mem_simple_4x1_gate_tb > mem_simple_4x1_gate_tb.out
+
+diff -u mem_simple_4x1_gold_tb.out mem_simple_4x1_gate_tb.out
+rm -f mem_simple_4x1_synth.v mem_simple_4x1_tb.vcd
+rm -f mem_simple_4x1_{gold,gate}_tb{,.out}
+: OK
+
diff --git a/tests/techmap/mem_simple_4x1_tb.v b/tests/techmap/mem_simple_4x1_tb.v
new file mode 100644
index 00000000..53262696
--- /dev/null
+++ b/tests/techmap/mem_simple_4x1_tb.v
@@ -0,0 +1,29 @@
+module tb;
+
+reg clk, rst;
+wire [7:0] out;
+wire [4:0] counter;
+
+uut uut (clk, rst, out, counter);
+
+initial begin
+ #5 clk <= 0;
+ repeat (100) #5 clk <= ~clk;
+ #5 $finish;
+end
+
+initial begin
+ rst <= 1;
+ repeat (2) @(posedge clk);
+ rst <= 0;
+end
+
+always @(posedge clk)
+ $display("%d %d %d", rst, out, counter);
+
+initial begin
+ $dumpfile("mem_simple_4x1_tb.vcd");
+ $dumpvars(0, uut);
+end
+
+endmodule
diff --git a/tests/techmap/mem_simple_4x1_uut.v b/tests/techmap/mem_simple_4x1_uut.v
new file mode 100644
index 00000000..8d461459
--- /dev/null
+++ b/tests/techmap/mem_simple_4x1_uut.v
@@ -0,0 +1,15 @@
+module uut (clk, rst, out, counter);
+
+input clk, rst;
+output reg [7:0] out;
+output reg [4:0] counter;
+
+reg [7:0] memory [0:19];
+
+always @(posedge clk) begin
+ counter <= rst || counter == 19 ? 0 : counter+1;
+ memory[counter] <= counter;
+ out <= memory[counter];
+end
+
+endmodule
diff --git a/tests/techmap/run-test.sh b/tests/techmap/run-test.sh
new file mode 100755
index 00000000..e2fc11e5
--- /dev/null
+++ b/tests/techmap/run-test.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -e
+for x in *_runtest.sh; do
+ echo "Running $x.."
+ if ! bash $x &> ${x%.sh}.log; then
+ tail ${x%.sh}.log
+ echo ERROR
+ exit 1
+ fi
+done
diff --git a/tests/tools/autotest.mk b/tests/tools/autotest.mk
new file mode 100644
index 00000000..f65002ce
--- /dev/null
+++ b/tests/tools/autotest.mk
@@ -0,0 +1,8 @@
+
+EXTRA_FLAGS=
+
+$(MAKECMDGOALS):
+ @$(basename $(MAKEFILE_LIST)).sh -G -j $(EXTRA_FLAGS) $@
+
+.PHONY: $(MAKECMDGOALS)
+
diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh
index 7bccd9a5..50f5cb58 100755
--- a/tests/tools/autotest.sh
+++ b/tests/tools/autotest.sh
@@ -6,38 +6,52 @@ use_xsim=false
use_modelsim=false
verbose=false
keeprunning=false
+makejmode=false
+frontend="verilog"
backend_opts="-noattr -noexpr"
+autotb_opts=""
scriptfiles=""
scriptopt=""
toolsdir="$(cd $(dirname $0); pwd)"
+warn_iverilog_git=false
if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then
( set -ex; gcc -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1
fi
-while getopts xml:wkvrs:p: opt; do
+while getopts xmGl:wkjvref:s:p:n: opt; do
case "$opt" in
x)
use_xsim=true ;;
m)
use_modelsim=true ;;
+ G)
+ warn_iverilog_git=true ;;
l)
libs="$libs $(cd $(dirname $OPTARG); pwd)/$(basename $OPTARG)";;
w)
genvcd=true ;;
k)
keeprunning=true ;;
+ j)
+ makejmode=true ;;
v)
verbose=true ;;
r)
backend_opts="$backend_opts -norename" ;;
+ e)
+ backend_opts="$( echo " $backend_opts " | sed 's, -noexpr ,,; s,^ ,,; s, $,,;'; )" ;;
+ f)
+ frontend="$OPTARG" ;;
s)
[[ "$OPTARG" == /* ]] || OPTARG="$PWD/$OPTARG"
scriptfiles="$scriptfiles $OPTARG" ;;
p)
scriptopt="$OPTARG" ;;
+ n)
+ autotb_opts="$autotb_opts -n $OPTARG" ;;
*)
- echo "Usage: $0 [-x|-m] [-w] [-k] [-v] [-r] [-l libs] [-s script] [-p cmdstring] verilog-files\n" >&2
+ echo "Usage: $0 [-x|-m] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] verilog-files\n" >&2
exit 1
esac
done
@@ -77,17 +91,26 @@ do
exit 1
fi
[[ "$bn" == *_tb ]] && continue
- echo -n "Test: $bn "
- rm -f ${bn}.{err,log}
+ if $makejmode; then
+ status_prefix="Test: $bn "
+ else
+ status_prefix=""
+ echo -n "Test: $bn "
+ fi
+
+ rm -f ${bn}.{err,log,sikp}
mkdir -p ${bn}.out
rm -rf ${bn}.out/*
body() {
cd ${bn}.out
+ fn=$(basename $fn)
+ bn=$(basename $bn)
+
cp ../$fn $fn
if [ ! -f ../${bn}_tb.v ]; then
- "$toolsdir"/../../yosys -b autotest -o ${bn}_tb.v $fn
+ "$toolsdir"/../../yosys -b "test_autotb $autotb_opts" -o ${bn}_tb.v $fn
else
cp ../${bn}_tb.v ${bn}_tb.v
fi
@@ -98,7 +121,7 @@ do
test_count=0
test_passes() {
- "$toolsdir"/../../yosys -b "verilog $backend_opts" "$@" -o ${bn}_syn${test_count}.v $fn $scriptfiles
+ "$toolsdir"/../../yosys -b "verilog $backend_opts" -o ${bn}_syn${test_count}.v "$@"
compile_and_run ${bn}_tb_syn${test_count} ${bn}_out_syn${test_count} \
${bn}_tb.v ${bn}_syn${test_count}.v $libs \
"$toolsdir"/../../techlibs/common/simlib.v \
@@ -108,13 +131,22 @@ do
test_count=$(( test_count + 1 ))
}
+ if [ "$frontend" = "verific" -o "$frontend" = "verific_gates" ] && grep -q VERIFIC-SKIP $fn; then
+ touch ../${bn}.skip
+ return
+ fi
+
if [ -n "$scriptfiles" ]; then
- test_passes
+ test_passes $fn $scriptfiles
elif [ -n "$scriptopt" ]; then
- test_passes -p "$scriptopt"
+ test_passes -f "$frontend" -p "$scriptopt" $fn
+ elif [ "$frontend" = "verific" ]; then
+ test_passes -p "verific -vlog2k $fn; verific -import -all; opt; memory;;"
+ elif [ "$frontend" = "verific_gates" ]; then
+ test_passes -p "verific -vlog2k $fn; verific -import -gates -all; opt; memory;;"
else
- test_passes -p "hierarchy; proc; opt; memory; opt; fsm; opt"
- test_passes -p "hierarchy; proc; opt; memory; opt; fsm; opt; techmap; opt; abc -dff; opt"
+ test_passes -f "$frontend" -p "hierarchy; proc; opt; memory; opt; fsm; opt -fine" $fn
+ test_passes -f "$frontend" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" $fn
fi
touch ../${bn}.log
}
@@ -129,8 +161,17 @@ do
if [ -f ${bn}.log ]; then
mv ${bn}.err ${bn}.log
- echo "-> ok"
- else echo "-> ERROR!"; $keeprunning || exit 1; fi
+ echo "${status_prefix}-> ok"
+ elif [ -f ${bn}.skip ]; then
+ mv ${bn}.err ${bn}.skip
+ echo "${status_prefix}-> skip"
+ else
+ echo "${status_prefix}-> ERROR!"
+ if $warn_iverilog_git; then
+ echo "Note: Make sure that 'iverilog' is an up-to-date git checkout of icarus verilog."
+ fi
+ $keeprunning || exit 1
+ fi
done
exit 0
diff --git a/tests/tools/txt2tikztiming.py b/tests/tools/txt2tikztiming.py
new file mode 100755
index 00000000..cfefe339
--- /dev/null
+++ b/tests/tools/txt2tikztiming.py
@@ -0,0 +1,109 @@
+#!/usr/bin/python
+
+from __future__ import division
+from __future__ import print_function
+
+import argparse
+import fileinput
+import sys
+
+parser = argparse.ArgumentParser(description='Convert vcd2txt output to tikz-timing line.')
+parser.add_argument('filename', metavar='FILE', help='input txt file')
+parser.add_argument('signame', metavar='SIG', help='Signal name')
+parser.add_argument('-s', metavar='scale', default=1.0, type=float, help='Scale all time spans with this factor')
+parser.add_argument('-l', action='store_true', help='Logic signal (high/low)')
+parser.add_argument('-b', action='store_true', help='Display binary value')
+parser.add_argument('-x', action='store_true', help='Display hex value')
+parser.add_argument('-d', action='store_true', help='Display decimal value')
+args = parser.parse_args()
+
+start_time = None
+stop_time = None
+time_val = { }
+
+def value_to_logic(value):
+ found_x = False
+ for char in value:
+ if char == '1':
+ return "H"
+ if char == 'x':
+ found_x = True
+ return "U" if found_x else "L"
+
+def value_to_binary(value):
+ return "D{%s}" % value
+
+def value_to_hex(value):
+ hex_string = ""
+ found_def = False
+ while len(value) % 4 != 0:
+ value = "0" + value
+ while len(value) != 0:
+ bin_digits = value[0:4]
+ hex_digit = 0
+ value = value[4:]
+ for b in bin_digits:
+ if b == '0':
+ hex_digit = hex_digit * 2
+ elif b == '1':
+ hex_digit = hex_digit * 2 + 1
+ else:
+ hex_digit += 100
+ if hex_digit > 15:
+ hex_string += "x"
+ else:
+ found_def = True
+ hex_string += "0123456789abcdef"[hex_digit]
+ if not found_def:
+ return "U";
+ return "D{%s}" % hex_string
+
+def value_to_decimal(value):
+ val = 0
+ found_def = False
+ found_undef = False
+ for digit in value:
+ if digit == 'x':
+ found_undef = True
+ else:
+ val = val*2 + int(digit)
+ found_def = True
+ if found_def:
+ if found_undef:
+ return "D{X}"
+ else:
+ return "D{%d}" % val
+ return "U"
+
+for line in fileinput.input(args.filename):
+ (node, time, name, value) = line.strip().split('\t')
+ time = int(time)
+ if start_time is None or start_time > time:
+ start_time = time
+ if stop_time is None or stop_time < time:
+ stop_time = time
+ if name == args.signame:
+ if args.l:
+ time_val[+time] = value_to_logic(value)
+ elif args.b:
+ time_val[+time] = value_to_binary(value)
+ elif args.x:
+ time_val[+time] = value_to_hex(value)
+ elif args.d:
+ time_val[+time] = value_to_decimal(value)
+ else:
+ time_val[+time] = value
+
+if start_time not in time_val:
+ time_val[start_time] = "S"
+
+last_time = None
+last_value = None
+for t in sorted(time_val.keys()):
+ if last_time is not None:
+ print("%f%s" % ((t - last_time)*args.s, last_value), end='')
+ (last_time, last_value) = (t, time_val[t])
+if last_time < stop_time:
+ print("%f%s" % ((stop_time - last_time)*args.s, last_value), end='')
+print('')
+
diff --git a/tests/tools/vcd2txt.pl b/tests/tools/vcd2txt.pl
new file mode 100755
index 00000000..92d3d165
--- /dev/null
+++ b/tests/tools/vcd2txt.pl
@@ -0,0 +1,61 @@
+#!/usr/bin/perl -w
+#
+# Note: You might need to install the Verilog::VCD package using CPAN..
+
+use strict;
+use Data::Dumper;
+use Verilog::VCD qw(parse_vcd list_sigs);
+
+$| = 1;
+
+my $from_time = -1;
+my $to_time = -1;
+
+while (1)
+{
+ if ($ARGV[0] eq '-f') {
+ $from_time = +$ARGV[1];
+ shift @ARGV;
+ shift @ARGV;
+ next;
+ }
+ if ($ARGV[0] eq '-t') {
+ $to_time = +$ARGV[1];
+ shift @ARGV;
+ shift @ARGV;
+ next;
+ }
+ last;
+}
+
+if ($#ARGV < 0) {
+ print STDERR "\n";
+ print STDERR "VCD2TXT - Convert VCD to tab-separated text file\n";
+ print STDERR "\n";
+ print STDERR "Usage: $0 [-f from_time] [-t to_time] input.vcd [<signal regex> ...]\n";
+ print STDERR "\n";
+ exit 1;
+}
+
+my $vcd = parse_vcd($ARGV[0]);
+
+for my $node (keys $vcd) {
+ for my $net (@{$vcd->{$node}->{'nets'}}) {
+ my $dump_this = $#ARGV == 0;
+ for (my $i = 1; $i <= $#ARGV; $i++) {
+ my $regex = $ARGV[$i];
+ $dump_this = 1 if ($net->{"hier"} . "." . $net->{"name"}) =~ /$regex/;
+ }
+ next unless $dump_this;
+ my $cached_value = "";
+ for my $tv (@{$vcd->{$node}->{'tv'}}) {
+ $cached_value = $tv->[1], next if $from_time >= 0 and +$tv->[0] < $from_time;
+ next if $to_time >= 0 and +$tv->[0] > $to_time;
+ printf "%s\t%s\t%s\t%s\n", $node, $from_time, $net->{"hier"} . "." . $net->{"name"}, $cached_value
+ if $cached_value ne "" and $from_time >= 0 and +$tv->[0] > $from_time;
+ printf "%s\t%s\t%s\t%s\n", $node, $tv->[0], $net->{"hier"} . "." . $net->{"name"}, $tv->[1];
+ $cached_value = "";
+ }
+ }
+}
+
diff --git a/tests/various/.gitignore b/tests/various/.gitignore
new file mode 100644
index 00000000..397b4a76
--- /dev/null
+++ b/tests/various/.gitignore
@@ -0,0 +1 @@
+*.log
diff --git a/tests/various/constmsk_test.v b/tests/various/constmsk_test.v
new file mode 100644
index 00000000..0d0e58fe
--- /dev/null
+++ b/tests/various/constmsk_test.v
@@ -0,0 +1,4 @@
+module test(input [3:0] A, output [3:0] Y1, Y2);
+ assign Y1 = |{A[3], 1'b0, A[1]};
+ assign Y2 = |{A[2], 1'b1, A[0]};
+endmodule
diff --git a/tests/various/constmsk_test.ys b/tests/various/constmsk_test.ys
new file mode 100644
index 00000000..ce36efc3
--- /dev/null
+++ b/tests/various/constmsk_test.ys
@@ -0,0 +1,15 @@
+read_verilog constmsk_test.v
+
+copy test gold
+rename test gate
+
+cd gate
+techmap -map constmsk_testmap.v;;
+cd ..
+
+select -assert-count 2 gold/r:A_WIDTH=3
+select -assert-count 1 gate/r:A_WIDTH=2
+select -assert-count 1 gate/c:*
+
+miter -equiv -flatten gold gate miter
+sat -verify -prove trigger 0 miter
diff --git a/tests/various/constmsk_testmap.v b/tests/various/constmsk_testmap.v
new file mode 100644
index 00000000..fab1b1bb
--- /dev/null
+++ b/tests/various/constmsk_testmap.v
@@ -0,0 +1,49 @@
+(* techmap_celltype = "$reduce_or" *)
+module my_opt_reduce_or(...);
+ parameter A_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ output reg [Y_WIDTH-1:0] Y;
+
+ parameter _TECHMAP_CONSTMSK_A_ = 0;
+ parameter _TECHMAP_CONSTVAL_A_ = 0;
+
+ wire _TECHMAP_FAIL_ = count_nonconst_bits() == A_WIDTH;
+ wire [1024:0] _TECHMAP_DO_ = "proc;;";
+
+ function integer count_nonconst_bits;
+ integer i;
+ begin
+ count_nonconst_bits = 0;
+ for (i = 0; i < A_WIDTH; i=i+1)
+ if (!_TECHMAP_CONSTMSK_A_[i])
+ count_nonconst_bits = count_nonconst_bits+1;
+ end
+ endfunction
+
+ function has_const_one;
+ integer i;
+ begin
+ has_const_one = 0;
+ for (i = 0; i < A_WIDTH; i=i+1)
+ if (_TECHMAP_CONSTMSK_A_[i] && _TECHMAP_CONSTVAL_A_[i] === 1'b1)
+ has_const_one = 1;
+ end
+ endfunction
+
+ integer i;
+ reg [count_nonconst_bits()-1:0] tmp;
+
+ always @* begin
+ if (has_const_one()) begin
+ Y = 1;
+ end else begin
+ for (i = 0; i < A_WIDTH; i=i+1)
+ if (!_TECHMAP_CONSTMSK_A_[i])
+ tmp = {A[i], tmp[count_nonconst_bits()-1:1]};
+ Y = |tmp;
+ end
+ end
+endmodule
diff --git a/tests/various/run-test.sh b/tests/various/run-test.sh
new file mode 100755
index 00000000..67e1beb2
--- /dev/null
+++ b/tests/various/run-test.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+set -e
+for x in *.ys; do
+ echo "Running $x.."
+ ../../yosys -ql ${x%.ys}.log $x
+done
diff --git a/tests/various/submod_extract.ys b/tests/various/submod_extract.ys
new file mode 100644
index 00000000..8d11c21d
--- /dev/null
+++ b/tests/various/submod_extract.ys
@@ -0,0 +1,21 @@
+read_verilog << EOT
+ module test(input [7:0] a, b, c, d, output [7:0] x, y, z);
+ assign x = a + b, y = b + c, z = c + d;
+ endmodule
+EOT
+
+copy test gold
+rename test gate
+
+submod -name mycell gate/x %ci*
+design -copy-to mymap mycell
+extract -map %mymap gate
+
+select -assert-count 3 gold/t:*
+select -assert-count 3 gold/t:$add
+
+select -assert-count 3 gate/t:*
+select -assert-count 3 gate/t:mycell
+
+miter -equiv -flatten gold gate miter
+sat -verify -prove trigger 0 miter
diff --git a/tests/vloghtb/.gitignore b/tests/vloghtb/.gitignore
new file mode 100644
index 00000000..63db2fba
--- /dev/null
+++ b/tests/vloghtb/.gitignore
@@ -0,0 +1,9 @@
+Makefile
+refdat
+rtl
+scripts
+spec
+check_yosys
+vloghammer_tb.tar.bz2
+temp
+log_test_*
diff --git a/tests/vloghtb/common.sh b/tests/vloghtb/common.sh
new file mode 100644
index 00000000..3965b04c
--- /dev/null
+++ b/tests/vloghtb/common.sh
@@ -0,0 +1,70 @@
+log_pass()
+{
+ printf "%-15s %s %s %s\n" "$1" "$2" "`printf "%20s" "$2" | tr -d a-zA-Z0-9_ | tr ' ' .`" "pass."
+}
+
+log_fail()
+{
+ printf "%-15s %s %s %s\n" "$1" "$2" "`printf "%20s" "$2" | tr -d a-zA-Z0-9_ | tr ' ' .`" "FAIL."
+}
+
+test_autotest()
+{
+ # Usage:
+ # test_autotest <test_name> <synth_script> <mod_name> <vlog_file>
+
+ test_name="$1"
+ synth_cmd="$2"
+ mod_name="$3"
+ vlog_file="$4"
+
+ mkdir -p log_test_$test_name
+ rm -rf log_test_$test_name/$mod_name.*
+
+ ../../yosys -q -l log_test_$test_name/$mod_name.out -o log_test_$test_name/$mod_name.v -p "$synth_cmd" "$vlog_file"
+ cat spec/${mod_name}_spec.v scripts/check.v >> log_test_$test_name/$mod_name.v
+ iverilog -o log_test_$test_name/$mod_name.bin -D"REFDAT_FN=\"refdat/${mod_name}_refdat.txt\"" log_test_$test_name/$mod_name.v
+
+ if log_test_$test_name/$mod_name.bin 2>&1 | tee -a log_test_$test_name/$mod_name.out | grep -q '++OK++'; then
+ mv log_test_$test_name/$mod_name.out log_test_$test_name/$mod_name.txt
+ log_pass test_$test_name $mod_name
+ else
+ mv log_test_$test_name/$mod_name.out log_test_$test_name/$mod_name.err
+ log_fail test_$test_name $mod_name
+ exit 1
+ fi
+}
+
+test_equiv()
+{
+ # Usage:
+ # test_equiv <test_name> <synth_script> <sat_options> <mod_name> <vlog_file>
+
+ mkdir -p log_test_$1
+ rm -f log_test_$1/$4.txt
+ rm -f log_test_$1/$4.err
+
+ if ! ../../yosys -q -l log_test_$1/$4.out - 2> /dev/null <<- EOT
+ read_verilog $5
+ proc;;
+
+ copy $4 gold
+ rename $4 work
+
+ cd work
+ $2
+ cd ..
+
+ miter -equiv -ignore_gold_x -make_outputs -make_outcmp gold work miter
+ flatten miter
+ sat $3 -verify -prove trigger 0 -show-inputs -show-outputs miter
+ EOT
+ then
+ log_fail test_$1 $4
+ mv log_test_$1/$4.out log_test_$1/$4.err
+ exit 1
+ fi
+
+ log_pass test_$1 $4
+ mv log_test_$1/$4.out log_test_$1/$4.txt
+}
diff --git a/tests/vloghtb/run-test.sh b/tests/vloghtb/run-test.sh
new file mode 100755
index 00000000..ad99226e
--- /dev/null
+++ b/tests/vloghtb/run-test.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -ex
+
+rm -rf Makefile refdat rtl scripts spec
+wget -N http://www.clifford.at/yosys/nogit/vloghammer_tb.tar.bz2
+tar --strip=1 -xjf vloghammer_tb.tar.bz2
+
+make clean
+rm -rf log_test_*
+
+${MAKE:-make} EXIT_ON_ERROR=1 YOSYS_BIN=$PWD/../../yosys YOSYS_SCRIPT="proc;;" check_yosys
+${MAKE:-make} -f test_makefile MODE=share
+${MAKE:-make} -f test_makefile MODE=mapopt
+
diff --git a/tests/vloghtb/test_makefile b/tests/vloghtb/test_makefile
new file mode 100644
index 00000000..174dbbc2
--- /dev/null
+++ b/tests/vloghtb/test_makefile
@@ -0,0 +1,9 @@
+
+MODE := share
+TESTS := $(shell ls rtl/ | sed 's,\.v$$,,' )
+
+run: $(addprefix log_test_$(MODE)/,$(addsuffix .txt,$(TESTS)))
+
+log_test_$(MODE)/%.txt: rtl/%.v
+ @bash test_$(MODE).sh $<
+
diff --git a/tests/vloghtb/test_mapopt.sh b/tests/vloghtb/test_mapopt.sh
new file mode 100644
index 00000000..61528c2b
--- /dev/null
+++ b/tests/vloghtb/test_mapopt.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+source common.sh
+
+f=$1
+n=$(basename ${f%.v})
+
+mkdir -p log_test_mapopt
+rm -f log_test_mapopt/$n.*
+
+test_equiv mapopt_1 "opt -fine; techmap; opt" "-set-def-inputs" $n $f
+test_autotest mapopt_2 "proc; opt; techmap; opt" $n $f
+
+tail -n20 log_test_mapopt_1/$n.txt log_test_mapopt_2/$n.txt > log_test_mapopt/$n.txt
+
+exit 0
diff --git a/tests/vloghtb/test_share.sh b/tests/vloghtb/test_share.sh
new file mode 100644
index 00000000..67cfe44e
--- /dev/null
+++ b/tests/vloghtb/test_share.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+source common.sh
+
+f=$1
+n=$(basename ${f%.v})
+
+test_equiv share "wreduce; share -aggressive" "-ignore_div_by_zero" $n $f
+
+exit 0