summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2013-01-05 11:13:26 +0100
committerClifford Wolf <clifford@clifford.at>2013-01-05 11:13:26 +0100
commit7764d0ba1dcf064ae487ee985c43083a0909e7f4 (patch)
tree18c05b8729df381af71b707748ce1d605e0df764
initial import
-rw-r--r--Makefile76
-rw-r--r--README97
-rw-r--r--backends/autotest/Makefile.inc3
-rw-r--r--backends/autotest/autotest.cc309
-rw-r--r--backends/ilang/Makefile.inc3
-rw-r--r--backends/ilang/ilang_backend.cc306
-rw-r--r--backends/ilang/ilang_backend.h47
-rw-r--r--backends/verilog/Makefile.inc3
-rw-r--r--backends/verilog/verilog_backend.cc905
-rw-r--r--backends/verilog/verilog_backend.h39
-rw-r--r--bigint/.gitignore6
-rw-r--r--bigint/BigInteger.cc405
-rw-r--r--bigint/BigInteger.hh215
-rw-r--r--bigint/BigIntegerAlgorithms.cc70
-rw-r--r--bigint/BigIntegerAlgorithms.hh25
-rw-r--r--bigint/BigIntegerLibrary.hh8
-rw-r--r--bigint/BigIntegerUtils.cc50
-rw-r--r--bigint/BigIntegerUtils.hh72
-rw-r--r--bigint/BigUnsigned.cc697
-rw-r--r--bigint/BigUnsigned.hh418
-rw-r--r--bigint/BigUnsignedInABase.cc125
-rw-r--r--bigint/BigUnsignedInABase.hh122
-rw-r--r--bigint/ChangeLog146
-rw-r--r--bigint/Makefile73
-rw-r--r--bigint/NumberlikeArray.hh177
-rw-r--r--bigint/README81
-rwxr-xr-xbigint/run-testsuite37
-rw-r--r--bigint/sample.cc125
-rw-r--r--bigint/testsuite.cc326
-rw-r--r--frontends/ast/Makefile.inc5
-rw-r--r--frontends/ast/ast.cc859
-rw-r--r--frontends/ast/ast.h228
-rw-r--r--frontends/ast/genrtlil.cc1054
-rw-r--r--frontends/ast/simplify.cc1081
-rw-r--r--frontends/ilang/Makefile.inc16
-rw-r--r--frontends/ilang/ilang_frontend.cc49
-rw-r--r--frontends/ilang/ilang_frontend.h45
-rw-r--r--frontends/ilang/lexer.l122
-rw-r--r--frontends/ilang/parser.y416
-rw-r--r--frontends/verilog/Makefile.inc19
-rw-r--r--frontends/verilog/const2ast.cc197
-rw-r--r--frontends/verilog/lexer.l264
-rw-r--r--frontends/verilog/parser.y1074
-rw-r--r--frontends/verilog/preproc.cc360
-rw-r--r--frontends/verilog/verilog_frontend.cc148
-rw-r--r--frontends/verilog/verilog_frontend.h62
-rw-r--r--kernel/bitpattern.h143
-rw-r--r--kernel/calc.cc392
-rw-r--r--kernel/celltypes.h210
-rw-r--r--kernel/consteval.h198
-rw-r--r--kernel/driver.cc253
-rw-r--r--kernel/log.cc197
-rw-r--r--kernel/log.h51
-rw-r--r--kernel/register.cc288
-rw-r--r--kernel/register.h80
-rw-r--r--kernel/rtlil.cc1081
-rw-r--r--kernel/rtlil.h341
-rw-r--r--kernel/select.cc476
-rw-r--r--kernel/sha1.cpp185
-rw-r--r--kernel/sha1.h49
-rw-r--r--kernel/show.cc343
-rw-r--r--kernel/sigtools.h415
-rw-r--r--passes/abc/Makefile.inc4
-rw-r--r--passes/abc/abc.cc645
-rw-r--r--passes/abc/vlparse.cc198
-rw-r--r--passes/abc/vlparse.h28
-rw-r--r--passes/dfflibmap/Makefile.inc10
-rw-r--r--passes/dfflibmap/dfflibmap.cc326
-rw-r--r--passes/dfflibmap/filterlib.cc4
-rw-r--r--passes/dfflibmap/libparse.cc629
-rw-r--r--passes/dfflibmap/libparse.h56
-rw-r--r--passes/fsm/Makefile.inc11
-rw-r--r--passes/fsm/fsm.cc91
-rw-r--r--passes/fsm/fsm_detect.cc160
-rw-r--r--passes/fsm/fsm_expand.cc255
-rw-r--r--passes/fsm/fsm_export.cc103
-rw-r--r--passes/fsm/fsm_extract.cc359
-rw-r--r--passes/fsm/fsm_info.cc46
-rw-r--r--passes/fsm/fsm_map.cc356
-rw-r--r--passes/fsm/fsm_opt.cc285
-rw-r--r--passes/fsm/fsm_recode.cc114
-rw-r--r--passes/fsm/fsmdata.h177
-rw-r--r--passes/hierarchy/Makefile.inc3
-rw-r--r--passes/hierarchy/hierarchy.cc194
-rw-r--r--passes/memory/Makefile.inc6
-rw-r--r--passes/memory/memory.cc40
-rw-r--r--passes/memory/memory_collect.cc182
-rw-r--r--passes/memory/memory_dff.cc200
-rw-r--r--passes/memory/memory_map.cc334
-rw-r--r--passes/opt/Makefile.inc9
-rw-r--r--passes/opt/opt.cc62
-rw-r--r--passes/opt/opt_const.cc263
-rw-r--r--passes/opt/opt_muxtree.cc417
-rw-r--r--passes/opt/opt_reduce.cc236
-rw-r--r--passes/opt/opt_rmdff.cc135
-rw-r--r--passes/opt/opt_rmunused.cc239
-rw-r--r--passes/opt/opt_share.cc250
-rw-r--r--passes/opt/opt_status.h26
-rw-r--r--passes/proc/Makefile.inc8
-rw-r--r--passes/proc/proc.cc44
-rw-r--r--passes/proc/proc_arst.cc191
-rw-r--r--passes/proc/proc_clean.cc160
-rw-r--r--passes/proc/proc_dff.cc178
-rw-r--r--passes/proc/proc_mux.cc294
-rw-r--r--passes/proc/proc_rmdead.cc87
-rw-r--r--passes/submod/Makefile.inc3
-rw-r--r--passes/submod/submod.cc273
-rw-r--r--passes/techmap/Makefile.inc11
-rw-r--r--passes/techmap/techmap.cc207
-rw-r--r--techlibs/Makefile.inc7
-rw-r--r--techlibs/blackbox.sed4
-rw-r--r--techlibs/simlib.v892
-rw-r--r--techlibs/stdcells.v1378
-rw-r--r--techlibs/stdcells_sim.v166
-rw-r--r--tests/asicworld/README1
-rw-r--r--tests/asicworld/code_hdl_models_GrayCounter.v33
-rw-r--r--tests/asicworld/code_hdl_models_arbiter.v123
-rw-r--r--tests/asicworld/code_hdl_models_arbiter_tb.v62
-rw-r--r--tests/asicworld/code_hdl_models_cam.v60
-rw-r--r--tests/asicworld/code_hdl_models_clk_div.v27
-rw-r--r--tests/asicworld/code_hdl_models_clk_div_45.v54
-rw-r--r--tests/asicworld/code_hdl_models_d_ff_gates.v29
-rw-r--r--tests/asicworld/code_hdl_models_d_latch_gates.v15
-rw-r--r--tests/asicworld/code_hdl_models_decoder_2to4_gates.v14
-rw-r--r--tests/asicworld/code_hdl_models_decoder_using_assign.v20
-rw-r--r--tests/asicworld/code_hdl_models_decoder_using_case.v43
-rw-r--r--tests/asicworld/code_hdl_models_dff_async_reset.v30
-rw-r--r--tests/asicworld/code_hdl_models_dff_sync_reset.v30
-rw-r--r--tests/asicworld/code_hdl_models_dlatch_reset.v30
-rw-r--r--tests/asicworld/code_hdl_models_encoder_4to2_gates.v8
-rw-r--r--tests/asicworld/code_hdl_models_encoder_using_case.v42
-rw-r--r--tests/asicworld/code_hdl_models_encoder_using_if.v58
-rw-r--r--tests/asicworld/code_hdl_models_full_adder_gates.v18
-rw-r--r--tests/asicworld/code_hdl_models_full_subtracter_gates.v20
-rw-r--r--tests/asicworld/code_hdl_models_gray_counter.v33
-rw-r--r--tests/asicworld/code_hdl_models_half_adder_gates.v14
-rw-r--r--tests/asicworld/code_hdl_models_lfsr.v35
-rw-r--r--tests/asicworld/code_hdl_models_lfsr_updown.v35
-rw-r--r--tests/asicworld/code_hdl_models_misc1.v22
-rw-r--r--tests/asicworld/code_hdl_models_mux21_switch.v22
-rw-r--r--tests/asicworld/code_hdl_models_mux_2to1_gates.v18
-rw-r--r--tests/asicworld/code_hdl_models_mux_using_assign.v22
-rw-r--r--tests/asicworld/code_hdl_models_mux_using_case.v28
-rw-r--r--tests/asicworld/code_hdl_models_mux_using_if.v29
-rw-r--r--tests/asicworld/code_hdl_models_nand_switch.v14
-rw-r--r--tests/asicworld/code_hdl_models_one_hot_cnt.v31
-rw-r--r--tests/asicworld/code_hdl_models_parallel_crc.v53
-rw-r--r--tests/asicworld/code_hdl_models_parity_using_assign.v21
-rw-r--r--tests/asicworld/code_hdl_models_parity_using_bitwise.v16
-rw-r--r--tests/asicworld/code_hdl_models_parity_using_function.v29
-rw-r--r--tests/asicworld/code_hdl_models_pri_encoder_using_assign.v36
-rw-r--r--tests/asicworld/code_hdl_models_ram_sp_ar_sw.v58
-rw-r--r--tests/asicworld/code_hdl_models_ram_sp_sr_sw.v62
-rw-r--r--tests/asicworld/code_hdl_models_rom_using_case.v42
-rw-r--r--tests/asicworld/code_hdl_models_serial_crc.v54
-rw-r--r--tests/asicworld/code_hdl_models_t_gate_switch.v11
-rw-r--r--tests/asicworld/code_hdl_models_tff_async_reset.v27
-rw-r--r--tests/asicworld/code_hdl_models_tff_sync_reset.v27
-rw-r--r--tests/asicworld/code_hdl_models_uart.v154
-rw-r--r--tests/asicworld/code_hdl_models_up_counter.v29
-rw-r--r--tests/asicworld/code_hdl_models_up_counter_load.v32
-rw-r--r--tests/asicworld/code_hdl_models_up_down_counter.v29
-rw-r--r--tests/asicworld/code_specman_switch_fabric.v82
-rw-r--r--tests/asicworld/code_tidbits_asyn_reset.v18
-rw-r--r--tests/asicworld/code_tidbits_blocking.v17
-rw-r--r--tests/asicworld/code_tidbits_fsm_using_always.v91
-rw-r--r--tests/asicworld/code_tidbits_fsm_using_function.v94
-rw-r--r--tests/asicworld/code_tidbits_fsm_using_single_always.v63
-rw-r--r--tests/asicworld/code_tidbits_nonblocking.v17
-rw-r--r--tests/asicworld/code_tidbits_reg_combo_example.v13
-rw-r--r--tests/asicworld/code_tidbits_reg_seq_example.v15
-rw-r--r--tests/asicworld/code_tidbits_syn_reset.v19
-rw-r--r--tests/asicworld/code_tidbits_wire_example.v9
-rw-r--r--tests/asicworld/code_verilog_tutorial_addbit.v24
-rw-r--r--tests/asicworld/code_verilog_tutorial_always_example.v11
-rw-r--r--tests/asicworld/code_verilog_tutorial_bus_con.v8
-rw-r--r--tests/asicworld/code_verilog_tutorial_comment.v25
-rw-r--r--tests/asicworld/code_verilog_tutorial_counter.v19
-rw-r--r--tests/asicworld/code_verilog_tutorial_counter_tb.v113
-rw-r--r--tests/asicworld/code_verilog_tutorial_d_ff.v14
-rw-r--r--tests/asicworld/code_verilog_tutorial_decoder.v14
-rw-r--r--tests/asicworld/code_verilog_tutorial_decoder_always.v20
-rw-r--r--tests/asicworld/code_verilog_tutorial_escape_id.v14
-rw-r--r--tests/asicworld/code_verilog_tutorial_explicit.v35
-rw-r--r--tests/asicworld/code_verilog_tutorial_first_counter.v47
-rw-r--r--tests/asicworld/code_verilog_tutorial_first_counter_tb.v36
-rw-r--r--tests/asicworld/code_verilog_tutorial_flip_flop.v15
-rw-r--r--tests/asicworld/code_verilog_tutorial_fsm_full.v114
-rw-r--r--tests/asicworld/code_verilog_tutorial_fsm_full_tb.v48
-rw-r--r--tests/asicworld/code_verilog_tutorial_good_code.v18
-rw-r--r--tests/asicworld/code_verilog_tutorial_if_else.v13
-rw-r--r--tests/asicworld/code_verilog_tutorial_multiply.v8
-rw-r--r--tests/asicworld/code_verilog_tutorial_mux_21.v9
-rw-r--r--tests/asicworld/code_verilog_tutorial_n_out_primitive.v13
-rw-r--r--tests/asicworld/code_verilog_tutorial_parallel_if.v21
-rw-r--r--tests/asicworld/code_verilog_tutorial_parity.v41
-rw-r--r--tests/asicworld/code_verilog_tutorial_simple_function.v10
-rw-r--r--tests/asicworld/code_verilog_tutorial_simple_if.v11
-rw-r--r--tests/asicworld/code_verilog_tutorial_task_global.v12
-rw-r--r--tests/asicworld/code_verilog_tutorial_tri_buf.v9
-rw-r--r--tests/asicworld/code_verilog_tutorial_v2k_reg.v24
-rw-r--r--tests/asicworld/code_verilog_tutorial_which_clock.v12
-rwxr-xr-xtests/asicworld/run-test.sh3
-rw-r--r--tests/hana/README14
-rw-r--r--tests/hana/hana_vlib.v1139
-rwxr-xr-xtests/hana/run-test.sh3
-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_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_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_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_always_31_tt.v50
-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_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_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_decoder_8_test.v76
-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_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_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_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_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_ff_1_test.v4
-rw-r--r--tests/hana/test_simulation_seq_ff_2_test.v4
-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_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_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_128_test.v134
-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_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_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_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/i2c_bench/i2c_master_bit_ctrl.v576
-rw-r--r--tests/i2c_bench/i2c_master_byte_ctrl.v344
-rw-r--r--tests/i2c_bench/i2c_master_defines.v59
-rw-r--r--tests/i2c_bench/i2c_master_top.v301
-rw-r--r--tests/i2c_bench/i2c_slave_model.v361
-rwxr-xr-xtests/i2c_bench/run-test.sh50
-rw-r--r--tests/i2c_bench/spi_slave_model.v125
-rw-r--r--tests/i2c_bench/timescale.v2
-rw-r--r--tests/i2c_bench/tst_bench_top.v468
-rw-r--r--tests/i2c_bench/wb_master_model.v205
-rw-r--r--tests/iwls2005/README7
-rw-r--r--tests/iwls2005/aes_core/aes_cipher_top.v256
-rw-r--r--tests/iwls2005/aes_core/aes_inv_cipher_top.v327
-rw-r--r--tests/iwls2005/aes_core/aes_inv_sbox.v328
-rw-r--r--tests/iwls2005/aes_core/aes_key_expand_128.v87
-rw-r--r--tests/iwls2005/aes_core/aes_rcon.v96
-rw-r--r--tests/iwls2005/aes_core/aes_sbox.v329
-rw-r--r--tests/iwls2005/aes_core/timescale.v1
-rw-r--r--tests/iwls2005/fpu/except.v153
-rw-r--r--tests/iwls2005/fpu/fpu.v560
-rw-r--r--tests/iwls2005/fpu/post_norm.v676
-rw-r--r--tests/iwls2005/fpu/pre_norm.v270
-rw-r--r--tests/iwls2005/fpu/pre_norm_fmul.v150
-rw-r--r--tests/iwls2005/fpu/primitives.v103
-rw-r--r--tests/iwls2005/i2c/i2c_master_bit_ctrl.v535
-rw-r--r--tests/iwls2005/i2c/i2c_master_byte_ctrl.v344
-rw-r--r--tests/iwls2005/i2c/i2c_master_defines.v64
-rw-r--r--tests/iwls2005/i2c/i2c_master_top.v301
-rw-r--r--tests/iwls2005/i2c/timescale.v2
-rwxr-xr-xtests/iwls2005/run-fm.sh42
-rwxr-xr-xtests/iwls2005/run-synth.sh45
-rw-r--r--tests/iwls2005/run-synth.ys11
-rw-r--r--tests/iwls2005/sasc/sasc_brg.v160
-rw-r--r--tests/iwls2005/sasc/sasc_fifo4.v135
-rw-r--r--tests/iwls2005/sasc/sasc_top.v301
-rw-r--r--tests/iwls2005/sasc/timescale.v1
-rw-r--r--tests/iwls2005/simple_spi/fifo4.v134
-rw-r--r--tests/iwls2005/simple_spi/simple_spi_top.v329
-rw-r--r--tests/iwls2005/spi/spi_clgen.v108
-rw-r--r--tests/iwls2005/spi/spi_defines.v159
-rw-r--r--tests/iwls2005/spi/spi_shift.v238
-rw-r--r--tests/iwls2005/spi/spi_top.v287
-rw-r--r--tests/iwls2005/spi/timescale.v2
-rw-r--r--tests/iwls2005/ss_pcm/pcm_slv_top.v222
-rw-r--r--tests/iwls2005/ss_pcm/timescale.v1
-rw-r--r--tests/iwls2005/systemcaes/aes.v358
-rw-r--r--tests/iwls2005/systemcaes/byte_mixcolum.v92
-rw-r--r--tests/iwls2005/systemcaes/keysched.v248
-rw-r--r--tests/iwls2005/systemcaes/mixcolum.v188
-rw-r--r--tests/iwls2005/systemcaes/sbox.v392
-rw-r--r--tests/iwls2005/systemcaes/subbytes.v259
-rw-r--r--tests/iwls2005/systemcaes/timescale.v1
-rw-r--r--tests/iwls2005/systemcaes/word_mixcolum.v124
-rw-r--r--tests/iwls2005/usb_phy/timescale.v1
-rw-r--r--tests/iwls2005/usb_phy/usb_phy.v184
-rw-r--r--tests/iwls2005/usb_phy/usb_rx_phy.v452
-rw-r--r--tests/iwls2005/usb_phy/usb_tx_phy.v465
-rw-r--r--tests/no-icarus/README2
-rw-r--r--tests/no-icarus/autowire.v25
-rw-r--r--tests/no-icarus/var_range.v45
-rw-r--r--tests/openmsp430/rtl/omsp_alu.v258
-rw-r--r--tests/openmsp430/rtl/omsp_and_gate.v89
-rw-r--r--tests/openmsp430/rtl/omsp_clock_gate.v86
-rw-r--r--tests/openmsp430/rtl/omsp_clock_module.v1058
-rw-r--r--tests/openmsp430/rtl/omsp_clock_mux.v192
-rw-r--r--tests/openmsp430/rtl/omsp_dbg.v827
-rw-r--r--tests/openmsp430/rtl/omsp_dbg_hwbrk.v282
-rw-r--r--tests/openmsp430/rtl/omsp_dbg_uart.v298
-rw-r--r--tests/openmsp430/rtl/omsp_execution_unit.v420
-rw-r--r--tests/openmsp430/rtl/omsp_frontend.v966
-rw-r--r--tests/openmsp430/rtl/omsp_mem_backbone.v275
-rw-r--r--tests/openmsp430/rtl/omsp_multiplier.v420
-rw-r--r--tests/openmsp430/rtl/omsp_register_file.v618
-rw-r--r--tests/openmsp430/rtl/omsp_scan_mux.v75
-rw-r--r--tests/openmsp430/rtl/omsp_sfr.v353
-rw-r--r--tests/openmsp430/rtl/omsp_sync_cell.v80
-rw-r--r--tests/openmsp430/rtl/omsp_sync_reset.v78
-rw-r--r--tests/openmsp430/rtl/omsp_wakeup_cell.v108
-rw-r--r--tests/openmsp430/rtl/omsp_watchdog.v556
-rw-r--r--tests/openmsp430/rtl/openMSP430.v584
-rw-r--r--tests/openmsp430/rtl/openMSP430_defines.v843
-rw-r--r--tests/openmsp430/rtl/openMSP430_undefines.v732
-rw-r--r--tests/openmsp430/run-fm.do37
-rw-r--r--tests/openmsp430/run-fm.sh5
-rw-r--r--tests/openmsp430/run-synth.sh3
-rw-r--r--tests/openmsp430/run-synth.ys11
-rw-r--r--tests/openmsp430/sim_mul.v29
-rw-r--r--tests/or1200/config.patch46
-rw-r--r--tests/or1200/run-checkout.sh4
-rw-r--r--tests/or1200/run-fm-mods.sh24
-rw-r--r--tests/or1200/run-fm.do53
-rw-r--r--tests/or1200/run-fm.sh5
-rw-r--r--tests/or1200/run-synth.sh2
-rw-r--r--tests/or1200/run-synth.ys11
-rw-r--r--tests/or1200/run-vg.sh4
-rw-r--r--tests/simple/aes_kexp128.v24
-rw-r--r--tests/simple/dff_different_styles.v52
-rw-r--r--tests/simple/fiedler-cooley.v33
-rw-r--r--tests/simple/fsm.v69
-rw-r--r--tests/simple/generate.v67
-rw-r--r--tests/simple/i2c_master_tests.v62
-rw-r--r--tests/simple/loops.v79
-rw-r--r--tests/simple/mem2reg.v17
-rw-r--r--tests/simple/memory.v19
-rw-r--r--tests/simple/muxtree.v50
-rw-r--r--tests/simple/omsp_dbg_uart.v34
-rw-r--r--tests/simple/operators.v97
-rw-r--r--tests/simple/paramods.v37
-rw-r--r--tests/simple/process.v65
-rwxr-xr-xtests/simple/run-test.sh3
-rw-r--r--tests/simple/subbytes.v82
-rw-r--r--tests/simple/task_func.v35
-rw-r--r--tests/simple/usb_phy_tetsts.v36
-rw-r--r--tests/simple/values.v44
-rwxr-xr-xtests/tools/autotest.sh164
-rw-r--r--tests/tools/cmp_tbdata.c67
-rwxr-xr-xtests/tools/profiler.pl55
-rwxr-xr-xtests/tools/rtlview.sh63
-rwxr-xr-xtests/tools/vcdcd.pl201
481 files changed, 54634 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..49533d06
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,76 @@
+
+CONFIG := clang-debug
+# CONFIG := gcc-debug
+# CONFIG := release
+
+OBJS = kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/sha1.o kernel/calc.o kernel/select.o kernel/show.o
+OBJS += bigint/BigIntegerAlgorithms.o bigint/BigInteger.o bigint/BigIntegerUtils.o bigint/BigUnsigned.o bigint/BigUnsignedInABase.o
+
+GENFILES =
+TARGETS = yosys
+
+all: top-all
+
+CXXFLAGS = -Wall -Wextra -ggdb -I$(shell pwd) -MD
+LDFLAGS =
+LDLIBS = -lstdc++ -lreadline -lm
+
+-include Makefile.conf
+
+ifeq ($(CONFIG),clang-debug)
+CXX = clang
+CXXFLAGS += -std=c++11 -O0
+endif
+
+ifeq ($(CONFIG),gcc-debug)
+CXX = gcc
+CXXFLAGS += -std=gnu++0x -O0
+endif
+
+ifeq ($(CONFIG),release)
+CXX = gcc
+CXXFLAGS += -std=gnu++0x -march=native -O3 -DNDEBUG
+endif
+
+include frontends/*/Makefile.inc
+include passes/*/Makefile.inc
+include backends/*/Makefile.inc
+include techlibs/Makefile.inc
+
+top-all: $(TARGETS)
+
+yosys: $(OBJS)
+ $(CXX) -o yosys $(LDFLAGS) $(OBJS) $(LDLIBS)
+
+test: yosys
+ cd tests/simple && bash run-test.sh
+ cd tests/hana && bash run-test.sh
+ cd tests/asicworld && bash run-test.sh
+
+help:
+ @find -name '*.cc' | xargs egrep -h '(Pass|Frontend|Backend)\(".*"\)' | \
+ sed 's,.*: ,,; s, .*,,;' | sort | tr '\n' '\t' | expand -t25 | fmt
+
+install: yosys
+ install yosys /usr/local/bin/yosys
+
+clean:
+ rm -f $(OBJS) $(GENFILES) $(TARGETS)
+ rm -f bigint/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d
+
+mrproper: clean
+ svn st --no-ignore | grep '^[?I]' | cut -c8- | sed 's,^ *,,; /^Makefile.conf$$/ d;' | xargs -r -d '\n' rm -vrf
+
+qtcreator:
+ { for file in $(basename $(OBJS)); do \
+ for prefix in cc y l; do if [ -f $${file}.$${prefix} ]; then echo $$file.$${prefix}; fi; done \
+ done; find backends bigint frontends kernel passes -type f \( -name '*.h' -o -name '*.hh' \); } > qtcreator.files
+ { echo .; find backends bigint frontends kernel passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes
+ touch qtcreator.config qtcreator.creator
+
+-include bigint/*.d
+-include frontends/*/*.d
+-include passes/*/*.d
+-include backends/*/*.d
+-include kernel/*.d
+
diff --git a/README b/README
new file mode 100644
index 00000000..0a519262
--- /dev/null
+++ b/README
@@ -0,0 +1,97 @@
+
+yosys -- Yosys Open SYnthesis Suite
+===================================
+
+This is a framework for RTL synthesis tools. It is highly
+experimental and under construction. The goal for now is
+to implement an extensible Verilog-2005 synthesis tool.
+
+The aim of this tool is to generate valid logic netlists
+from HDL designs in a manner that allows for easy addition
+of extra synthesis passes. This tool does not aim at generating
+efficient logic netlists. This can be done by passing the
+output of Yosys to a low-level synthesis tool such as ABC.
+
+Yosys is free software licensed under the ISC license (a GPL
+compatible licence that is similar in terms to the MIT license
+or the 2-clause BSD license).
+
+
+Unsupported Verilog-2005 Features
+=================================
+
+The following Verilog-2005 features are not supported by
+yosys and there are currently no plans to add support
+for them:
+
+- Non-sythesizable language features as defined in
+ IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
+
+- The "tri", "triand", "trior", "wand" and "wor" net types
+
+- The "library" and "configuration" source file formats
+
+- The "disable" and "primitive" statements
+
+- Latched logic (is synthesized as logic with feedback loops)
+
+
+Verilog Attributes and non-standard features
+============================================
+
+- The 'full_case' attribute on case statements is supported
+ (also the non-standard "// synopsys full_case" directive)
+
+- The "// synopsys translate_off" and "// synopsys translate_on"
+ directives are also supported (but the use of `ifdef .. `endif
+ is strongly recommended instead).
+
+- The "nomem2reg" attribute on modules or arrays prohibits the
+ automatic early conversion of arrays to seperate registers.
+
+- The "nolatches" attribute on modules or always-blocks
+ prohibits the generation of logic-loops for latches. Instead
+ all not explicitly assigned values default to x-bits.
+
+- In addition to the (* ... *) attribute syntax, yosys supports
+ the non-standard {* ... *} attribute syntax to set default attributes
+ for everything that comes after the {* ... *} statement. (Reset
+ by adding an empty {* *} statement.) The preprocessor define
+ __YOSYS_ENABLE_DEFATTR__ must be set in order for this featre to be active.
+
+
+TODOs / Open Bugs
+=================
+
+- Write "design and implementation of.." document
+
+- Add brief sourcecode documentation to:
+
+ - Most passes and kernel functionalities
+
+- Implement missing Verilog 2005 features:
+
+ - Signed constants
+ - ROM modelling using "initial" blocks
+ - Builtin primitive gates (and, nand, cmos, nmos, pmos, etc..)
+ - Ignore what needs to be ignored (e.g. drive and charge strenghts)
+ - Check standard vs. implementation to identify missing features
+
+- Actually use range information on parameters
+
+- Implement mux-to-tribuf pass and rebalance mixed mux/tribuf trees
+
+- TCL and Python interfaces to frontends, passes, backends and RTLIL
+
+- Additional internal cell types: $bitcount, $pla, $lut and $pmux
+
+- Subsystem for selecting stuff (and limiting scope of passes)
+
+- Support for registering designs (as collection of modules) to CellTypes
+
+- Kernel support for collections of cells (from input/output cones, etc)
+
+- Smarter resource sharing pass (add MUXes and get rid of duplicated cells)
+
+- FSM state encoding and technology mapping
+
diff --git a/backends/autotest/Makefile.inc b/backends/autotest/Makefile.inc
new file mode 100644
index 00000000..9308dcd4
--- /dev/null
+++ b/backends/autotest/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += backends/autotest/autotest.o
+
diff --git a/backends/autotest/autotest.cc b/backends/autotest/autotest.cc
new file mode 100644
index 00000000..36d5650f
--- /dev/null
+++ b/backends/autotest/autotest.cc
@@ -0,0 +1,309 @@
+/*
+ * 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;
+ 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->attributes.count("\\gentb_clock") > 0;
+ 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(\"%%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();\n");
+ for (auto &hdr : header1)
+ fprintf(f, "\t$display(\" %s\");\n", hdr.c_str());
+ fprintf(f, "\t$display();\n");
+ fprintf(f, "\t$display(\"%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(\"\\n==== %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++)
+ 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") { }
+ 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/ilang/Makefile.inc b/backends/ilang/Makefile.inc
new file mode 100644
index 00000000..52fc2b89
--- /dev/null
+++ b/backends/ilang/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += backends/ilang/ilang_backend.o
+
diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc
new file mode 100644
index 00000000..7e283723
--- /dev/null
+++ b/backends/ilang/ilang_backend.cc
@@ -0,0 +1,306 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * ---
+ *
+ * A very simple and straightforward backend for the RTLIL text
+ * representation (as understood by the 'ilang' frontend).
+ *
+ */
+
+#include "ilang_backend.h"
+#include "kernel/register.h"
+#include "kernel/log.h"
+#include <string>
+#include <assert.h>
+
+using namespace ILANG_BACKEND;
+
+void ILANG_BACKEND::dump_const(FILE *f, const RTLIL::Const &data, int width, int offset, bool autoint)
+{
+ if (width < 0)
+ width = data.bits.size() - offset;
+ if (data.str.empty() || width != (int)data.bits.size()) {
+ if (width == 32 && autoint) {
+ int32_t val = 0;
+ for (int i = 0; i < width; i++) {
+ assert(offset+i < (int)data.bits.size());
+ switch (data.bits[offset+i]) {
+ case RTLIL::S0: break;
+ case RTLIL::S1: val |= 1 << i; break;
+ default: val = -1; break;
+ }
+ }
+ if (val >= 0) {
+ fprintf(f, "%d", val);
+ return;
+ }
+ }
+ fprintf(f, "%d'", width);
+ for (int i = offset+width-1; i >= offset; i--) {
+ 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;
+ }
+ }
+ } else {
+ fprintf(f, "\"");
+ for (size_t i = 0; i < data.str.size(); i++) {
+ if (data.str[i] == '\n')
+ fprintf(f, "\\n");
+ else if (data.str[i] == '\t')
+ fprintf(f, "\\t");
+ else if (data.str[i] < 32)
+ fprintf(f, "\\%03o", data.str[i]);
+ else if (data.str[i] == '"')
+ fprintf(f, "\\\"");
+ else
+ fputc(data.str[i], f);
+ }
+ fprintf(f, "\"");
+ }
+}
+
+void ILANG_BACKEND::dump_sigchunk(FILE *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());
+ else if (chunk.width == 1)
+ fprintf(f, "%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);
+ }
+}
+
+void ILANG_BACKEND::dump_sigspec(FILE *f, const RTLIL::SigSpec &sig, bool autoint)
+{
+ if (sig.chunks.size() == 1) {
+ dump_sigchunk(f, sig.chunks[0], autoint);
+ } else {
+ fprintf(f, "{ ");
+ for (auto it = sig.chunks.rbegin(); it != sig.chunks.rend(); it++) {
+ dump_sigchunk(f, *it, false);
+ fprintf(f, " ");
+ }
+ fprintf(f, "}");
+ }
+}
+
+void ILANG_BACKEND::dump_wire(FILE *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());
+ dump_const(f, it->second);
+ fprintf(f, "\n");
+ }
+ fprintf(f, "%s" "wire ", indent.c_str());
+ if (wire->auto_width)
+ fprintf(f, "auto ");
+ if (wire->width != 1)
+ fprintf(f, "width %d ", wire->width);
+ if (wire->start_offset != 0)
+ fprintf(f, "offset %d ", wire->start_offset);
+ if (wire->port_input && !wire->port_output)
+ fprintf(f, "input %d ", wire->port_id);
+ if (!wire->port_input && wire->port_output)
+ fprintf(f, "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());
+}
+
+void ILANG_BACKEND::dump_memory(FILE *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());
+ dump_const(f, it->second);
+ fprintf(f, "\n");
+ }
+ fprintf(f, "%s" "memory ", indent.c_str());
+ if (memory->width != 1)
+ fprintf(f, "width %d ", memory->width);
+ if (memory->size != 0)
+ fprintf(f, "size %d ", memory->size);
+ fprintf(f, "%s\n", memory->name.c_str());
+}
+
+void ILANG_BACKEND::dump_cell(FILE *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());
+ dump_const(f, it->second);
+ fprintf(f, "\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 ", indent.c_str(), it->first.c_str());
+ dump_const(f, it->second);
+ fprintf(f, "\n");
+ }
+ for (auto it = cell->connections.begin(); it != cell->connections.end(); it++) {
+ fprintf(f, "%s connect %s ", indent.c_str(), it->first.c_str());
+ dump_sigspec(f, it->second);
+ fprintf(f, "\n");
+ }
+ fprintf(f, "%s" "end\n", indent.c_str());
+}
+
+void ILANG_BACKEND::dump_proc_case_body(FILE *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());
+ dump_sigspec(f, it->first);
+ fprintf(f, " ");
+ dump_sigspec(f, it->second);
+ fprintf(f, "\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)
+{
+ for (auto it = sw->attributes.begin(); it != sw->attributes.end(); it++) {
+ fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
+ dump_const(f, it->second);
+ fprintf(f, "\n");
+ }
+
+ fprintf(f, "%s" "switch ", indent.c_str());
+ dump_sigspec(f, sw->signal);
+ fprintf(f, "\n");
+
+ for (auto it = sw->cases.begin(); it != sw->cases.end(); it++)
+ {
+ fprintf(f, "%s case ", indent.c_str());
+ for (size_t i = 0; i < (*it)->compare.size(); i++) {
+ if (i > 0)
+ fprintf(f, ", ");
+ dump_sigspec(f, (*it)->compare[i]);
+ }
+ fprintf(f, "\n");
+
+ dump_proc_case_body(f, indent + " ", *it);
+ }
+
+ fprintf(f, "%s" "end\n", indent.c_str());
+}
+
+void ILANG_BACKEND::dump_proc_sync(FILE *f, std::string indent, const RTLIL::SyncRule *sy)
+{
+ fprintf(f, "%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 ");
+ dump_sigspec(f, sy->signal);
+ fprintf(f, "\n");
+ break;
+ case RTLIL::STa: fprintf(f, "always\n"); break;
+ }
+
+ for (auto it = sy->actions.begin(); it != sy->actions.end(); it++) {
+ fprintf(f, "%s update ", indent.c_str());
+ dump_sigspec(f, it->first);
+ fprintf(f, " ");
+ dump_sigspec(f, it->second);
+ fprintf(f, "\n");
+ }
+}
+
+void ILANG_BACKEND::dump_proc(FILE *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());
+ dump_const(f, it->second);
+ fprintf(f, "\n");
+ }
+ fprintf(f, "%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());
+}
+
+void ILANG_BACKEND::dump_conn(FILE *f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
+{
+ fprintf(f, "%s" "connect ", indent.c_str());
+ dump_sigspec(f, left);
+ fprintf(f, " ");
+ dump_sigspec(f, right);
+ fprintf(f, "\n");
+}
+
+void ILANG_BACKEND::dump_module(FILE *f, std::string indent, const RTLIL::Module *module)
+{
+ for (auto it = module->attributes.begin(); it != module->attributes.end(); it++) {
+ fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
+ dump_const(f, it->second);
+ fprintf(f, "\n");
+ }
+
+ fprintf(f, "%s" "module %s\n", indent.c_str(), module->name.c_str());
+
+ 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++)
+ dump_cell(f, indent + " ", it->second);
+
+ for (auto it = module->processes.begin(); it != module->processes.end(); it++)
+ dump_proc(f, indent + " ", it->second);
+
+ for (auto it = module->connections.begin(); it != module->connections.end(); it++)
+ dump_conn(f, indent + " ", it->first, it->second);
+
+ fprintf(f, "%s" "end\n", indent.c_str());
+}
+
+void ILANG_BACKEND::dump_design(FILE *f, const RTLIL::Design *design)
+{
+ for (auto it = design->modules.begin(); it != design->modules.end(); it++) {
+ if (it != design->modules.begin())
+ fprintf(f, "\n");
+ dump_module(f, "", it->second);
+ }
+}
+
+struct IlangBackend : public Backend {
+ IlangBackend() : Backend("ilang") { }
+ virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) {
+ log_header("Executing ILANG backend.\n");
+ extra_args(f, filename, args, 1);
+ log("Output filename: %s\n", filename.c_str());
+ ILANG_BACKEND::dump_design(f, design);
+ }
+} IlangBackend;
+
diff --git a/backends/ilang/ilang_backend.h b/backends/ilang/ilang_backend.h
new file mode 100644
index 00000000..e34c4e67
--- /dev/null
+++ b/backends/ilang/ilang_backend.h
@@ -0,0 +1,47 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * ---
+ *
+ * A very simple and straightforward backend for the RTLIL text
+ * representation (as understood by the 'ilang' frontend).
+ *
+ */
+
+#ifndef ILANG_BACKEND_H
+#define ILANG_BACKEND_H
+
+#include "kernel/rtlil.h"
+#include <stdio.h>
+
+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);
+ void dump_design(FILE *f, const RTLIL::Design *design);
+}
+
+#endif
diff --git a/backends/verilog/Makefile.inc b/backends/verilog/Makefile.inc
new file mode 100644
index 00000000..c2dffef7
--- /dev/null
+++ b/backends/verilog/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += backends/verilog/verilog_backend.o
+
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
new file mode 100644
index 00000000..d7990800
--- /dev/null
+++ b/backends/verilog/verilog_backend.cc
@@ -0,0 +1,905 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * ---
+ *
+ * A simple and straightforward verilog backend.
+ *
+ * Note that RTLIL processes can't always be mapped easily to a Verilog
+ * process. Therefore this frontend should only be used to export a
+ * Verilog netlist (i.e. after the "proc" pass has converted all processes
+ * to logic networks and registers).
+ *
+ */
+
+#include "verilog_backend.h"
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/log.h"
+#include <assert.h>
+#include <string>
+#include <sstream>
+#include <set>
+#include <map>
+
+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::set<std::string> reg_wires;
+
+CellTypes reg_ct;
+RTLIL::Module *active_module;
+
+void reset_auto_counter_id(const std::string &id, bool may_rename)
+{
+ const char *str = id.c_str();
+
+ if (*str == '$' && may_rename && !norename)
+ auto_name_map[id] = auto_name_counter++;
+
+ if (str[0] != '_' && str[1] != 0)
+ return;
+ for (int i = 0; str[i] != 0; i++) {
+ if (str[i] == '_')
+ continue;
+ if (str[i] < '0' || str[i] > '9')
+ return;
+ }
+
+ int num = atoi(str+1);
+ if (num >= auto_name_offset)
+ auto_name_offset = num + 1;
+}
+
+void reset_auto_counter(RTLIL::Module *module)
+{
+ auto_name_map.clear();
+ auto_name_counter = 0;
+ auto_name_offset = 0;
+
+ reset_auto_counter_id(module->name, false);
+
+ 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++) {
+ reset_auto_counter_id(it->second->name, true);
+ reset_auto_counter_id(it->second->type, false);
+ }
+
+ for (auto it = module->processes.begin(); it != module->processes.end(); it++)
+ reset_auto_counter_id(it->second->name, false);
+
+ auto_name_digits = 1;
+ for (size_t i = 10; i < auto_name_offset + auto_name_map.size(); i = i*10)
+ auto_name_digits++;
+
+ for (auto it = auto_name_map.begin(); it != auto_name_map.end(); it++)
+ 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)
+{
+ const char *str = internal_id.c_str();
+ bool do_escape = false;
+
+ if (may_rename && auto_name_map.count(internal_id) != 0) {
+ char buffer[100];
+ snprintf(buffer, 100, "_%0*d_", auto_name_digits, auto_name_offset + auto_name_map[internal_id]);
+ return std::string(buffer);
+ }
+
+ 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);
+}
+
+bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
+{
+ sig.optimize();
+ if (sig.chunks.size() != 1 || sig.chunks[0].wire == NULL)
+ return false;
+ if (reg_wires.count(sig.chunks[0].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);
+ else
+ reg_name += stringf("[%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);
+ return true;
+}
+
+void dump_const(FILE *f, RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false)
+{
+ if (width < 0)
+ width = data.bits.size() - offset;
+ if (data.str.empty() || width != (int)data.bits.size()) {
+ if (width == 32 && !no_decimal) {
+ uint32_t val = 0;
+ for (int i = offset+width-1; i >= offset; i--) {
+ 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)
+ val |= 1 << (i - offset);
+ }
+ fprintf(f, "%d", (int)val);
+ } else {
+ dump_bits:
+ fprintf(f, "%d'b", width);
+ for (int i = offset+width-1; i >= offset; i--) {
+ 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::Sm: log_error("Found marker state in final netlist.");
+ }
+ }
+ }
+ } else {
+ fprintf(f, "\"");
+ for (size_t i = 0; i < data.str.size(); i++) {
+ if (data.str[i] == '\n')
+ fprintf(f, "\\n");
+ else if (data.str[i] == '\t')
+ fprintf(f, "\\t");
+ else if (data.str[i] < 32)
+ fprintf(f, "\\%03o", data.str[i]);
+ else if (data.str[i] == '"')
+ fprintf(f, "\\\"");
+ else
+ fputc(data.str[i], f);
+ }
+ fprintf(f, "\"");
+ }
+}
+
+void dump_sigchunk(FILE *f, 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);
+ }
+}
+
+void dump_sigspec(FILE *f, RTLIL::SigSpec &sig)
+{
+ if (sig.chunks.size() == 1) {
+ dump_sigchunk(f, sig.chunks[0]);
+ } else {
+ fprintf(f, "{ ");
+ for (auto it = sig.chunks.rbegin(); it != sig.chunks.rend(); it++) {
+ if (it != sig.chunks.rbegin())
+ fprintf(f, ", ");
+ dump_sigchunk(f, *it, true);
+ }
+ fprintf(f, " }");
+ }
+}
+
+void dump_attributes(FILE *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());
+ if (it->second.bits.size() > 0) {
+ fprintf(f, " = ");
+ dump_const(f, it->second);
+ }
+ fprintf(f, " %s%c", attr2comment ? "*/" : "*)", term);
+ }
+}
+
+void dump_wire(FILE *f, std::string indent, RTLIL::Wire *wire)
+{
+ dump_attributes(f, indent, wire->attributes);
+ if (wire->port_input && !wire->port_output)
+ fprintf(f, "%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 " : "");
+ else if (wire->port_input && wire->port_output)
+ fprintf(f, "%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");
+ 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());
+}
+
+void dump_memory(FILE *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);
+}
+
+void dump_cell_expr_port(FILE *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, ")");
+ } else
+ dump_sigspec(f, cell->connections["\\" + port]);
+}
+
+std::string cellname(RTLIL::Cell *cell)
+{
+ if (!norename && cell->name[0] == '$' && reg_ct.cell_known(cell->type) && cell->connections.count("\\Q") > 0)
+ {
+ RTLIL::SigSpec sig = cell->connections["\\Q"];
+ if (sig.width != 1 || sig.is_fully_const())
+ goto no_special_reg_name;
+
+ sig.optimize();
+ RTLIL::Wire *wire = sig.chunks[0].wire;
+
+ if (wire->name[0] != '\\')
+ goto no_special_reg_name;
+
+ std::string cell_name = wire->name;
+
+ size_t pos = cell_name.find('[');
+ if (pos != std::string::npos)
+ cell_name = cell_name.substr(0, pos) + "_reg" + cell_name.substr(pos);
+ else
+ cell_name = cell_name + "_reg";
+
+ if (wire->width != 1)
+ cell_name += stringf("[%d]", wire->start_offset + sig.chunks[0].offset);
+
+ if (active_module && active_module->count_id(cell_name) > 0)
+ goto no_special_reg_name;
+
+ return id(cell_name);
+ }
+ else
+ {
+no_special_reg_name:
+ return id(cell->name).c_str();
+ }
+}
+
+void dump_cell_expr_uniop(FILE *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());
+ dump_attributes(f, "", cell->attributes, ' ');
+ dump_cell_expr_port(f, cell, "A", true);
+ fprintf(f, ";\n");
+}
+
+void dump_cell_expr_binop(FILE *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, " = ");
+ dump_cell_expr_port(f, cell, "A", true);
+ fprintf(f, " %s ", op.c_str());
+ dump_attributes(f, "", cell->attributes, ' ');
+ dump_cell_expr_port(f, cell, "B", true);
+ fprintf(f, ";\n");
+}
+
+bool dump_cell_expr(FILE *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, "~");
+ dump_attributes(f, "", cell->attributes, ' ');
+ dump_cell_expr_port(f, cell, "A", false);
+ fprintf(f, ";\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, " = ");
+ 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, "^");
+ dump_attributes(f, "", cell->attributes, ' ');
+ fprintf(f, " ");
+ dump_cell_expr_port(f, cell, "B", false);
+ fprintf(f, ";\n");
+ return true;
+ }
+
+ if (cell->type == "$_MUX_") {
+ fprintf(f, "%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->connections["\\Y"]);
+ fprintf(f, " = ");
+ dump_cell_expr_port(f, cell, "S", false);
+ fprintf(f, " ? ");
+ dump_attributes(f, "", cell->attributes, ' ');
+ dump_cell_expr_port(f, cell, "B", false);
+ fprintf(f, " : ");
+ dump_cell_expr_port(f, cell, "A", false);
+ fprintf(f, ";\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);
+
+ if (!out_is_reg_wire)
+ fprintf(f, "%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"]);
+ if (cell->type[7] != '_') {
+ fprintf(f, " or %sedge ", cell->type[7] == 'P' ? "pos" : "neg");
+ dump_sigspec(f, cell->connections["\\R"]);
+ }
+ fprintf(f, ")\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());
+ }
+
+ fprintf(f, "%s" " %s <= ", indent.c_str(), reg_name.c_str());
+ dump_cell_expr_port(f, cell, "D", false);
+ fprintf(f, ";\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());
+ }
+
+ return true;
+ }
+
+#define HANDLE_UNIOP(_type, _operator) \
+ if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
+#define HANDLE_BINOP(_type, _operator) \
+ if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
+
+ HANDLE_UNIOP("$not", "~")
+ HANDLE_UNIOP("$pos", "+")
+ HANDLE_UNIOP("$neg", "-")
+
+ HANDLE_BINOP("$and", "&")
+ HANDLE_BINOP("$or", "|")
+ HANDLE_BINOP("$xor", "^")
+ HANDLE_BINOP("$xnor", "~^")
+
+ HANDLE_UNIOP("$reduce_and", "&")
+ HANDLE_UNIOP("$reduce_or", "|")
+ HANDLE_UNIOP("$reduce_xor", "^")
+ HANDLE_UNIOP("$reduce_xnor", "~^")
+ HANDLE_UNIOP("$reduce_bool", "|")
+
+ HANDLE_BINOP("$shl", "<<")
+ HANDLE_BINOP("$shr", ">>")
+ HANDLE_BINOP("$sshl", "<<<")
+ HANDLE_BINOP("$sshr", ">>>")
+
+ HANDLE_BINOP("$lt", "<")
+ HANDLE_BINOP("$le", "<=")
+ HANDLE_BINOP("$eq", "==")
+ HANDLE_BINOP("$ne", "!=")
+ HANDLE_BINOP("$ge", ">=")
+ HANDLE_BINOP("$gt", ">")
+
+ HANDLE_BINOP("$add", "+")
+ HANDLE_BINOP("$sub", "-")
+ HANDLE_BINOP("$mul", "*")
+ HANDLE_BINOP("$div", "/")
+ HANDLE_BINOP("$mod", "%")
+ HANDLE_BINOP("$pow", "**")
+
+ HANDLE_UNIOP("$logic_not", "!")
+ HANDLE_BINOP("$logic_and", "&&")
+ HANDLE_BINOP("$logic_or", "||")
+
+#undef HANDLE_UNIOP
+#undef HANDLE_BINOP
+
+ if (cell->type == "$mux" || 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());
+
+ 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");
+
+ for (int i = 0; i < s_width; i++)
+ {
+ fprintf(f, "%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' : '?');
+
+ 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");
+ }
+
+ 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());
+ return true;
+ }
+
+ if (cell->type == "$dff" || cell->type == "$adff")
+ {
+ RTLIL::SigSpec sig_clk, sig_arst, val_arst;
+ bool pol_clk, pol_arst = false;
+
+ sig_clk = cell->connections["\\CLK"];
+ pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
+
+ if (cell->type == "$adff") {
+ sig_arst = cell->connections["\\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);
+
+ 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());
+
+ fprintf(f, "%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");
+ dump_sigspec(f, sig_arst);
+ }
+ fprintf(f, ")\n");
+
+ if (cell->type == "$adff") {
+ fprintf(f, "%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());
+ dump_sigspec(f, val_arst);
+ fprintf(f, ";\n");
+ fprintf(f, "%s" " else\n", indent.c_str());
+ }
+
+ fprintf(f, "%s" " %s <= ", indent.c_str(), reg_name.c_str());
+ dump_cell_expr_port(f, cell, "D", false);
+ fprintf(f, ";\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());
+ }
+
+ return true;
+ }
+
+ // FIXME: $memrd, $memwr, $mem, $fsm
+
+ return false;
+}
+
+void dump_cell(FILE *f, std::string indent, RTLIL::Cell *cell)
+{
+ if (cell->type[0] == '$' && !noexpr) {
+ if (dump_cell_expr(f, indent, cell))
+ return;
+ }
+
+ dump_attributes(f, indent, cell->attributes);
+ fprintf(f, "%s" "%s", indent.c_str(), id(cell->type, false).c_str());
+
+ if (cell->parameters.size() > 0) {
+ fprintf(f, " #(");
+ 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());
+ dump_const(f, it->second);
+ fprintf(f, ")");
+ }
+ fprintf(f, "\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());
+ else
+ fprintf(f, " %s (", cell_name.c_str());
+
+ bool first_arg = true;
+ std::set<std::string> 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++) {
+ if (it->first != str)
+ continue;
+ if (!first_arg)
+ fprintf(f, ",");
+ first_arg = false;
+ fprintf(f, "\n%s ", indent.c_str());
+ dump_sigspec(f, it->second);
+ numbered_ports.insert(it->first);
+ goto found_numbered_port;
+ }
+ break;
+ found_numbered_port:;
+ }
+ for (auto it = cell->connections.begin(); it != cell->connections.end(); it++) {
+ if (numbered_ports.count(it->first))
+ continue;
+ if (!first_arg)
+ fprintf(f, ",");
+ first_arg = false;
+ fprintf(f, "\n%s .%s(", indent.c_str(), id(it->first).c_str());
+ if (it->second.width > 0)
+ dump_sigspec(f, it->second);
+ fprintf(f, ")");
+ }
+ fprintf(f, "\n%s" ");\n", indent.c_str());
+}
+
+void dump_conn(FILE *f, std::string indent, RTLIL::SigSpec &left, RTLIL::SigSpec &right)
+{
+ fprintf(f, "%s" "assign ", indent.c_str());
+ dump_sigspec(f, left);
+ fprintf(f, " = ");
+ dump_sigspec(f, right);
+ fprintf(f, ";\n");
+}
+
+void dump_proc_switch(FILE *f, std::string indent, RTLIL::SwitchRule *sw);
+
+void dump_case_body(FILE *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());
+
+ for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
+ if (it->first.width == 0)
+ continue;
+ fprintf(f, "%s ", indent.c_str());
+ dump_sigspec(f, it->first);
+ fprintf(f, " = ");
+ dump_sigspec(f, it->second);
+ fprintf(f, ";\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());
+
+ if (omit_trailing_begin || number_of_stmts >= 2)
+ fprintf(f, "%s" "end\n", indent.c_str());
+}
+
+void dump_proc_switch(FILE *f, std::string indent, RTLIL::SwitchRule *sw)
+{
+ if (sw->signal.width == 0) {
+ fprintf(f, "%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());
+ return;
+ }
+
+ fprintf(f, "%s" "casez (", indent.c_str());
+ dump_sigspec(f, sw->signal);
+ fprintf(f, ")\n");
+
+ for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
+ fprintf(f, "%s ", indent.c_str());
+ if ((*it)->compare.size() == 0)
+ fprintf(f, "default");
+ else {
+ for (size_t i = 0; i < (*it)->compare.size(); i++) {
+ if (i > 0)
+ fprintf(f, ", ");
+ dump_sigspec(f, (*it)->compare[i]);
+ }
+ }
+ fprintf(f, ":\n");
+ dump_case_body(f, indent + " ", *it);
+ }
+
+ fprintf(f, "%s" "endcase\n", indent.c_str());
+}
+
+void case_body_find_regs(RTLIL::CaseRule *cs)
+{
+ for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
+ for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
+ case_body_find_regs(*it2);
+
+ for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
+ for (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);
+ }
+}
+
+void dump_process(FILE *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);
+ }
+ return;
+ }
+
+ fprintf(f, "%s" "always @* begin\n", indent.c_str());
+ dump_case_body(f, indent, &proc->root_case, true);
+
+ std::string backup_indent = indent;
+
+ for (size_t i = 0; i < proc->syncs.size(); i++)
+ {
+ RTLIL::SyncRule *sync = proc->syncs[i];
+ indent = backup_indent;
+
+ if (sync->type == RTLIL::STa) {
+ fprintf(f, "%s" "always @* begin\n", indent.c_str());
+ } else {
+ fprintf(f, "%s" "always @(", indent.c_str());
+ if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
+ fprintf(f, "posedge ");
+ if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
+ fprintf(f, "negedge ");
+ dump_sigspec(f, sync->signal);
+ fprintf(f, ") 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 ? "!" : "");
+ dump_sigspec(f, sync->signal);
+ fprintf(f, ") begin\n");
+ ends = indent + "end\n" + ends;
+ indent += " ";
+ }
+
+ if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) {
+ 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 ? "!" : "");
+ dump_sigspec(f, sync2->signal);
+ fprintf(f, ") begin\n");
+ ends = indent + "end\n" + ends;
+ indent += " ";
+ }
+ }
+ }
+
+ for (auto it = sync->actions.begin(); it != sync->actions.end(); it++) {
+ if (it->first.width == 0)
+ continue;
+ fprintf(f, "%s ", indent.c_str());
+ dump_sigspec(f, it->first);
+ fprintf(f, " <= ");
+ dump_sigspec(f, it->second);
+ fprintf(f, ";\n");
+ }
+
+ fprintf(f, "%s", ends.c_str());
+ }
+}
+
+void dump_module(FILE *f, std::string indent, RTLIL::Module *module)
+{
+ reg_wires.clear();
+ reset_auto_counter(module);
+ active_module = module;
+
+ 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)
+ {
+ RTLIL::Cell *cell = it.second;
+ if (!reg_ct.cell_known(cell->type) || cell->connections.count("\\Q") == 0)
+ continue;
+
+ RTLIL::SigSpec sig = cell->connections["\\Q"];
+ sig.optimize();
+
+ 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));
+ }
+ 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);
+ this_wire_aint_reg:;
+ }
+ }
+
+ dump_attributes(f, indent, module->attributes);
+ fprintf(f, "%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++) {
+ 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());
+ keep_running = true;
+ continue;
+ }
+ }
+ }
+ fprintf(f, ");\n");
+
+ 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++)
+ 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++)
+ dump_conn(f, indent + " ", it->first, it->second);
+
+ fprintf(f, "%s" "endmodule\n", indent.c_str());
+ active_module = NULL;
+}
+
+} /* namespace */
+
+struct VerilogBackend : public Backend {
+ VerilogBackend() : Backend("verilog") { }
+ virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Executing Verilog backend.\n");
+
+ norename = false;
+ noattr = false;
+ attr2comment = false;
+ noexpr = false;
+
+ reg_ct.clear();
+ reg_ct.setup_stdcells_mem();
+ reg_ct.cell_types.insert("$dff");
+ reg_ct.cell_types.insert("$adff");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ std::string arg = args[argidx];
+ if (arg == "-norename") {
+ norename = true;
+ continue;
+ }
+ if (arg == "-noattr") {
+ noattr = true;
+ continue;
+ }
+ if (arg == "-attr2comment") {
+ attr2comment = true;
+ continue;
+ }
+ if (arg == "-noexpr") {
+ noexpr = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ for (auto it = design->modules.begin(); it != design->modules.end(); it++) {
+ log("Dumping module `%s'.\n", it->first.c_str());
+ if (it != design->modules.begin())
+ fprintf(f, "\n");
+ dump_module(f, "", it->second);
+ }
+
+ reg_ct.clear();
+ }
+} VerilogBackend;
+
diff --git a/backends/verilog/verilog_backend.h b/backends/verilog/verilog_backend.h
new file mode 100644
index 00000000..c40830ef
--- /dev/null
+++ b/backends/verilog/verilog_backend.h
@@ -0,0 +1,39 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * ---
+ *
+ * A simple and straightforward verilog backend.
+ *
+ * Note that RTLIL processes can't always be mapped easily to a Verilog
+ * process. Therefore this frontend should only be used to export a
+ * Verilog netlist (i.e. after the "proc" pass has converted all processes
+ * to logic networks and registers).
+ *
+ */
+
+#ifndef VERILOG_BACKEND_H
+#define VERILOG_BACKEND_H
+
+#include "kernel/rtlil.h"
+#include <stdio.h>
+
+namespace VERILOG_BACKEND {
+ void verilog_backend(FILE *f, std::vector<std::string> args, RTLIL::Design *design);
+}
+
+#endif
diff --git a/bigint/.gitignore b/bigint/.gitignore
new file mode 100644
index 00000000..4467edcf
--- /dev/null
+++ b/bigint/.gitignore
@@ -0,0 +1,6 @@
+*.o
+sample
+testsuite
+testsuite.expected
+testsuite.out
+testsuite.err
diff --git a/bigint/BigInteger.cc b/bigint/BigInteger.cc
new file mode 100644
index 00000000..3b23aa1e
--- /dev/null
+++ b/bigint/BigInteger.cc
@@ -0,0 +1,405 @@
+#include "BigInteger.hh"
+
+void BigInteger::operator =(const BigInteger &x) {
+ // Calls like a = a have no effect
+ if (this == &x)
+ return;
+ // Copy sign
+ sign = x.sign;
+ // Copy the rest
+ mag = x.mag;
+}
+
+BigInteger::BigInteger(const Blk *b, Index blen, Sign s) : mag(b, blen) {
+ switch (s) {
+ case zero:
+ if (!mag.isZero())
+ throw "BigInteger::BigInteger(const Blk *, Index, Sign): Cannot use a sign of zero with a nonzero magnitude";
+ sign = zero;
+ break;
+ case positive:
+ case negative:
+ // If the magnitude is zero, force the sign to zero.
+ sign = mag.isZero() ? zero : s;
+ break;
+ default:
+ /* g++ seems to be optimizing out this case on the assumption
+ * that the sign is a valid member of the enumeration. Oh well. */
+ throw "BigInteger::BigInteger(const Blk *, Index, Sign): Invalid sign";
+ }
+}
+
+BigInteger::BigInteger(const BigUnsigned &x, Sign s) : mag(x) {
+ switch (s) {
+ case zero:
+ if (!mag.isZero())
+ throw "BigInteger::BigInteger(const BigUnsigned &, Sign): Cannot use a sign of zero with a nonzero magnitude";
+ sign = zero;
+ break;
+ case positive:
+ case negative:
+ // If the magnitude is zero, force the sign to zero.
+ sign = mag.isZero() ? zero : s;
+ break;
+ default:
+ /* g++ seems to be optimizing out this case on the assumption
+ * that the sign is a valid member of the enumeration. Oh well. */
+ throw "BigInteger::BigInteger(const BigUnsigned &, Sign): Invalid sign";
+ }
+}
+
+/* CONSTRUCTION FROM PRIMITIVE INTEGERS
+ * Same idea as in BigUnsigned.cc, except that negative input results in a
+ * negative BigInteger instead of an exception. */
+
+// Done longhand to let us use initialization.
+BigInteger::BigInteger(unsigned long x) : mag(x) { sign = mag.isZero() ? zero : positive; }
+BigInteger::BigInteger(unsigned int x) : mag(x) { sign = mag.isZero() ? zero : positive; }
+BigInteger::BigInteger(unsigned short x) : mag(x) { sign = mag.isZero() ? zero : positive; }
+
+// For signed input, determine the desired magnitude and sign separately.
+
+namespace {
+ template <class X, class UX>
+ BigInteger::Blk magOf(X x) {
+ /* UX(...) cast needed to stop short(-2^15), which negates to
+ * itself, from sign-extending in the conversion to Blk. */
+ return BigInteger::Blk(x < 0 ? UX(-x) : x);
+ }
+ template <class X>
+ BigInteger::Sign signOf(X x) {
+ return (x == 0) ? BigInteger::zero
+ : (x > 0) ? BigInteger::positive
+ : BigInteger::negative;
+ }
+}
+
+BigInteger::BigInteger(long x) : sign(signOf(x)), mag(magOf<long , unsigned long >(x)) {}
+BigInteger::BigInteger(int x) : sign(signOf(x)), mag(magOf<int , unsigned int >(x)) {}
+BigInteger::BigInteger(short x) : sign(signOf(x)), mag(magOf<short, unsigned short>(x)) {}
+
+// CONVERSION TO PRIMITIVE INTEGERS
+
+/* Reuse BigUnsigned's conversion to an unsigned primitive integer.
+ * The friend is a separate function rather than
+ * BigInteger::convertToUnsignedPrimitive to avoid requiring BigUnsigned to
+ * declare BigInteger. */
+template <class X>
+inline X convertBigUnsignedToPrimitiveAccess(const BigUnsigned &a) {
+ return a.convertToPrimitive<X>();
+}
+
+template <class X>
+X BigInteger::convertToUnsignedPrimitive() const {
+ if (sign == negative)
+ throw "BigInteger::to<Primitive>: "
+ "Cannot convert a negative integer to an unsigned type";
+ else
+ return convertBigUnsignedToPrimitiveAccess<X>(mag);
+}
+
+/* Similar to BigUnsigned::convertToPrimitive, but split into two cases for
+ * nonnegative and negative numbers. */
+template <class X, class UX>
+X BigInteger::convertToSignedPrimitive() const {
+ if (sign == zero)
+ return 0;
+ else if (mag.getLength() == 1) {
+ // The single block might fit in an X. Try the conversion.
+ Blk b = mag.getBlock(0);
+ if (sign == positive) {
+ X x = X(b);
+ if (x >= 0 && Blk(x) == b)
+ return x;
+ } else {
+ X x = -X(b);
+ /* UX(...) needed to avoid rejecting conversion of
+ * -2^15 to a short. */
+ if (x < 0 && Blk(UX(-x)) == b)
+ return x;
+ }
+ // Otherwise fall through.
+ }
+ throw "BigInteger::to<Primitive>: "
+ "Value is too big to fit in the requested type";
+}
+
+unsigned long BigInteger::toUnsignedLong () const { return convertToUnsignedPrimitive<unsigned long > (); }
+unsigned int BigInteger::toUnsignedInt () const { return convertToUnsignedPrimitive<unsigned int > (); }
+unsigned short BigInteger::toUnsignedShort() const { return convertToUnsignedPrimitive<unsigned short> (); }
+long BigInteger::toLong () const { return convertToSignedPrimitive <long , unsigned long> (); }
+int BigInteger::toInt () const { return convertToSignedPrimitive <int , unsigned int> (); }
+short BigInteger::toShort () const { return convertToSignedPrimitive <short, unsigned short>(); }
+
+// COMPARISON
+BigInteger::CmpRes BigInteger::compareTo(const BigInteger &x) const {
+ // A greater sign implies a greater number
+ if (sign < x.sign)
+ return less;
+ else if (sign > x.sign)
+ return greater;
+ else switch (sign) {
+ // If the signs are the same...
+ case zero:
+ return equal; // Two zeros are equal
+ case positive:
+ // Compare the magnitudes
+ return mag.compareTo(x.mag);
+ case negative:
+ // Compare the magnitudes, but return the opposite result
+ return CmpRes(-mag.compareTo(x.mag));
+ default:
+ throw "BigInteger internal error";
+ }
+}
+
+/* COPY-LESS OPERATIONS
+ * These do some messing around to determine the sign of the result,
+ * then call one of BigUnsigned's copy-less operations. */
+
+// See remarks about aliased calls in BigUnsigned.cc .
+#define DTRT_ALIASED(cond, op) \
+ if (cond) { \
+ BigInteger tmpThis; \
+ tmpThis.op; \
+ *this = tmpThis; \
+ return; \
+ }
+
+void BigInteger::add(const BigInteger &a, const BigInteger &b) {
+ DTRT_ALIASED(this == &a || this == &b, add(a, b));
+ // If one argument is zero, copy the other.
+ if (a.sign == zero)
+ operator =(b);
+ else if (b.sign == zero)
+ operator =(a);
+ // If the arguments have the same sign, take the
+ // common sign and add their magnitudes.
+ else if (a.sign == b.sign) {
+ sign = a.sign;
+ mag.add(a.mag, b.mag);
+ } else {
+ // Otherwise, their magnitudes must be compared.
+ switch (a.mag.compareTo(b.mag)) {
+ case equal:
+ // If their magnitudes are the same, copy zero.
+ mag = 0;
+ sign = zero;
+ break;
+ // Otherwise, take the sign of the greater, and subtract
+ // the lesser magnitude from the greater magnitude.
+ case greater:
+ sign = a.sign;
+ mag.subtract(a.mag, b.mag);
+ break;
+ case less:
+ sign = b.sign;
+ mag.subtract(b.mag, a.mag);
+ break;
+ }
+ }
+}
+
+void BigInteger::subtract(const BigInteger &a, const BigInteger &b) {
+ // Notice that this routine is identical to BigInteger::add,
+ // if one replaces b.sign by its opposite.
+ DTRT_ALIASED(this == &a || this == &b, subtract(a, b));
+ // If a is zero, copy b and flip its sign. If b is zero, copy a.
+ if (a.sign == zero) {
+ mag = b.mag;
+ // Take the negative of _b_'s, sign, not ours.
+ // Bug pointed out by Sam Larkin on 2005.03.30.
+ sign = Sign(-b.sign);
+ } else if (b.sign == zero)
+ operator =(a);
+ // If their signs differ, take a.sign and add the magnitudes.
+ else if (a.sign != b.sign) {
+ sign = a.sign;
+ mag.add(a.mag, b.mag);
+ } else {
+ // Otherwise, their magnitudes must be compared.
+ switch (a.mag.compareTo(b.mag)) {
+ // If their magnitudes are the same, copy zero.
+ case equal:
+ mag = 0;
+ sign = zero;
+ break;
+ // If a's magnitude is greater, take a.sign and
+ // subtract a from b.
+ case greater:
+ sign = a.sign;
+ mag.subtract(a.mag, b.mag);
+ break;
+ // If b's magnitude is greater, take the opposite
+ // of b.sign and subtract b from a.
+ case less:
+ sign = Sign(-b.sign);
+ mag.subtract(b.mag, a.mag);
+ break;
+ }
+ }
+}
+
+void BigInteger::multiply(const BigInteger &a, const BigInteger &b) {
+ DTRT_ALIASED(this == &a || this == &b, multiply(a, b));
+ // If one object is zero, copy zero and return.
+ if (a.sign == zero || b.sign == zero) {
+ sign = zero;
+ mag = 0;
+ return;
+ }
+ // If the signs of the arguments are the same, the result
+ // is positive, otherwise it is negative.
+ sign = (a.sign == b.sign) ? positive : negative;
+ // Multiply the magnitudes.
+ mag.multiply(a.mag, b.mag);
+}
+
+/*
+ * DIVISION WITH REMAINDER
+ * Please read the comments before the definition of
+ * `BigUnsigned::divideWithRemainder' in `BigUnsigned.cc' for lots of
+ * information you should know before reading this function.
+ *
+ * Following Knuth, I decree that x / y is to be
+ * 0 if y==0 and floor(real-number x / y) if y!=0.
+ * Then x % y shall be x - y*(integer x / y).
+ *
+ * Note that x = y * (x / y) + (x % y) always holds.
+ * In addition, (x % y) is from 0 to y - 1 if y > 0,
+ * and from -(|y| - 1) to 0 if y < 0. (x % y) = x if y = 0.
+ *
+ * Examples: (q = a / b, r = a % b)
+ * a b q r
+ * === === === ===
+ * 4 3 1 1
+ * -4 3 -2 2
+ * 4 -3 -2 -2
+ * -4 -3 1 -1
+ */
+void BigInteger::divideWithRemainder(const BigInteger &b, BigInteger &q) {
+ // Defend against aliased calls;
+ // same idea as in BigUnsigned::divideWithRemainder .
+ if (this == &q)
+ throw "BigInteger::divideWithRemainder: Cannot write quotient and remainder into the same variable";
+ if (this == &b || &q == &b) {
+ BigInteger tmpB(b);
+ divideWithRemainder(tmpB, q);
+ return;
+ }
+
+ // Division by zero gives quotient 0 and remainder *this
+ if (b.sign == zero) {
+ q.mag = 0;
+ q.sign = zero;
+ return;
+ }
+ // 0 / b gives quotient 0 and remainder 0
+ if (sign == zero) {
+ q.mag = 0;
+ q.sign = zero;
+ return;
+ }
+
+ // Here *this != 0, b != 0.
+
+ // Do the operands have the same sign?
+ if (sign == b.sign) {
+ // Yes: easy case. Quotient is zero or positive.
+ q.sign = positive;
+ } else {
+ // No: harder case. Quotient is negative.
+ q.sign = negative;
+ // Decrease the magnitude of the dividend by one.
+ mag--;
+ /*
+ * We tinker with the dividend before and with the
+ * quotient and remainder after so that the result
+ * comes out right. To see why it works, consider the following
+ * list of examples, where A is the magnitude-decreased
+ * a, Q and R are the results of BigUnsigned division
+ * with remainder on A and |b|, and q and r are the
+ * final results we want:
+ *
+ * a A b Q R q r
+ * -3 -2 3 0 2 -1 0
+ * -4 -3 3 1 0 -2 2
+ * -5 -4 3 1 1 -2 1
+ * -6 -5 3 1 2 -2 0
+ *
+ * It appears that we need a total of 3 corrections:
+ * Decrease the magnitude of a to get A. Increase the
+ * magnitude of Q to get q (and make it negative).
+ * Find r = (b - 1) - R and give it the desired sign.
+ */
+ }
+
+ // Divide the magnitudes.
+ mag.divideWithRemainder(b.mag, q.mag);
+
+ if (sign != b.sign) {
+ // More for the harder case (as described):
+ // Increase the magnitude of the quotient by one.
+ q.mag++;
+ // Modify the remainder.
+ mag.subtract(b.mag, mag);
+ mag--;
+ }
+
+ // Sign of the remainder is always the sign of the divisor b.
+ sign = b.sign;
+
+ // Set signs to zero as necessary. (Thanks David Allen!)
+ if (mag.isZero())
+ sign = zero;
+ if (q.mag.isZero())
+ q.sign = zero;
+
+ // WHEW!!!
+}
+
+// Negation
+void BigInteger::negate(const BigInteger &a) {
+ DTRT_ALIASED(this == &a, negate(a));
+ // Copy a's magnitude
+ mag = a.mag;
+ // Copy the opposite of a.sign
+ sign = Sign(-a.sign);
+}
+
+// INCREMENT/DECREMENT OPERATORS
+
+// Prefix increment
+void BigInteger::operator ++() {
+ if (sign == negative) {
+ mag--;
+ if (mag == 0)
+ sign = zero;
+ } else {
+ mag++;
+ sign = positive; // if not already
+ }
+}
+
+// Postfix increment: same as prefix
+void BigInteger::operator ++(int) {
+ operator ++();
+}
+
+// Prefix decrement
+void BigInteger::operator --() {
+ if (sign == positive) {
+ mag--;
+ if (mag == 0)
+ sign = zero;
+ } else {
+ mag++;
+ sign = negative;
+ }
+}
+
+// Postfix decrement: same as prefix
+void BigInteger::operator --(int) {
+ operator --();
+}
+
diff --git a/bigint/BigInteger.hh b/bigint/BigInteger.hh
new file mode 100644
index 00000000..cf6e9105
--- /dev/null
+++ b/bigint/BigInteger.hh
@@ -0,0 +1,215 @@
+#ifndef BIGINTEGER_H
+#define BIGINTEGER_H
+
+#include "BigUnsigned.hh"
+
+/* A BigInteger object represents a signed integer of size limited only by
+ * available memory. BigUnsigneds support most mathematical operators and can
+ * be converted to and from most primitive integer types.
+ *
+ * A BigInteger is just an aggregate of a BigUnsigned and a sign. (It is no
+ * longer derived from BigUnsigned because that led to harmful implicit
+ * conversions.) */
+class BigInteger {
+
+public:
+ typedef BigUnsigned::Blk Blk;
+ typedef BigUnsigned::Index Index;
+ typedef BigUnsigned::CmpRes CmpRes;
+ static const CmpRes
+ less = BigUnsigned::less ,
+ equal = BigUnsigned::equal ,
+ greater = BigUnsigned::greater;
+ // Enumeration for the sign of a BigInteger.
+ enum Sign { negative = -1, zero = 0, positive = 1 };
+
+protected:
+ Sign sign;
+ BigUnsigned mag;
+
+public:
+ // Constructs zero.
+ BigInteger() : sign(zero), mag() {}
+
+ // Copy constructor
+ BigInteger(const BigInteger &x) : sign(x.sign), mag(x.mag) {};
+
+ // Assignment operator
+ void operator=(const BigInteger &x);
+
+ // Constructor that copies from a given array of blocks with a sign.
+ BigInteger(const Blk *b, Index blen, Sign s);
+
+ // Nonnegative constructor that copies from a given array of blocks.
+ BigInteger(const Blk *b, Index blen) : mag(b, blen) {
+ sign = mag.isZero() ? zero : positive;
+ }
+
+ // Constructor from a BigUnsigned and a sign
+ BigInteger(const BigUnsigned &x, Sign s);
+
+ // Nonnegative constructor from a BigUnsigned
+ BigInteger(const BigUnsigned &x) : mag(x) {
+ sign = mag.isZero() ? zero : positive;
+ }
+
+ // Constructors from primitive integer types
+ BigInteger(unsigned long x);
+ BigInteger( long x);
+ BigInteger(unsigned int x);
+ BigInteger( int x);
+ BigInteger(unsigned short x);
+ BigInteger( short x);
+
+ /* Converters to primitive integer types
+ * The implicit conversion operators caused trouble, so these are now
+ * named. */
+ unsigned long toUnsignedLong () const;
+ long toLong () const;
+ unsigned int toUnsignedInt () const;
+ int toInt () const;
+ unsigned short toUnsignedShort() const;
+ short toShort () const;
+protected:
+ // Helper
+ template <class X> X convertToUnsignedPrimitive() const;
+ template <class X, class UX> X convertToSignedPrimitive() const;
+public:
+
+ // ACCESSORS
+ Sign getSign() const { return sign; }
+ /* The client can't do any harm by holding a read-only reference to the
+ * magnitude. */
+ const BigUnsigned &getMagnitude() const { return mag; }
+
+ // Some accessors that go through to the magnitude
+ Index getLength() const { return mag.getLength(); }
+ Index getCapacity() const { return mag.getCapacity(); }
+ Blk getBlock(Index i) const { return mag.getBlock(i); }
+ bool isZero() const { return sign == zero; } // A bit special
+
+ // COMPARISONS
+
+ // Compares this to x like Perl's <=>
+ CmpRes compareTo(const BigInteger &x) const;
+
+ // Ordinary comparison operators
+ bool operator ==(const BigInteger &x) const {
+ return sign == x.sign && mag == x.mag;
+ }
+ bool operator !=(const BigInteger &x) const { return !operator ==(x); };
+ bool operator < (const BigInteger &x) const { return compareTo(x) == less ; }
+ bool operator <=(const BigInteger &x) const { return compareTo(x) != greater; }
+ bool operator >=(const BigInteger &x) const { return compareTo(x) != less ; }
+ bool operator > (const BigInteger &x) const { return compareTo(x) == greater; }
+
+ // OPERATORS -- See the discussion in BigUnsigned.hh.
+ void add (const BigInteger &a, const BigInteger &b);
+ void subtract(const BigInteger &a, const BigInteger &b);
+ void multiply(const BigInteger &a, const BigInteger &b);
+ /* See the comment on BigUnsigned::divideWithRemainder. Semantics
+ * differ from those of primitive integers when negatives and/or zeros
+ * are involved. */
+ void divideWithRemainder(const BigInteger &b, BigInteger &q);
+ void negate(const BigInteger &a);
+
+ /* Bitwise operators are not provided for BigIntegers. Use
+ * getMagnitude to get the magnitude and operate on that instead. */
+
+ BigInteger operator +(const BigInteger &x) const;
+ BigInteger operator -(const BigInteger &x) const;
+ BigInteger operator *(const BigInteger &x) const;
+ BigInteger operator /(const BigInteger &x) const;
+ BigInteger operator %(const BigInteger &x) const;
+ BigInteger operator -() const;
+
+ void operator +=(const BigInteger &x);
+ void operator -=(const BigInteger &x);
+ void operator *=(const BigInteger &x);
+ void operator /=(const BigInteger &x);
+ void operator %=(const BigInteger &x);
+ void flipSign();
+
+ // INCREMENT/DECREMENT OPERATORS
+ void operator ++( );
+ void operator ++(int);
+ void operator --( );
+ void operator --(int);
+};
+
+// NORMAL OPERATORS
+/* These create an object to hold the result and invoke
+ * the appropriate put-here operation on it, passing
+ * this and x. The new object is then returned. */
+inline BigInteger BigInteger::operator +(const BigInteger &x) const {
+ BigInteger ans;
+ ans.add(*this, x);
+ return ans;
+}
+inline BigInteger BigInteger::operator -(const BigInteger &x) const {
+ BigInteger ans;
+ ans.subtract(*this, x);
+ return ans;
+}
+inline BigInteger BigInteger::operator *(const BigInteger &x) const {
+ BigInteger ans;
+ ans.multiply(*this, x);
+ return ans;
+}
+inline BigInteger BigInteger::operator /(const BigInteger &x) const {
+ if (x.isZero()) throw "BigInteger::operator /: division by zero";
+ BigInteger q, r;
+ r = *this;
+ r.divideWithRemainder(x, q);
+ return q;
+}
+inline BigInteger BigInteger::operator %(const BigInteger &x) const {
+ if (x.isZero()) throw "BigInteger::operator %: division by zero";
+ BigInteger q, r;
+ r = *this;
+ r.divideWithRemainder(x, q);
+ return r;
+}
+inline BigInteger BigInteger::operator -() const {
+ BigInteger ans;
+ ans.negate(*this);
+ return ans;
+}
+
+/*
+ * ASSIGNMENT OPERATORS
+ *
+ * Now the responsibility for making a temporary copy if necessary
+ * belongs to the put-here operations. See Assignment Operators in
+ * BigUnsigned.hh.
+ */
+inline void BigInteger::operator +=(const BigInteger &x) {
+ add(*this, x);
+}
+inline void BigInteger::operator -=(const BigInteger &x) {
+ subtract(*this, x);
+}
+inline void BigInteger::operator *=(const BigInteger &x) {
+ multiply(*this, x);
+}
+inline void BigInteger::operator /=(const BigInteger &x) {
+ if (x.isZero()) throw "BigInteger::operator /=: division by zero";
+ /* The following technique is slightly faster than copying *this first
+ * when x is large. */
+ BigInteger q;
+ divideWithRemainder(x, q);
+ // *this contains the remainder, but we overwrite it with the quotient.
+ *this = q;
+}
+inline void BigInteger::operator %=(const BigInteger &x) {
+ if (x.isZero()) throw "BigInteger::operator %=: division by zero";
+ BigInteger q;
+ // Mods *this by x. Don't care about quotient left in q.
+ divideWithRemainder(x, q);
+}
+// This one is trivial
+inline void BigInteger::flipSign() {
+ sign = Sign(-sign);
+}
+
+#endif
diff --git a/bigint/BigIntegerAlgorithms.cc b/bigint/BigIntegerAlgorithms.cc
new file mode 100644
index 00000000..7edebda7
--- /dev/null
+++ b/bigint/BigIntegerAlgorithms.cc
@@ -0,0 +1,70 @@
+#include "BigIntegerAlgorithms.hh"
+
+BigUnsigned gcd(BigUnsigned a, BigUnsigned b) {
+ BigUnsigned trash;
+ // Neat in-place alternating technique.
+ for (;;) {
+ if (b.isZero())
+ return a;
+ a.divideWithRemainder(b, trash);
+ if (a.isZero())
+ return b;
+ b.divideWithRemainder(a, trash);
+ }
+}
+
+void extendedEuclidean(BigInteger m, BigInteger n,
+ BigInteger &g, BigInteger &r, BigInteger &s) {
+ if (&g == &r || &g == &s || &r == &s)
+ throw "BigInteger extendedEuclidean: Outputs are aliased";
+ BigInteger r1(1), s1(0), r2(0), s2(1), q;
+ /* Invariants:
+ * r1*m(orig) + s1*n(orig) == m(current)
+ * r2*m(orig) + s2*n(orig) == n(current) */
+ for (;;) {
+ if (n.isZero()) {
+ r = r1; s = s1; g = m;
+ return;
+ }
+ // Subtract q times the second invariant from the first invariant.
+ m.divideWithRemainder(n, q);
+ r1 -= q*r2; s1 -= q*s2;
+
+ if (m.isZero()) {
+ r = r2; s = s2; g = n;
+ return;
+ }
+ // Subtract q times the first invariant from the second invariant.
+ n.divideWithRemainder(m, q);
+ r2 -= q*r1; s2 -= q*s1;
+ }
+}
+
+BigUnsigned modinv(const BigInteger &x, const BigUnsigned &n) {
+ BigInteger g, r, s;
+ extendedEuclidean(x, n, g, r, s);
+ if (g == 1)
+ // r*x + s*n == 1, so r*x === 1 (mod n), so r is the answer.
+ return (r % n).getMagnitude(); // (r % n) will be nonnegative
+ else
+ throw "BigInteger modinv: x and n have a common factor";
+}
+
+BigUnsigned modexp(const BigInteger &base, const BigUnsigned &exponent,
+ const BigUnsigned &modulus) {
+ BigUnsigned ans = 1, base2 = (base % modulus).getMagnitude();
+ BigUnsigned::Index i = exponent.bitLength();
+ // For each bit of the exponent, most to least significant...
+ while (i > 0) {
+ i--;
+ // Square.
+ ans *= ans;
+ ans %= modulus;
+ // And multiply if the bit is a 1.
+ if (exponent.getBit(i)) {
+ ans *= base2;
+ ans %= modulus;
+ }
+ }
+ return ans;
+}
diff --git a/bigint/BigIntegerAlgorithms.hh b/bigint/BigIntegerAlgorithms.hh
new file mode 100644
index 00000000..b1dd9432
--- /dev/null
+++ b/bigint/BigIntegerAlgorithms.hh
@@ -0,0 +1,25 @@
+#ifndef BIGINTEGERALGORITHMS_H
+#define BIGINTEGERALGORITHMS_H
+
+#include "BigInteger.hh"
+
+/* Some mathematical algorithms for big integers.
+ * This code is new and, as such, experimental. */
+
+// Returns the greatest common divisor of a and b.
+BigUnsigned gcd(BigUnsigned a, BigUnsigned b);
+
+/* Extended Euclidean algorithm.
+ * Given m and n, finds gcd g and numbers r, s such that r*m + s*n == g. */
+void extendedEuclidean(BigInteger m, BigInteger n,
+ BigInteger &g, BigInteger &r, BigInteger &s);
+
+/* Returns the multiplicative inverse of x modulo n, or throws an exception if
+ * they have a common factor. */
+BigUnsigned modinv(const BigInteger &x, const BigUnsigned &n);
+
+// Returns (base ^ exponent) % modulus.
+BigUnsigned modexp(const BigInteger &base, const BigUnsigned &exponent,
+ const BigUnsigned &modulus);
+
+#endif
diff --git a/bigint/BigIntegerLibrary.hh b/bigint/BigIntegerLibrary.hh
new file mode 100644
index 00000000..2a0ebee6
--- /dev/null
+++ b/bigint/BigIntegerLibrary.hh
@@ -0,0 +1,8 @@
+// This header file includes all of the library header files.
+
+#include "NumberlikeArray.hh"
+#include "BigUnsigned.hh"
+#include "BigInteger.hh"
+#include "BigIntegerAlgorithms.hh"
+#include "BigUnsignedInABase.hh"
+#include "BigIntegerUtils.hh"
diff --git a/bigint/BigIntegerUtils.cc b/bigint/BigIntegerUtils.cc
new file mode 100644
index 00000000..44073af6
--- /dev/null
+++ b/bigint/BigIntegerUtils.cc
@@ -0,0 +1,50 @@
+#include "BigIntegerUtils.hh"
+#include "BigUnsignedInABase.hh"
+
+std::string bigUnsignedToString(const BigUnsigned &x) {
+ return std::string(BigUnsignedInABase(x, 10));
+}
+
+std::string bigIntegerToString(const BigInteger &x) {
+ return (x.getSign() == BigInteger::negative)
+ ? (std::string("-") + bigUnsignedToString(x.getMagnitude()))
+ : (bigUnsignedToString(x.getMagnitude()));
+}
+
+BigUnsigned stringToBigUnsigned(const std::string &s) {
+ return BigUnsigned(BigUnsignedInABase(s, 10));
+}
+
+BigInteger stringToBigInteger(const std::string &s) {
+ // Recognize a sign followed by a BigUnsigned.
+ return (s[0] == '-') ? BigInteger(stringToBigUnsigned(s.substr(1, s.length() - 1)), BigInteger::negative)
+ : (s[0] == '+') ? BigInteger(stringToBigUnsigned(s.substr(1, s.length() - 1)))
+ : BigInteger(stringToBigUnsigned(s));
+}
+
+std::ostream &operator <<(std::ostream &os, const BigUnsigned &x) {
+ BigUnsignedInABase::Base base;
+ long osFlags = os.flags();
+ if (osFlags & os.dec)
+ base = 10;
+ else if (osFlags & os.hex) {
+ base = 16;
+ if (osFlags & os.showbase)
+ os << "0x";
+ } else if (osFlags & os.oct) {
+ base = 8;
+ if (osFlags & os.showbase)
+ os << '0';
+ } else
+ throw "std::ostream << BigUnsigned: Could not determine the desired base from output-stream flags";
+ std::string s = std::string(BigUnsignedInABase(x, base));
+ os << s;
+ return os;
+}
+
+std::ostream &operator <<(std::ostream &os, const BigInteger &x) {
+ if (x.getSign() == BigInteger::negative)
+ os << '-';
+ os << x.getMagnitude();
+ return os;
+}
diff --git a/bigint/BigIntegerUtils.hh b/bigint/BigIntegerUtils.hh
new file mode 100644
index 00000000..c815b5d7
--- /dev/null
+++ b/bigint/BigIntegerUtils.hh
@@ -0,0 +1,72 @@
+#ifndef BIGINTEGERUTILS_H
+#define BIGINTEGERUTILS_H
+
+#include "BigInteger.hh"
+#include <string>
+#include <iostream>
+
+/* This file provides:
+ * - Convenient std::string <-> BigUnsigned/BigInteger conversion routines
+ * - std::ostream << operators for BigUnsigned/BigInteger */
+
+// std::string conversion routines. Base 10 only.
+std::string bigUnsignedToString(const BigUnsigned &x);
+std::string bigIntegerToString(const BigInteger &x);
+BigUnsigned stringToBigUnsigned(const std::string &s);
+BigInteger stringToBigInteger(const std::string &s);
+
+// Creates a BigInteger from data such as `char's; read below for details.
+template <class T>
+BigInteger dataToBigInteger(const T* data, BigInteger::Index length, BigInteger::Sign sign);
+
+// Outputs x to os, obeying the flags `dec', `hex', `bin', and `showbase'.
+std::ostream &operator <<(std::ostream &os, const BigUnsigned &x);
+
+// Outputs x to os, obeying the flags `dec', `hex', `bin', and `showbase'.
+// My somewhat arbitrary policy: a negative sign comes before a base indicator (like -0xFF).
+std::ostream &operator <<(std::ostream &os, const BigInteger &x);
+
+// BEGIN TEMPLATE DEFINITIONS.
+
+/*
+ * Converts binary data to a BigInteger.
+ * Pass an array `data', its length, and the desired sign.
+ *
+ * Elements of `data' may be of any type `T' that has the following
+ * two properties (this includes almost all integral types):
+ *
+ * (1) `sizeof(T)' correctly gives the amount of binary data in one
+ * value of `T' and is a factor of `sizeof(Blk)'.
+ *
+ * (2) When a value of `T' is casted to a `Blk', the low bytes of
+ * the result contain the desired binary data.
+ */
+template <class T>
+BigInteger dataToBigInteger(const T* data, BigInteger::Index length, BigInteger::Sign sign) {
+ // really ceiling(numBytes / sizeof(BigInteger::Blk))
+ unsigned int pieceSizeInBits = 8 * sizeof(T);
+ unsigned int piecesPerBlock = sizeof(BigInteger::Blk) / sizeof(T);
+ unsigned int numBlocks = (length + piecesPerBlock - 1) / piecesPerBlock;
+
+ // Allocate our block array
+ BigInteger::Blk *blocks = new BigInteger::Blk[numBlocks];
+
+ BigInteger::Index blockNum, pieceNum, pieceNumHere;
+
+ // Convert
+ for (blockNum = 0, pieceNum = 0; blockNum < numBlocks; blockNum++) {
+ BigInteger::Blk curBlock = 0;
+ for (pieceNumHere = 0; pieceNumHere < piecesPerBlock && pieceNum < length;
+ pieceNumHere++, pieceNum++)
+ curBlock |= (BigInteger::Blk(data[pieceNum]) << (pieceSizeInBits * pieceNumHere));
+ blocks[blockNum] = curBlock;
+ }
+
+ // Create the BigInteger.
+ BigInteger x(blocks, numBlocks, sign);
+
+ delete [] blocks;
+ return x;
+}
+
+#endif
diff --git a/bigint/BigUnsigned.cc b/bigint/BigUnsigned.cc
new file mode 100644
index 00000000..d7f9889c
--- /dev/null
+++ b/bigint/BigUnsigned.cc
@@ -0,0 +1,697 @@
+#include "BigUnsigned.hh"
+
+// Memory management definitions have moved to the bottom of NumberlikeArray.hh.
+
+// The templates used by these constructors and converters are at the bottom of
+// BigUnsigned.hh.
+
+BigUnsigned::BigUnsigned(unsigned long x) { initFromPrimitive (x); }
+BigUnsigned::BigUnsigned(unsigned int x) { initFromPrimitive (x); }
+BigUnsigned::BigUnsigned(unsigned short x) { initFromPrimitive (x); }
+BigUnsigned::BigUnsigned( long x) { initFromSignedPrimitive(x); }
+BigUnsigned::BigUnsigned( int x) { initFromSignedPrimitive(x); }
+BigUnsigned::BigUnsigned( short x) { initFromSignedPrimitive(x); }
+
+unsigned long BigUnsigned::toUnsignedLong () const { return convertToPrimitive <unsigned long >(); }
+unsigned int BigUnsigned::toUnsignedInt () const { return convertToPrimitive <unsigned int >(); }
+unsigned short BigUnsigned::toUnsignedShort() const { return convertToPrimitive <unsigned short>(); }
+long BigUnsigned::toLong () const { return convertToSignedPrimitive< long >(); }
+int BigUnsigned::toInt () const { return convertToSignedPrimitive< int >(); }
+short BigUnsigned::toShort () const { return convertToSignedPrimitive< short>(); }
+
+// BIT/BLOCK ACCESSORS
+
+void BigUnsigned::setBlock(Index i, Blk newBlock) {
+ if (newBlock == 0) {
+ if (i < len) {
+ blk[i] = 0;
+ zapLeadingZeros();
+ }
+ // If i >= len, no effect.
+ } else {
+ if (i >= len) {
+ // The nonzero block extends the number.
+ allocateAndCopy(i+1);
+ // Zero any added blocks that we aren't setting.
+ for (Index j = len; j < i; j++)
+ blk[j] = 0;
+ len = i+1;
+ }
+ blk[i] = newBlock;
+ }
+}
+
+/* Evidently the compiler wants BigUnsigned:: on the return type because, at
+ * that point, it hasn't yet parsed the BigUnsigned:: on the name to get the
+ * proper scope. */
+BigUnsigned::Index BigUnsigned::bitLength() const {
+ if (isZero())
+ return 0;
+ else {
+ Blk leftmostBlock = getBlock(len - 1);
+ Index leftmostBlockLen = 0;
+ while (leftmostBlock != 0) {
+ leftmostBlock >>= 1;
+ leftmostBlockLen++;
+ }
+ return leftmostBlockLen + (len - 1) * N;
+ }
+}
+
+void BigUnsigned::setBit(Index bi, bool newBit) {
+ Index blockI = bi / N;
+ Blk block = getBlock(blockI), mask = Blk(1) << (bi % N);
+ block = newBit ? (block | mask) : (block & ~mask);
+ setBlock(blockI, block);
+}
+
+// COMPARISON
+BigUnsigned::CmpRes BigUnsigned::compareTo(const BigUnsigned &x) const {
+ // A bigger length implies a bigger number.
+ if (len < x.len)
+ return less;
+ else if (len > x.len)
+ return greater;
+ else {
+ // Compare blocks one by one from left to right.
+ Index i = len;
+ while (i > 0) {
+ i--;
+ if (blk[i] == x.blk[i])
+ continue;
+ else if (blk[i] > x.blk[i])
+ return greater;
+ else
+ return less;
+ }
+ // If no blocks differed, the numbers are equal.
+ return equal;
+ }
+}
+
+// COPY-LESS OPERATIONS
+
+/*
+ * On most calls to copy-less operations, it's safe to read the inputs little by
+ * little and write the outputs little by little. However, if one of the
+ * inputs is coming from the same variable into which the output is to be
+ * stored (an "aliased" call), we risk overwriting the input before we read it.
+ * In this case, we first compute the result into a temporary BigUnsigned
+ * variable and then copy it into the requested output variable *this.
+ * Each put-here operation uses the DTRT_ALIASED macro (Do The Right Thing on
+ * aliased calls) to generate code for this check.
+ *
+ * I adopted this approach on 2007.02.13 (see Assignment Operators in
+ * BigUnsigned.hh). Before then, put-here operations rejected aliased calls
+ * with an exception. I think doing the right thing is better.
+ *
+ * Some of the put-here operations can probably handle aliased calls safely
+ * without the extra copy because (for example) they process blocks strictly
+ * right-to-left. At some point I might determine which ones don't need the
+ * copy, but my reasoning would need to be verified very carefully. For now
+ * I'll leave in the copy.
+ */
+#define DTRT_ALIASED(cond, op) \
+ if (cond) { \
+ BigUnsigned tmpThis; \
+ tmpThis.op; \
+ *this = tmpThis; \
+ return; \
+ }
+
+
+
+void BigUnsigned::add(const BigUnsigned &a, const BigUnsigned &b) {
+ DTRT_ALIASED(this == &a || this == &b, add(a, b));
+ // If one argument is zero, copy the other.
+ if (a.len == 0) {
+ operator =(b);
+ return;
+ } else if (b.len == 0) {
+ operator =(a);
+ return;
+ }
+ // Some variables...
+ // Carries in and out of an addition stage
+ bool carryIn, carryOut;
+ Blk temp;
+ Index i;
+ // a2 points to the longer input, b2 points to the shorter
+ const BigUnsigned *a2, *b2;
+ if (a.len >= b.len) {
+ a2 = &a;
+ b2 = &b;
+ } else {
+ a2 = &b;
+ b2 = &a;
+ }
+ // Set prelimiary length and make room in this BigUnsigned
+ len = a2->len + 1;
+ allocate(len);
+ // For each block index that is present in both inputs...
+ for (i = 0, carryIn = false; i < b2->len; i++) {
+ // Add input blocks
+ temp = a2->blk[i] + b2->blk[i];
+ // If a rollover occurred, the result is less than either input.
+ // This test is used many times in the BigUnsigned code.
+ carryOut = (temp < a2->blk[i]);
+ // If a carry was input, handle it
+ if (carryIn) {
+ temp++;
+ carryOut |= (temp == 0);
+ }
+ blk[i] = temp; // Save the addition result
+ carryIn = carryOut; // Pass the carry along
+ }
+ // If there is a carry left over, increase blocks until
+ // one does not roll over.
+ for (; i < a2->len && carryIn; i++) {
+ temp = a2->blk[i] + 1;
+ carryIn = (temp == 0);
+ blk[i] = temp;
+ }
+ // If the carry was resolved but the larger number
+ // still has blocks, copy them over.
+ for (; i < a2->len; i++)
+ blk[i] = a2->blk[i];
+ // Set the extra block if there's still a carry, decrease length otherwise
+ if (carryIn)
+ blk[i] = 1;
+ else
+ len--;
+}
+
+void BigUnsigned::subtract(const BigUnsigned &a, const BigUnsigned &b) {
+ DTRT_ALIASED(this == &a || this == &b, subtract(a, b));
+ if (b.len == 0) {
+ // If b is zero, copy a.
+ operator =(a);
+ return;
+ } else if (a.len < b.len)
+ // If a is shorter than b, the result is negative.
+ throw "BigUnsigned::subtract: "
+ "Negative result in unsigned calculation";
+ // Some variables...
+ bool borrowIn, borrowOut;
+ Blk temp;
+ Index i;
+ // Set preliminary length and make room
+ len = a.len;
+ allocate(len);
+ // For each block index that is present in both inputs...
+ for (i = 0, borrowIn = false; i < b.len; i++) {
+ temp = a.blk[i] - b.blk[i];
+ // If a reverse rollover occurred,
+ // the result is greater than the block from a.
+ borrowOut = (temp > a.blk[i]);
+ // Handle an incoming borrow
+ if (borrowIn) {
+ borrowOut |= (temp == 0);
+ temp--;
+ }
+ blk[i] = temp; // Save the subtraction result
+ borrowIn = borrowOut; // Pass the borrow along
+ }
+ // If there is a borrow left over, decrease blocks until
+ // one does not reverse rollover.
+ for (; i < a.len && borrowIn; i++) {
+ borrowIn = (a.blk[i] == 0);
+ blk[i] = a.blk[i] - 1;
+ }
+ /* If there's still a borrow, the result is negative.
+ * Throw an exception, but zero out this object so as to leave it in a
+ * predictable state. */
+ if (borrowIn) {
+ len = 0;
+ throw "BigUnsigned::subtract: Negative result in unsigned calculation";
+ } else
+ // Copy over the rest of the blocks
+ for (; i < a.len; i++)
+ blk[i] = a.blk[i];
+ // Zap leading zeros
+ zapLeadingZeros();
+}
+
+/*
+ * About the multiplication and division algorithms:
+ *
+ * I searched unsucessfully for fast C++ built-in operations like the `b_0'
+ * and `c_0' Knuth describes in Section 4.3.1 of ``The Art of Computer
+ * Programming'' (replace `place' by `Blk'):
+ *
+ * ``b_0[:] multiplication of a one-place integer by another one-place
+ * integer, giving a two-place answer;
+ *
+ * ``c_0[:] division of a two-place integer by a one-place integer,
+ * provided that the quotient is a one-place integer, and yielding
+ * also a one-place remainder.''
+ *
+ * I also missed his note that ``[b]y adjusting the word size, if
+ * necessary, nearly all computers will have these three operations
+ * available'', so I gave up on trying to use algorithms similar to his.
+ * A future version of the library might include such algorithms; I
+ * would welcome contributions from others for this.
+ *
+ * I eventually decided to use bit-shifting algorithms. To multiply `a'
+ * and `b', we zero out the result. Then, for each `1' bit in `a', we
+ * shift `b' left the appropriate amount and add it to the result.
+ * Similarly, to divide `a' by `b', we shift `b' left varying amounts,
+ * repeatedly trying to subtract it from `a'. When we succeed, we note
+ * the fact by setting a bit in the quotient. While these algorithms
+ * have the same O(n^2) time complexity as Knuth's, the ``constant factor''
+ * is likely to be larger.
+ *
+ * Because I used these algorithms, which require single-block addition
+ * and subtraction rather than single-block multiplication and division,
+ * the innermost loops of all four routines are very similar. Study one
+ * of them and all will become clear.
+ */
+
+/*
+ * This is a little inline function used by both the multiplication
+ * routine and the division routine.
+ *
+ * `getShiftedBlock' returns the `x'th block of `num << y'.
+ * `y' may be anything from 0 to N - 1, and `x' may be anything from
+ * 0 to `num.len'.
+ *
+ * Two things contribute to this block:
+ *
+ * (1) The `N - y' low bits of `num.blk[x]', shifted `y' bits left.
+ *
+ * (2) The `y' high bits of `num.blk[x-1]', shifted `N - y' bits right.
+ *
+ * But we must be careful if `x == 0' or `x == num.len', in
+ * which case we should use 0 instead of (2) or (1), respectively.
+ *
+ * If `y == 0', then (2) contributes 0, as it should. However,
+ * in some computer environments, for a reason I cannot understand,
+ * `a >> b' means `a >> (b % N)'. This means `num.blk[x-1] >> (N - y)'
+ * will return `num.blk[x-1]' instead of the desired 0 when `y == 0';
+ * the test `y == 0' handles this case specially.
+ */
+inline BigUnsigned::Blk getShiftedBlock(const BigUnsigned &num,
+ BigUnsigned::Index x, unsigned int y) {
+ BigUnsigned::Blk part1 = (x == 0 || y == 0) ? 0 : (num.blk[x - 1] >> (BigUnsigned::N - y));
+ BigUnsigned::Blk part2 = (x == num.len) ? 0 : (num.blk[x] << y);
+ return part1 | part2;
+}
+
+void BigUnsigned::multiply(const BigUnsigned &a, const BigUnsigned &b) {
+ DTRT_ALIASED(this == &a || this == &b, multiply(a, b));
+ // If either a or b is zero, set to zero.
+ if (a.len == 0 || b.len == 0) {
+ len = 0;
+ return;
+ }
+ /*
+ * Overall method:
+ *
+ * Set this = 0.
+ * For each 1-bit of `a' (say the `i2'th bit of block `i'):
+ * Add `b << (i blocks and i2 bits)' to *this.
+ */
+ // Variables for the calculation
+ Index i, j, k;
+ unsigned int i2;
+ Blk temp;
+ bool carryIn, carryOut;
+ // Set preliminary length and make room
+ len = a.len + b.len;
+ allocate(len);
+ // Zero out this object
+ for (i = 0; i < len; i++)
+ blk[i] = 0;
+ // For each block of the first number...
+ for (i = 0; i < a.len; i++) {
+ // For each 1-bit of that block...
+ for (i2 = 0; i2 < N; i2++) {
+ if ((a.blk[i] & (Blk(1) << i2)) == 0)
+ continue;
+ /*
+ * Add b to this, shifted left i blocks and i2 bits.
+ * j is the index in b, and k = i + j is the index in this.
+ *
+ * `getShiftedBlock', a short inline function defined above,
+ * is now used for the bit handling. It replaces the more
+ * complex `bHigh' code, in which each run of the loop dealt
+ * immediately with the low bits and saved the high bits to
+ * be picked up next time. The last run of the loop used to
+ * leave leftover high bits, which were handled separately.
+ * Instead, this loop runs an additional time with j == b.len.
+ * These changes were made on 2005.01.11.
+ */
+ for (j = 0, k = i, carryIn = false; j <= b.len; j++, k++) {
+ /*
+ * The body of this loop is very similar to the body of the first loop
+ * in `add', except that this loop does a `+=' instead of a `+'.
+ */
+ temp = blk[k] + getShiftedBlock(b, j, i2);
+ carryOut = (temp < blk[k]);
+ if (carryIn) {
+ temp++;
+ carryOut |= (temp == 0);
+ }
+ blk[k] = temp;
+ carryIn = carryOut;
+ }
+ // No more extra iteration to deal with `bHigh'.
+ // Roll-over a carry as necessary.
+ for (; carryIn; k++) {
+ blk[k]++;
+ carryIn = (blk[k] == 0);
+ }
+ }
+ }
+ // Zap possible leading zero
+ if (blk[len - 1] == 0)
+ len--;
+}
+
+/*
+ * DIVISION WITH REMAINDER
+ * This monstrous function mods *this by the given divisor b while storing the
+ * quotient in the given object q; at the end, *this contains the remainder.
+ * The seemingly bizarre pattern of inputs and outputs was chosen so that the
+ * function copies as little as possible (since it is implemented by repeated
+ * subtraction of multiples of b from *this).
+ *
+ * "modWithQuotient" might be a better name for this function, but I would
+ * rather not change the name now.
+ */
+void BigUnsigned::divideWithRemainder(const BigUnsigned &b, BigUnsigned &q) {
+ /* Defending against aliased calls is more complex than usual because we
+ * are writing to both *this and q.
+ *
+ * It would be silly to try to write quotient and remainder to the
+ * same variable. Rule that out right away. */
+ if (this == &q)
+ throw "BigUnsigned::divideWithRemainder: Cannot write quotient and remainder into the same variable";
+ /* Now *this and q are separate, so the only concern is that b might be
+ * aliased to one of them. If so, use a temporary copy of b. */
+ if (this == &b || &q == &b) {
+ BigUnsigned tmpB(b);
+ divideWithRemainder(tmpB, q);
+ return;
+ }
+
+ /*
+ * Knuth's definition of mod (which this function uses) is somewhat
+ * different from the C++ definition of % in case of division by 0.
+ *
+ * We let a / 0 == 0 (it doesn't matter much) and a % 0 == a, no
+ * exceptions thrown. This allows us to preserve both Knuth's demand
+ * that a mod 0 == a and the useful property that
+ * (a / b) * b + (a % b) == a.
+ */
+ if (b.len == 0) {
+ q.len = 0;
+ return;
+ }
+
+ /*
+ * If *this.len < b.len, then *this < b, and we can be sure that b doesn't go into
+ * *this at all. The quotient is 0 and *this is already the remainder (so leave it alone).
+ */
+ if (len < b.len) {
+ q.len = 0;
+ return;
+ }
+
+ // At this point we know (*this).len >= b.len > 0. (Whew!)
+
+ /*
+ * Overall method:
+ *
+ * For each appropriate i and i2, decreasing:
+ * Subtract (b << (i blocks and i2 bits)) from *this, storing the
+ * result in subtractBuf.
+ * If the subtraction succeeds with a nonnegative result:
+ * Turn on bit i2 of block i of the quotient q.
+ * Copy subtractBuf back into *this.
+ * Otherwise bit i2 of block i remains off, and *this is unchanged.
+ *
+ * Eventually q will contain the entire quotient, and *this will
+ * be left with the remainder.
+ *
+ * subtractBuf[x] corresponds to blk[x], not blk[x+i], since 2005.01.11.
+ * But on a single iteration, we don't touch the i lowest blocks of blk
+ * (and don't use those of subtractBuf) because these blocks are
+ * unaffected by the subtraction: we are subtracting
+ * (b << (i blocks and i2 bits)), which ends in at least `i' zero
+ * blocks. */
+ // Variables for the calculation
+ Index i, j, k;
+ unsigned int i2;
+ Blk temp;
+ bool borrowIn, borrowOut;
+
+ /*
+ * Make sure we have an extra zero block just past the value.
+ *
+ * When we attempt a subtraction, we might shift `b' so
+ * its first block begins a few bits left of the dividend,
+ * and then we'll try to compare these extra bits with
+ * a nonexistent block to the left of the dividend. The
+ * extra zero block ensures sensible behavior; we need
+ * an extra block in `subtractBuf' for exactly the same reason.
+ */
+ Index origLen = len; // Save real length.
+ /* To avoid an out-of-bounds access in case of reallocation, allocate
+ * first and then increment the logical length. */
+ allocateAndCopy(len + 1);
+ len++;
+ blk[origLen] = 0; // Zero the added block.
+
+ // subtractBuf holds part of the result of a subtraction; see above.
+ Blk *subtractBuf = new Blk[len];
+
+ // Set preliminary length for quotient and make room
+ q.len = origLen - b.len + 1;
+ q.allocate(q.len);
+ // Zero out the quotient
+ for (i = 0; i < q.len; i++)
+ q.blk[i] = 0;
+
+ // For each possible left-shift of b in blocks...
+ i = q.len;
+ while (i > 0) {
+ i--;
+ // For each possible left-shift of b in bits...
+ // (Remember, N is the number of bits in a Blk.)
+ q.blk[i] = 0;
+ i2 = N;
+ while (i2 > 0) {
+ i2--;
+ /*
+ * Subtract b, shifted left i blocks and i2 bits, from *this,
+ * and store the answer in subtractBuf. In the for loop, `k == i + j'.
+ *
+ * Compare this to the middle section of `multiply'. They
+ * are in many ways analogous. See especially the discussion
+ * of `getShiftedBlock'.
+ */
+ for (j = 0, k = i, borrowIn = false; j <= b.len; j++, k++) {
+ temp = blk[k] - getShiftedBlock(b, j, i2);
+ borrowOut = (temp > blk[k]);
+ if (borrowIn) {
+ borrowOut |= (temp == 0);
+ temp--;
+ }
+ // Since 2005.01.11, indices of `subtractBuf' directly match those of `blk', so use `k'.
+ subtractBuf[k] = temp;
+ borrowIn = borrowOut;
+ }
+ // No more extra iteration to deal with `bHigh'.
+ // Roll-over a borrow as necessary.
+ for (; k < origLen && borrowIn; k++) {
+ borrowIn = (blk[k] == 0);
+ subtractBuf[k] = blk[k] - 1;
+ }
+ /*
+ * If the subtraction was performed successfully (!borrowIn),
+ * set bit i2 in block i of the quotient.
+ *
+ * Then, copy the portion of subtractBuf filled by the subtraction
+ * back to *this. This portion starts with block i and ends--
+ * where? Not necessarily at block `i + b.len'! Well, we
+ * increased k every time we saved a block into subtractBuf, so
+ * the region of subtractBuf we copy is just [i, k).
+ */
+ if (!borrowIn) {
+ q.blk[i] |= (Blk(1) << i2);
+ while (k > i) {
+ k--;
+ blk[k] = subtractBuf[k];
+ }
+ }
+ }
+ }
+ // Zap possible leading zero in quotient
+ if (q.blk[q.len - 1] == 0)
+ q.len--;
+ // Zap any/all leading zeros in remainder
+ zapLeadingZeros();
+ // Deallocate subtractBuf.
+ // (Thanks to Brad Spencer for noticing my accidental omission of this!)
+ delete [] subtractBuf;
+}
+
+/* BITWISE OPERATORS
+ * These are straightforward blockwise operations except that they differ in
+ * the output length and the necessity of zapLeadingZeros. */
+
+void BigUnsigned::bitAnd(const BigUnsigned &a, const BigUnsigned &b) {
+ DTRT_ALIASED(this == &a || this == &b, bitAnd(a, b));
+ // The bitwise & can't be longer than either operand.
+ len = (a.len >= b.len) ? b.len : a.len;
+ allocate(len);
+ Index i;
+ for (i = 0; i < len; i++)
+ blk[i] = a.blk[i] & b.blk[i];
+ zapLeadingZeros();
+}
+
+void BigUnsigned::bitOr(const BigUnsigned &a, const BigUnsigned &b) {
+ DTRT_ALIASED(this == &a || this == &b, bitOr(a, b));
+ Index i;
+ const BigUnsigned *a2, *b2;
+ if (a.len >= b.len) {
+ a2 = &a;
+ b2 = &b;
+ } else {
+ a2 = &b;
+ b2 = &a;
+ }
+ allocate(a2->len);
+ for (i = 0; i < b2->len; i++)
+ blk[i] = a2->blk[i] | b2->blk[i];
+ for (; i < a2->len; i++)
+ blk[i] = a2->blk[i];
+ len = a2->len;
+ // Doesn't need zapLeadingZeros.
+}
+
+void BigUnsigned::bitXor(const BigUnsigned &a, const BigUnsigned &b) {
+ DTRT_ALIASED(this == &a || this == &b, bitXor(a, b));
+ Index i;
+ const BigUnsigned *a2, *b2;
+ if (a.len >= b.len) {
+ a2 = &a;
+ b2 = &b;
+ } else {
+ a2 = &b;
+ b2 = &a;
+ }
+ allocate(a2->len);
+ for (i = 0; i < b2->len; i++)
+ blk[i] = a2->blk[i] ^ b2->blk[i];
+ for (; i < a2->len; i++)
+ blk[i] = a2->blk[i];
+ len = a2->len;
+ zapLeadingZeros();
+}
+
+void BigUnsigned::bitShiftLeft(const BigUnsigned &a, int b) {
+ DTRT_ALIASED(this == &a, bitShiftLeft(a, b));
+ if (b < 0) {
+ if (b << 1 == 0)
+ throw "BigUnsigned::bitShiftLeft: "
+ "Pathological shift amount not implemented";
+ else {
+ bitShiftRight(a, -b);
+ return;
+ }
+ }
+ Index shiftBlocks = b / N;
+ unsigned int shiftBits = b % N;
+ // + 1: room for high bits nudged left into another block
+ len = a.len + shiftBlocks + 1;
+ allocate(len);
+ Index i, j;
+ for (i = 0; i < shiftBlocks; i++)
+ blk[i] = 0;
+ for (j = 0, i = shiftBlocks; j <= a.len; j++, i++)
+ blk[i] = getShiftedBlock(a, j, shiftBits);
+ // Zap possible leading zero
+ if (blk[len - 1] == 0)
+ len--;
+}
+
+void BigUnsigned::bitShiftRight(const BigUnsigned &a, int b) {
+ DTRT_ALIASED(this == &a, bitShiftRight(a, b));
+ if (b < 0) {
+ if (b << 1 == 0)
+ throw "BigUnsigned::bitShiftRight: "
+ "Pathological shift amount not implemented";
+ else {
+ bitShiftLeft(a, -b);
+ return;
+ }
+ }
+ // This calculation is wacky, but expressing the shift as a left bit shift
+ // within each block lets us use getShiftedBlock.
+ Index rightShiftBlocks = (b + N - 1) / N;
+ unsigned int leftShiftBits = N * rightShiftBlocks - b;
+ // Now (N * rightShiftBlocks - leftShiftBits) == b
+ // and 0 <= leftShiftBits < N.
+ if (rightShiftBlocks >= a.len + 1) {
+ // All of a is guaranteed to be shifted off, even considering the left
+ // bit shift.
+ len = 0;
+ return;
+ }
+ // Now we're allocating a positive amount.
+ // + 1: room for high bits nudged left into another block
+ len = a.len + 1 - rightShiftBlocks;
+ allocate(len);
+ Index i, j;
+ for (j = rightShiftBlocks, i = 0; j <= a.len; j++, i++)
+ blk[i] = getShiftedBlock(a, j, leftShiftBits);
+ // Zap possible leading zero
+ if (blk[len - 1] == 0)
+ len--;
+}
+
+// INCREMENT/DECREMENT OPERATORS
+
+// Prefix increment
+void BigUnsigned::operator ++() {
+ Index i;
+ bool carry = true;
+ for (i = 0; i < len && carry; i++) {
+ blk[i]++;
+ carry = (blk[i] == 0);
+ }
+ if (carry) {
+ // Allocate and then increase length, as in divideWithRemainder
+ allocateAndCopy(len + 1);
+ len++;
+ blk[i] = 1;
+ }
+}
+
+// Postfix increment: same as prefix
+void BigUnsigned::operator ++(int) {
+ operator ++();
+}
+
+// Prefix decrement
+void BigUnsigned::operator --() {
+ if (len == 0)
+ throw "BigUnsigned::operator --(): Cannot decrement an unsigned zero";
+ Index i;
+ bool borrow = true;
+ for (i = 0; borrow; i++) {
+ borrow = (blk[i] == 0);
+ blk[i]--;
+ }
+ // Zap possible leading zero (there can only be one)
+ if (blk[len - 1] == 0)
+ len--;
+}
+
+// Postfix decrement: same as prefix
+void BigUnsigned::operator --(int) {
+ operator --();
+}
diff --git a/bigint/BigUnsigned.hh b/bigint/BigUnsigned.hh
new file mode 100644
index 00000000..9228753c
--- /dev/null
+++ b/bigint/BigUnsigned.hh
@@ -0,0 +1,418 @@
+#ifndef BIGUNSIGNED_H
+#define BIGUNSIGNED_H
+
+#include "NumberlikeArray.hh"
+
+/* A BigUnsigned object represents a nonnegative integer of size limited only by
+ * available memory. BigUnsigneds support most mathematical operators and can
+ * be converted to and from most primitive integer types.
+ *
+ * The number is stored as a NumberlikeArray of unsigned longs as if it were
+ * written in base 256^sizeof(unsigned long). The least significant block is
+ * first, and the length is such that the most significant block is nonzero. */
+class BigUnsigned : protected NumberlikeArray<unsigned long> {
+
+public:
+ // Enumeration for the result of a comparison.
+ enum CmpRes { less = -1, equal = 0, greater = 1 };
+
+ // BigUnsigneds are built with a Blk type of unsigned long.
+ typedef unsigned long Blk;
+
+ typedef NumberlikeArray<Blk>::Index Index;
+ using NumberlikeArray<Blk>::N;
+
+protected:
+ // Creates a BigUnsigned with a capacity; for internal use.
+ BigUnsigned(int, Index c) : NumberlikeArray<Blk>(0, c) {}
+
+ // Decreases len to eliminate any leading zero blocks.
+ void zapLeadingZeros() {
+ while (len > 0 && blk[len - 1] == 0)
+ len--;
+ }
+
+public:
+ // Constructs zero.
+ BigUnsigned() : NumberlikeArray<Blk>() {}
+
+ // Copy constructor
+ BigUnsigned(const BigUnsigned &x) : NumberlikeArray<Blk>(x) {}
+
+ // Assignment operator
+ void operator=(const BigUnsigned &x) {
+ NumberlikeArray<Blk>::operator =(x);
+ }
+
+ // Constructor that copies from a given array of blocks.
+ BigUnsigned(const Blk *b, Index blen) : NumberlikeArray<Blk>(b, blen) {
+ // Eliminate any leading zeros we may have been passed.
+ zapLeadingZeros();
+ }
+
+ // Destructor. NumberlikeArray does the delete for us.
+ ~BigUnsigned() {}
+
+ // Constructors from primitive integer types
+ BigUnsigned(unsigned long x);
+ BigUnsigned( long x);
+ BigUnsigned(unsigned int x);
+ BigUnsigned( int x);
+ BigUnsigned(unsigned short x);
+ BigUnsigned( short x);
+protected:
+ // Helpers
+ template <class X> void initFromPrimitive (X x);
+ template <class X> void initFromSignedPrimitive(X x);
+public:
+
+ /* Converters to primitive integer types
+ * The implicit conversion operators caused trouble, so these are now
+ * named. */
+ unsigned long toUnsignedLong () const;
+ long toLong () const;
+ unsigned int toUnsignedInt () const;
+ int toInt () const;
+ unsigned short toUnsignedShort() const;
+ short toShort () const;
+protected:
+ // Helpers
+ template <class X> X convertToSignedPrimitive() const;
+ template <class X> X convertToPrimitive () const;
+public:
+
+ // BIT/BLOCK ACCESSORS
+
+ // Expose these from NumberlikeArray directly.
+ using NumberlikeArray<Blk>::getCapacity;
+ using NumberlikeArray<Blk>::getLength;
+
+ /* Returns the requested block, or 0 if it is beyond the length (as if
+ * the number had 0s infinitely to the left). */
+ Blk getBlock(Index i) const { return i >= len ? 0 : blk[i]; }
+ /* Sets the requested block. The number grows or shrinks as necessary. */
+ void setBlock(Index i, Blk newBlock);
+
+ // The number is zero if and only if the canonical length is zero.
+ bool isZero() const { return NumberlikeArray<Blk>::isEmpty(); }
+
+ /* Returns the length of the number in bits, i.e., zero if the number
+ * is zero and otherwise one more than the largest value of bi for
+ * which getBit(bi) returns true. */
+ Index bitLength() const;
+ /* Get the state of bit bi, which has value 2^bi. Bits beyond the
+ * number's length are considered to be 0. */
+ bool getBit(Index bi) const {
+ return (getBlock(bi / N) & (Blk(1) << (bi % N))) != 0;
+ }
+ /* Sets the state of bit bi to newBit. The number grows or shrinks as
+ * necessary. */
+ void setBit(Index bi, bool newBit);
+
+ // COMPARISONS
+
+ // Compares this to x like Perl's <=>
+ CmpRes compareTo(const BigUnsigned &x) const;
+
+ // Ordinary comparison operators
+ bool operator ==(const BigUnsigned &x) const {
+ return NumberlikeArray<Blk>::operator ==(x);
+ }
+ bool operator !=(const BigUnsigned &x) const {
+ return NumberlikeArray<Blk>::operator !=(x);
+ }
+ bool operator < (const BigUnsigned &x) const { return compareTo(x) == less ; }
+ bool operator <=(const BigUnsigned &x) const { return compareTo(x) != greater; }
+ bool operator >=(const BigUnsigned &x) const { return compareTo(x) != less ; }
+ bool operator > (const BigUnsigned &x) const { return compareTo(x) == greater; }
+
+ /*
+ * BigUnsigned and BigInteger both provide three kinds of operators.
+ * Here ``big-integer'' refers to BigInteger or BigUnsigned.
+ *
+ * (1) Overloaded ``return-by-value'' operators:
+ * +, -, *, /, %, unary -, &, |, ^, <<, >>.
+ * Big-integer code using these operators looks identical to code using
+ * the primitive integer types. These operators take one or two
+ * big-integer inputs and return a big-integer result, which can then
+ * be assigned to a BigInteger variable or used in an expression.
+ * Example:
+ * BigInteger a(1), b = 1;
+ * BigInteger c = a + b;
+ *
+ * (2) Overloaded assignment operators:
+ * +=, -=, *=, /=, %=, flipSign, &=, |=, ^=, <<=, >>=, ++, --.
+ * Again, these are used on big integers just like on ints. They take
+ * one writable big integer that both provides an operand and receives a
+ * result. Most also take a second read-only operand.
+ * Example:
+ * BigInteger a(1), b(1);
+ * a += b;
+ *
+ * (3) Copy-less operations: `add', `subtract', etc.
+ * These named methods take operands as arguments and store the result
+ * in the receiver (*this), avoiding unnecessary copies and allocations.
+ * `divideWithRemainder' is special: it both takes the dividend from and
+ * stores the remainder into the receiver, and it takes a separate
+ * object in which to store the quotient. NOTE: If you are wondering
+ * why these don't return a value, you probably mean to use the
+ * overloaded return-by-value operators instead.
+ *
+ * Examples:
+ * BigInteger a(43), b(7), c, d;
+ *
+ * c = a + b; // Now c == 50.
+ * c.add(a, b); // Same effect but without the two copies.
+ *
+ * c.divideWithRemainder(b, d);
+ * // 50 / 7; now d == 7 (quotient) and c == 1 (remainder).
+ *
+ * // ``Aliased'' calls now do the right thing using a temporary
+ * // copy, but see note on `divideWithRemainder'.
+ * a.add(a, b);
+ */
+
+ // COPY-LESS OPERATIONS
+
+ // These 8: Arguments are read-only operands, result is saved in *this.
+ void add(const BigUnsigned &a, const BigUnsigned &b);
+ void subtract(const BigUnsigned &a, const BigUnsigned &b);
+ void multiply(const BigUnsigned &a, const BigUnsigned &b);
+ void bitAnd(const BigUnsigned &a, const BigUnsigned &b);
+ void bitOr(const BigUnsigned &a, const BigUnsigned &b);
+ void bitXor(const BigUnsigned &a, const BigUnsigned &b);
+ /* Negative shift amounts translate to opposite-direction shifts,
+ * except for -2^(8*sizeof(int)-1) which is unimplemented. */
+ void bitShiftLeft(const BigUnsigned &a, int b);
+ void bitShiftRight(const BigUnsigned &a, int b);
+
+ /* `a.divideWithRemainder(b, q)' is like `q = a / b, a %= b'.
+ * / and % use semantics similar to Knuth's, which differ from the
+ * primitive integer semantics under division by zero. See the
+ * implementation in BigUnsigned.cc for details.
+ * `a.divideWithRemainder(b, a)' throws an exception: it doesn't make
+ * sense to write quotient and remainder into the same variable. */
+ void divideWithRemainder(const BigUnsigned &b, BigUnsigned &q);
+
+ /* `divide' and `modulo' are no longer offered. Use
+ * `divideWithRemainder' instead. */
+
+ // OVERLOADED RETURN-BY-VALUE OPERATORS
+ BigUnsigned operator +(const BigUnsigned &x) const;
+ BigUnsigned operator -(const BigUnsigned &x) const;
+ BigUnsigned operator *(const BigUnsigned &x) const;
+ BigUnsigned operator /(const BigUnsigned &x) const;
+ BigUnsigned operator %(const BigUnsigned &x) const;
+ /* OK, maybe unary minus could succeed in one case, but it really
+ * shouldn't be used, so it isn't provided. */
+ BigUnsigned operator &(const BigUnsigned &x) const;
+ BigUnsigned operator |(const BigUnsigned &x) const;
+ BigUnsigned operator ^(const BigUnsigned &x) const;
+ BigUnsigned operator <<(int b) const;
+ BigUnsigned operator >>(int b) const;
+
+ // OVERLOADED ASSIGNMENT OPERATORS
+ void operator +=(const BigUnsigned &x);
+ void operator -=(const BigUnsigned &x);
+ void operator *=(const BigUnsigned &x);
+ void operator /=(const BigUnsigned &x);
+ void operator %=(const BigUnsigned &x);
+ void operator &=(const BigUnsigned &x);
+ void operator |=(const BigUnsigned &x);
+ void operator ^=(const BigUnsigned &x);
+ void operator <<=(int b);
+ void operator >>=(int b);
+
+ /* INCREMENT/DECREMENT OPERATORS
+ * To discourage messy coding, these do not return *this, so prefix
+ * and postfix behave the same. */
+ void operator ++( );
+ void operator ++(int);
+ void operator --( );
+ void operator --(int);
+
+ // Helper function that needs access to BigUnsigned internals
+ friend Blk getShiftedBlock(const BigUnsigned &num, Index x,
+ unsigned int y);
+
+ // See BigInteger.cc.
+ template <class X>
+ friend X convertBigUnsignedToPrimitiveAccess(const BigUnsigned &a);
+};
+
+/* Implementing the return-by-value and assignment operators in terms of the
+ * copy-less operations. The copy-less operations are responsible for making
+ * any necessary temporary copies to work around aliasing. */
+
+inline BigUnsigned BigUnsigned::operator +(const BigUnsigned &x) const {
+ BigUnsigned ans;
+ ans.add(*this, x);
+ return ans;
+}
+inline BigUnsigned BigUnsigned::operator -(const BigUnsigned &x) const {
+ BigUnsigned ans;
+ ans.subtract(*this, x);
+ return ans;
+}
+inline BigUnsigned BigUnsigned::operator *(const BigUnsigned &x) const {
+ BigUnsigned ans;
+ ans.multiply(*this, x);
+ return ans;
+}
+inline BigUnsigned BigUnsigned::operator /(const BigUnsigned &x) const {
+ if (x.isZero()) throw "BigUnsigned::operator /: division by zero";
+ BigUnsigned q, r;
+ r = *this;
+ r.divideWithRemainder(x, q);
+ return q;
+}
+inline BigUnsigned BigUnsigned::operator %(const BigUnsigned &x) const {
+ if (x.isZero()) throw "BigUnsigned::operator %: division by zero";
+ BigUnsigned q, r;
+ r = *this;
+ r.divideWithRemainder(x, q);
+ return r;
+}
+inline BigUnsigned BigUnsigned::operator &(const BigUnsigned &x) const {
+ BigUnsigned ans;
+ ans.bitAnd(*this, x);
+ return ans;
+}
+inline BigUnsigned BigUnsigned::operator |(const BigUnsigned &x) const {
+ BigUnsigned ans;
+ ans.bitOr(*this, x);
+ return ans;
+}
+inline BigUnsigned BigUnsigned::operator ^(const BigUnsigned &x) const {
+ BigUnsigned ans;
+ ans.bitXor(*this, x);
+ return ans;
+}
+inline BigUnsigned BigUnsigned::operator <<(int b) const {
+ BigUnsigned ans;
+ ans.bitShiftLeft(*this, b);
+ return ans;
+}
+inline BigUnsigned BigUnsigned::operator >>(int b) const {
+ BigUnsigned ans;
+ ans.bitShiftRight(*this, b);
+ return ans;
+}
+
+inline void BigUnsigned::operator +=(const BigUnsigned &x) {
+ add(*this, x);
+}
+inline void BigUnsigned::operator -=(const BigUnsigned &x) {
+ subtract(*this, x);
+}
+inline void BigUnsigned::operator *=(const BigUnsigned &x) {
+ multiply(*this, x);
+}
+inline void BigUnsigned::operator /=(const BigUnsigned &x) {
+ if (x.isZero()) throw "BigUnsigned::operator /=: division by zero";
+ /* The following technique is slightly faster than copying *this first
+ * when x is large. */
+ BigUnsigned q;
+ divideWithRemainder(x, q);
+ // *this contains the remainder, but we overwrite it with the quotient.
+ *this = q;
+}
+inline void BigUnsigned::operator %=(const BigUnsigned &x) {
+ if (x.isZero()) throw "BigUnsigned::operator %=: division by zero";
+ BigUnsigned q;
+ // Mods *this by x. Don't care about quotient left in q.
+ divideWithRemainder(x, q);
+}
+inline void BigUnsigned::operator &=(const BigUnsigned &x) {
+ bitAnd(*this, x);
+}
+inline void BigUnsigned::operator |=(const BigUnsigned &x) {
+ bitOr(*this, x);
+}
+inline void BigUnsigned::operator ^=(const BigUnsigned &x) {
+ bitXor(*this, x);
+}
+inline void BigUnsigned::operator <<=(int b) {
+ bitShiftLeft(*this, b);
+}
+inline void BigUnsigned::operator >>=(int b) {
+ bitShiftRight(*this, b);
+}
+
+/* Templates for conversions of BigUnsigned to and from primitive integers.
+ * BigInteger.cc needs to instantiate convertToPrimitive, and the uses in
+ * BigUnsigned.cc didn't do the trick; I think g++ inlined convertToPrimitive
+ * instead of generating linkable instantiations. So for consistency, I put
+ * all the templates here. */
+
+// CONSTRUCTION FROM PRIMITIVE INTEGERS
+
+/* Initialize this BigUnsigned from the given primitive integer. The same
+ * pattern works for all primitive integer types, so I put it into a template to
+ * reduce code duplication. (Don't worry: this is protected and we instantiate
+ * it only with primitive integer types.) Type X could be signed, but x is
+ * known to be nonnegative. */
+template <class X>
+void BigUnsigned::initFromPrimitive(X x) {
+ if (x == 0)
+ ; // NumberlikeArray already initialized us to zero.
+ else {
+ // Create a single block. blk is NULL; no need to delete it.
+ cap = 1;
+ blk = new Blk[1];
+ len = 1;
+ blk[0] = Blk(x);
+ }
+}
+
+/* Ditto, but first check that x is nonnegative. I could have put the check in
+ * initFromPrimitive and let the compiler optimize it out for unsigned-type
+ * instantiations, but I wanted to avoid the warning stupidly issued by g++ for
+ * a condition that is constant in *any* instantiation, even if not in all. */
+template <class X>
+void BigUnsigned::initFromSignedPrimitive(X x) {
+ if (x < 0)
+ throw "BigUnsigned constructor: "
+ "Cannot construct a BigUnsigned from a negative number";
+ else
+ initFromPrimitive(x);
+}
+
+// CONVERSION TO PRIMITIVE INTEGERS
+
+/* Template with the same idea as initFromPrimitive. This might be slightly
+ * slower than the previous version with the masks, but it's much shorter and
+ * clearer, which is the library's stated goal. */
+template <class X>
+X BigUnsigned::convertToPrimitive() const {
+ if (len == 0)
+ // The number is zero; return zero.
+ return 0;
+ else if (len == 1) {
+ // The single block might fit in an X. Try the conversion.
+ X x = X(blk[0]);
+ // Make sure the result accurately represents the block.
+ if (Blk(x) == blk[0])
+ // Successful conversion.
+ return x;
+ // Otherwise fall through.
+ }
+ throw "BigUnsigned::to<Primitive>: "
+ "Value is too big to fit in the requested type";
+}
+
+/* Wrap the above in an x >= 0 test to make sure we got a nonnegative result,
+ * not a negative one that happened to convert back into the correct nonnegative
+ * one. (E.g., catch incorrect conversion of 2^31 to the long -2^31.) Again,
+ * separated to avoid a g++ warning. */
+template <class X>
+X BigUnsigned::convertToSignedPrimitive() const {
+ X x = convertToPrimitive<X>();
+ if (x >= 0)
+ return x;
+ else
+ throw "BigUnsigned::to(Primitive): "
+ "Value is too big to fit in the requested type";
+}
+
+#endif
diff --git a/bigint/BigUnsignedInABase.cc b/bigint/BigUnsignedInABase.cc
new file mode 100644
index 00000000..999faaf2
--- /dev/null
+++ b/bigint/BigUnsignedInABase.cc
@@ -0,0 +1,125 @@
+#include "BigUnsignedInABase.hh"
+
+BigUnsignedInABase::BigUnsignedInABase(const Digit *d, Index l, Base base)
+ : NumberlikeArray<Digit>(d, l), base(base) {
+ // Check the base
+ if (base < 2)
+ throw "BigUnsignedInABase::BigUnsignedInABase(const Digit *, Index, Base): The base must be at least 2";
+
+ // Validate the digits.
+ for (Index i = 0; i < l; i++)
+ if (blk[i] >= base)
+ throw "BigUnsignedInABase::BigUnsignedInABase(const Digit *, Index, Base): A digit is too large for the specified base";
+
+ // Eliminate any leading zeros we may have been passed.
+ zapLeadingZeros();
+}
+
+namespace {
+ unsigned int bitLen(unsigned int x) {
+ unsigned int len = 0;
+ while (x > 0) {
+ x >>= 1;
+ len++;
+ }
+ return len;
+ }
+ unsigned int ceilingDiv(unsigned int a, unsigned int b) {
+ return (a + b - 1) / b;
+ }
+}
+
+BigUnsignedInABase::BigUnsignedInABase(const BigUnsigned &x, Base base) {
+ // Check the base
+ if (base < 2)
+ throw "BigUnsignedInABase(BigUnsigned, Base): The base must be at least 2";
+ this->base = base;
+
+ // Get an upper bound on how much space we need
+ int maxBitLenOfX = x.getLength() * BigUnsigned::N;
+ int minBitsPerDigit = bitLen(base) - 1;
+ int maxDigitLenOfX = ceilingDiv(maxBitLenOfX, minBitsPerDigit);
+ len = maxDigitLenOfX; // Another change to comply with `staying in bounds'.
+ allocate(len); // Get the space
+
+ BigUnsigned x2(x), buBase(base);
+ Index digitNum = 0;
+
+ while (!x2.isZero()) {
+ // Get last digit. This is like `lastDigit = x2 % buBase, x2 /= buBase'.
+ BigUnsigned lastDigit(x2);
+ lastDigit.divideWithRemainder(buBase, x2);
+ // Save the digit.
+ blk[digitNum] = lastDigit.toUnsignedShort();
+ // Move on. We can't run out of room: we figured it out above.
+ digitNum++;
+ }
+
+ // Save the actual length.
+ len = digitNum;
+}
+
+BigUnsignedInABase::operator BigUnsigned() const {
+ BigUnsigned ans(0), buBase(base), temp;
+ Index digitNum = len;
+ while (digitNum > 0) {
+ digitNum--;
+ temp.multiply(ans, buBase);
+ ans.add(temp, BigUnsigned(blk[digitNum]));
+ }
+ return ans;
+}
+
+BigUnsignedInABase::BigUnsignedInABase(const std::string &s, Base base) {
+ // Check the base.
+ if (base > 36)
+ throw "BigUnsignedInABase(std::string, Base): The default string conversion routines use the symbol set 0-9, A-Z and therefore support only up to base 36. You tried a conversion with a base over 36; write your own string conversion routine.";
+ // Save the base.
+ // This pattern is seldom seen in C++, but the analogous ``this.'' is common in Java.
+ this->base = base;
+
+ // `s.length()' is a `size_t', while `len' is a `NumberlikeArray::Index',
+ // also known as an `unsigned int'. Some compilers warn without this cast.
+ len = Index(s.length());
+ allocate(len);
+
+ Index digitNum, symbolNumInString;
+ for (digitNum = 0; digitNum < len; digitNum++) {
+ symbolNumInString = len - 1 - digitNum;
+ char theSymbol = s[symbolNumInString];
+ if (theSymbol >= '0' && theSymbol <= '9')
+ blk[digitNum] = theSymbol - '0';
+ else if (theSymbol >= 'A' && theSymbol <= 'Z')
+ blk[digitNum] = theSymbol - 'A' + 10;
+ else if (theSymbol >= 'a' && theSymbol <= 'z')
+ blk[digitNum] = theSymbol - 'a' + 10;
+ else
+ throw "BigUnsignedInABase(std::string, Base): Bad symbol in input. Only 0-9, A-Z, a-z are accepted.";
+
+ if (blk[digitNum] >= base)
+ throw "BigUnsignedInABase::BigUnsignedInABase(const Digit *, Index, Base): A digit is too large for the specified base";
+ }
+ zapLeadingZeros();
+}
+
+BigUnsignedInABase::operator std::string() const {
+ if (base > 36)
+ throw "BigUnsignedInABase ==> std::string: The default string conversion routines use the symbol set 0-9, A-Z and therefore support only up to base 36. You tried a conversion with a base over 36; write your own string conversion routine.";
+ if (len == 0)
+ return std::string("0");
+ // Some compilers don't have push_back, so use a char * buffer instead.
+ char *s = new char[len + 1];
+ s[len] = '\0';
+ Index digitNum, symbolNumInString;
+ for (symbolNumInString = 0; symbolNumInString < len; symbolNumInString++) {
+ digitNum = len - 1 - symbolNumInString;
+ Digit theDigit = blk[digitNum];
+ if (theDigit < 10)
+ s[symbolNumInString] = char('0' + theDigit);
+ else
+ s[symbolNumInString] = char('A' + theDigit - 10);
+ }
+ std::string s2(s);
+ delete [] s;
+ return s2;
+}
diff --git a/bigint/BigUnsignedInABase.hh b/bigint/BigUnsignedInABase.hh
new file mode 100644
index 00000000..0ea89c6e
--- /dev/null
+++ b/bigint/BigUnsignedInABase.hh
@@ -0,0 +1,122 @@
+#ifndef BIGUNSIGNEDINABASE_H
+#define BIGUNSIGNEDINABASE_H
+
+#include "NumberlikeArray.hh"
+#include "BigUnsigned.hh"
+#include <string>
+
+/*
+ * A BigUnsignedInABase object represents a nonnegative integer of size limited
+ * only by available memory, represented in a user-specified base that can fit
+ * in an `unsigned short' (most can, and this saves memory).
+ *
+ * BigUnsignedInABase is intended as an intermediary class with little
+ * functionality of its own. BigUnsignedInABase objects can be constructed
+ * from, and converted to, BigUnsigneds (requiring multiplication, mods, etc.)
+ * and `std::string's (by switching digit values for appropriate characters).
+ *
+ * BigUnsignedInABase is similar to BigUnsigned. Note the following:
+ *
+ * (1) They represent the number in exactly the same way, except that
+ * BigUnsignedInABase uses ``digits'' (or Digit) where BigUnsigned uses
+ * ``blocks'' (or Blk).
+ *
+ * (2) Both use the management features of NumberlikeArray. (In fact, my desire
+ * to add a BigUnsignedInABase class without duplicating a lot of code led me to
+ * introduce NumberlikeArray.)
+ *
+ * (3) The only arithmetic operation supported by BigUnsignedInABase is an
+ * equality test. Use BigUnsigned for arithmetic.
+ */
+
+class BigUnsignedInABase : protected NumberlikeArray<unsigned short> {
+
+public:
+ // The digits of a BigUnsignedInABase are unsigned shorts.
+ typedef unsigned short Digit;
+ // That's also the type of a base.
+ typedef Digit Base;
+
+protected:
+ // The base in which this BigUnsignedInABase is expressed
+ Base base;
+
+ // Creates a BigUnsignedInABase with a capacity; for internal use.
+ BigUnsignedInABase(int, Index c) : NumberlikeArray<Digit>(0, c) {}
+
+ // Decreases len to eliminate any leading zero digits.
+ void zapLeadingZeros() {
+ while (len > 0 && blk[len - 1] == 0)
+ len--;
+ }
+
+public:
+ // Constructs zero in base 2.
+ BigUnsignedInABase() : NumberlikeArray<Digit>(), base(2) {}
+
+ // Copy constructor
+ BigUnsignedInABase(const BigUnsignedInABase &x) : NumberlikeArray<Digit>(x), base(x.base) {}
+
+ // Assignment operator
+ void operator =(const BigUnsignedInABase &x) {
+ NumberlikeArray<Digit>::operator =(x);
+ base = x.base;
+ }
+
+ // Constructor that copies from a given array of digits.
+ BigUnsignedInABase(const Digit *d, Index l, Base base);
+
+ // Destructor. NumberlikeArray does the delete for us.
+ ~BigUnsignedInABase() {}
+
+ // LINKS TO BIGUNSIGNED
+ BigUnsignedInABase(const BigUnsigned &x, Base base);
+ operator BigUnsigned() const;
+
+ /* LINKS TO STRINGS
+ *
+ * These use the symbols ``0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'' to
+ * represent digits of 0 through 35. When parsing strings, lowercase is
+ * also accepted.
+ *
+ * All string representations are big-endian (big-place-value digits
+ * first). (Computer scientists have adopted zero-based counting; why
+ * can't they tolerate little-endian numbers?)
+ *
+ * No string representation has a ``base indicator'' like ``0x''.
+ *
+ * An exception is made for zero: it is converted to ``0'' and not the
+ * empty string.
+ *
+ * If you want different conventions, write your own routines to go
+ * between BigUnsignedInABase and strings. It's not hard.
+ */
+ operator std::string() const;
+ BigUnsignedInABase(const std::string &s, Base base);
+
+public:
+
+ // ACCESSORS
+ Base getBase() const { return base; }
+
+ // Expose these from NumberlikeArray directly.
+ using NumberlikeArray<Digit>::getCapacity;
+ using NumberlikeArray<Digit>::getLength;
+
+ /* Returns the requested digit, or 0 if it is beyond the length (as if
+ * the number had 0s infinitely to the left). */
+ Digit getDigit(Index i) const { return i >= len ? 0 : blk[i]; }
+
+ // The number is zero if and only if the canonical length is zero.
+ bool isZero() const { return NumberlikeArray<Digit>::isEmpty(); }
+
+ /* Equality test. For the purposes of this test, two BigUnsignedInABase
+ * values must have the same base to be equal. */
+ bool operator ==(const BigUnsignedInABase &x) const {
+ return base == x.base && NumberlikeArray<Digit>::operator ==(x);
+ }
+ bool operator !=(const BigUnsignedInABase &x) const { return !operator ==(x); }
+
+};
+
+#endif
diff --git a/bigint/ChangeLog b/bigint/ChangeLog
new file mode 100644
index 00000000..ac6927c4
--- /dev/null
+++ b/bigint/ChangeLog
@@ -0,0 +1,146 @@
+ Change Log
+
+These entries tell you what was added, fixed, or improved in each version as
+compared to the previous one. In case you haven't noticed, a version number
+roughly corresponds to the release date of that version in `YYYY.MM.DD[.N]'
+format, where `.N' goes `.2', `.3', etc. if there are multiple versions on the
+same day. The topmost version listed is the one you have.
+
+2010.04.30
+----------
+- Strengthen the advice about build/IDE configuration in the README.
+
+2009.05.03
+----------
+- BigUnsigned::{get,set}Bit: Change two remaining `1 <<' to `Blk(1) <<' to work
+ on systems where sizeof(unsigned int) != sizeof(Blk). Bug reported by Brad
+ Spencer.
+- dataToBigInteger: Change a `delete' to `delete []' to avoid leaking memory.
+ Bug reported by Nicolás Carrasco.
+
+2009.03.26
+----------
+- BigUnsignedInABase(std::string) Reject digits too big for the base.
+ Bug reported by Niakam Kazemi.
+
+2008.07.20
+----------
+Dennis Yew pointed out serious problems with ambiguities and unwanted
+conversions when mixing BigInteger/BigUnsigned and primitive integers. To fix
+these, I removed the implicit conversions from BigInteger/BigUnsigned to
+primitive integers and from BigInteger to BigUnsigned. Removing the
+BigInteger-to-BigUnsigned conversion required changing BigInteger to have a
+BigUnsigned field instead of inheriting from it; this was a complex task but
+ultimately gave a saner design. At the same time, I went through the entire
+codebase, making the formatting and comments prettier and reworking anything I
+thought was unclear. I also added a testsuite (currently for 32-bit systems
+only); it doesn't yet cover the entire library but should help to ensure that
+things work the way they should.
+
+A number of changes from version 2007.07.07 break compatibility with existing
+code that uses the library, but updating that code should be pretty easy:
+- BigInteger can no longer be implicitly converted to BigUnsigned. Use
+ getMagnitude() instead.
+- BigUnsigned and BigInteger can no longer be implicitly converted to primitive
+ integers. Use the toInt() family of functions instead.
+- The easy* functions have been renamed to more mature names:
+ bigUnsignedToString, bigIntegerToString, stringToBigUnsigned,
+ stringToBigInteger, dataToBigInteger.
+- BigInteger no longer supports bitwise operations. Get the magnitude with
+ getMagnitude() and operate on that instead.
+- The old {BigUnsigned,BigInteger}::{divide,modulo} copy-less options have been
+ removed. Use divideWithRemainder instead.
+- Added a base argument to BigUnsignedInABase's digit-array constructor. I
+ ope no one used that constructor in its broken state anyway.
+
+Other notable changes:
+- Added BigUnsigned functions setBlock, bitLength, getBit, setBit.
+- The bit-shifting operations now support negative shift amounts, which shift in
+ the other direction.
+- Added some big-integer algorithms in BigIntegerAlgorithms.hh: gcd,
+ extendedEuclidean, modinv, modexp.
+
+2007.07.07
+----------
+Update the "Running the sample program produces this output:" comment in
+sample.cc for the bitwise operators.
+
+2007.06.14
+----------
+- Implement << and >> for BigUnsigned in response to email from Marco Schulze.
+- Fix name: DOTR_ALIASED -> DTRT_ALIASED.
+- Demonstrate all bitwise operators (&, |, ^, <<, >>) in sample.cc.
+
+2007.02.16
+----------
+Boris Dessy pointed out that the library threw an exception on "a *= a", so I changed all the put-here operations to handle aliased calls correctly using a temporary copy instead of throwing exceptions.
+
+2006.08.14
+----------
+In BigUnsigned::bitXor, change allocate(b2->len) to allocate(a2->len): we should allocate enough space for the longer number, not the shorter one! Thanks to Sriram Sankararaman for pointing this out.
+
+2006.05.03
+----------
+I ran the sample program using valgrind and discovered a `delete s' that should be `delete [] s' and a `len++' before an `allocateAndCopy(len)' that should have been after an `allocateAndCopy(len + 1)'. I fixed both. Yay for valgrind!
+
+2006.05.01
+----------
+I fixed incorrect results reported by Mohand Mezmaz and related memory corruption on platforms where Blk is bigger than int. I replaced (1 << x) with (Blk(1) << x) in two places in BigUnsigned.cc.
+
+2006.04.24
+----------
+Two bug fixes: BigUnsigned "++x" no longer segfaults when x grows in length, and BigUnsigned == and != are now redeclared so as to be usable. I redid the Makefile: I removed the *.tag mechanism and hard-coded the library's header dependencies, I added comments, and I made the Makefile more useful for building one's own programs instead of just the sample.
+
+2006.02.26
+----------
+A few tweaks in preparation for a group to distribute the library. The project Web site has moved; I updated the references. I fixed a typo and added a missing function in NumberlikeArray.hh. I'm using Eclipse now, so you get Eclipse project files.
+
+2005.03.30
+----------
+Sam Larkin found a bug in `BigInteger::subtract'; I fixed it.
+
+2005.01.18
+----------
+I fixed some problems with `easyDataToBI'. Due to some multiply declared variables, this function would not compile. However, it is a template function, so the compiler parses it and doesn't compile the parsed representation until something uses the function; this is how I missed the problems. I also removed debugging output from this function.
+
+2005.01.17
+----------
+A fix to some out-of-bounds accesses reported by Milan Tomic (see the comment under `BigUnsigned::divideWithRemainder'). `BigUnsigned::multiply' and `BigUnsigned::divideWithRemainder' implementations neatened up a bit with the help of a function `getShiftedBlock'. I (finally!) introduced a constant `BigUnsigned::N', the number of bits in a `BigUnsigned::Blk', which varies depending on machine word size. In both code and comments, it replaces the much clunkier `8*sizeof(Blk)'. Numerous other small changes. There's a new conversion routine `easyDataToBI' that will convert almost any format of binary data to a `BigInteger'.
+
+I have inserted a significant number of new comments. Most explain unobvious aspects of the code.
+
+2005.01.06
+----------
+Some changes to the way zero-length arrays are handled by `NumberlikeArray', which fixed a memory leak reported by Milan Tomic.
+
+2004.12.24.2
+------------
+I tied down a couple of loose ends involving division/modulo. I added an explanation of put-here vs. overloaded operators in the sample program; this has confused too many people. Miscellaneous other improvements.
+
+I believe that, at this point, the Big Integer Library makes no assumptions about the word size of the machine it is using. `BigUnsigned::Blk' is always an `unsigned long', whatever that may be, and its size is computed with `sizeof' when necessary. However, just in case, I would be interested to have someone test the library on a non-32-bit machine to see if it works.
+
+2004.12.24
+----------
+This is a _major_ upgrade to the library. Among the things that have changed:
+
+I wrote the original version of the library, particularly the four ``classical algorithms'' in `BigUnsigned.cc', using array indexing. Then I rewrote it to use pointers because I thought that would be faster. But recently, I revisited the code in `BigUnsigned.cc' and found that I could not begin to understand what it was doing.
+
+I have decided that the drawbacks of pointers, increased coding difficulty and reduced code readability, far outweigh their speed benefits. Plus, any modern optimizing compiler should produce fast code either way. Therefore, I rewrote the library to use array indexing again. (Thank goodness for regular-expression find-and-replace. It saved me a lot of time.)
+
+The put-here operations `divide' and `modulo' of each of `BigUnsigned' and `BigInteger' have been supplanted by a single operation `divideWithRemainder'. Read the profuse comments for more information on its exact behavior.
+
+There is a new class `BigUnsignedInABase' that is like `BigUnsigned' but uses a user-specified, small base instead of `256 ^ sizeof(unsigned long)'. Much of the code common to the two has been factored out into `NumberlikeArray'.
+
+`BigUnsignedInABase' facilitates conversion between `BigUnsigned's and digit-by-digit string representations using `std::string'. Convenience routines to do this conversion are in `BigIntegerUtils.hh'. `iostream' compatibility has been improved.
+
+I would like to thank Chris Morbitzer for the e-mail message that catalyzed this major upgrade. He wanted a way to convert a string to a BigInteger. One thing just led to another, roughly in reverse order from how they are listed here.
+
+2004.1216
+---------
+Brad Spencer pointed out a memory leak in `BigUnsigned::divide'. It is fixed in the December 16, 2004 version.
+
+2004.1205
+---------
+After months of inactivity, I fixed a bug in the `BigInteger' division routine; thanks to David Allen for reporting the bug. I also added simple routines for decimal output to `std::ostream's, and there is a demo that prints out powers of 3.
+
+~~~~
diff --git a/bigint/Makefile b/bigint/Makefile
new file mode 100644
index 00000000..3018e98e
--- /dev/null
+++ b/bigint/Makefile
@@ -0,0 +1,73 @@
+# Mention default target.
+all:
+
+# Implicit rule to compile C++ files. Modify to your taste.
+%.o: %.cc
+ g++ -c -O2 -Wall -Wextra -pedantic $<
+
+# Components of the library.
+library-objects = \
+ BigUnsigned.o \
+ BigInteger.o \
+ BigIntegerAlgorithms.o \
+ BigUnsignedInABase.o \
+ BigIntegerUtils.o \
+
+library-headers = \
+ NumberlikeArray.hh \
+ BigUnsigned.hh \
+ BigInteger.hh \
+ BigIntegerAlgorithms.hh \
+ BigUnsignedInABase.hh \
+ BigIntegerLibrary.hh \
+
+# To ``make the library'', make all its objects using the implicit rule.
+library: $(library-objects)
+
+# Conservatively assume that all the objects depend on all the headers.
+$(library-objects): $(library-headers)
+
+# TESTSUITE (NOTE: Currently expects a 32-bit system)
+# Compiling the testsuite.
+testsuite.o: $(library-headers)
+testsuite: testsuite.o $(library-objects)
+ g++ $^ -o $@
+# Extract the expected output from the testsuite source.
+testsuite.expected: testsuite.cc
+ nl -ba -p -s: $< | sed -nre 's,^ +([0-9]+):.*//([^ ]),Line \1: \2,p' >$@
+# Run the testsuite.
+.PHONY: test
+test: testsuite testsuite.expected
+ ./run-testsuite
+testsuite-cleanfiles = \
+ testsuite.o testsuite testsuite.expected \
+ testsuite.out testsuite.err
+
+# The rules below build a program that uses the library. They are preset to
+# build ``sample'' from ``sample.cc''. You can change the name(s) of the
+# source file(s) and program file to build your own program, or you can write
+# your own Makefile.
+
+# Components of the program.
+program = sample
+program-objects = sample.o
+
+# Conservatively assume all the program source files depend on all the library
+# headers. You can change this if it is not the case.
+$(program-objects) : $(library-headers)
+
+# How to link the program. The implicit rule covers individual objects.
+$(program) : $(program-objects) $(library-objects)
+ g++ $^ -o $@
+
+# Delete all generated files we know about.
+clean :
+ rm -f $(library-objects) $(testsuite-cleanfiles) $(program-objects) $(program)
+
+# I removed the *.tag dependency tracking system because it had few advantages
+# over manually entering all the dependencies. If there were a portable,
+# reliable dependency tracking system, I'd use it, but I know of no such;
+# cons and depcomp are almost good enough.
+
+# Come back and define default target.
+all : library $(program)
diff --git a/bigint/NumberlikeArray.hh b/bigint/NumberlikeArray.hh
new file mode 100644
index 00000000..53c8e5be
--- /dev/null
+++ b/bigint/NumberlikeArray.hh
@@ -0,0 +1,177 @@
+#ifndef NUMBERLIKEARRAY_H
+#define NUMBERLIKEARRAY_H
+
+// Make sure we have NULL.
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* A NumberlikeArray<Blk> object holds a heap-allocated array of Blk with a
+ * length and a capacity and provides basic memory management features.
+ * BigUnsigned and BigUnsignedInABase both subclass it.
+ *
+ * NumberlikeArray provides no information hiding. Subclasses should use
+ * nonpublic inheritance and manually expose members as desired using
+ * declarations like this:
+ *
+ * public:
+ * NumberlikeArray< the-type-argument >::getLength;
+ */
+template <class Blk>
+class NumberlikeArray {
+public:
+
+ // Type for the index of a block in the array
+ typedef unsigned int Index;
+ // The number of bits in a block, defined below.
+ static const unsigned int N;
+
+ // The current allocated capacity of this NumberlikeArray (in blocks)
+ Index cap;
+ // The actual length of the value stored in this NumberlikeArray (in blocks)
+ Index len;
+ // Heap-allocated array of the blocks (can be NULL if len == 0)
+ Blk *blk;
+
+ // Constructs a ``zero'' NumberlikeArray with the given capacity.
+ NumberlikeArray(Index c) : cap(c), len(0) {
+ blk = (cap > 0) ? (new Blk[cap]) : NULL;
+ }
+
+ /* Constructs a zero NumberlikeArray without allocating a backing array.
+ * A subclass that doesn't know the needed capacity at initialization
+ * time can use this constructor and then overwrite blk without first
+ * deleting it. */
+ NumberlikeArray() : cap(0), len(0) {
+ blk = NULL;
+ }
+
+ // Destructor. Note that `delete NULL' is a no-op.
+ ~NumberlikeArray() {
+ delete [] blk;
+ }
+
+ /* Ensures that the array has at least the requested capacity; may
+ * destroy the contents. */
+ void allocate(Index c);
+
+ /* Ensures that the array has at least the requested capacity; does not
+ * destroy the contents. */
+ void allocateAndCopy(Index c);
+
+ // Copy constructor
+ NumberlikeArray(const NumberlikeArray<Blk> &x);
+
+ // Assignment operator
+ void operator=(const NumberlikeArray<Blk> &x);
+
+ // Constructor that copies from a given array of blocks
+ NumberlikeArray(const Blk *b, Index blen);
+
+ // ACCESSORS
+ Index getCapacity() const { return cap; }
+ Index getLength() const { return len; }
+ Blk getBlock(Index i) const { return blk[i]; }
+ bool isEmpty() const { return len == 0; }
+
+ /* Equality comparison: checks if both objects have the same length and
+ * equal (==) array elements to that length. Subclasses may wish to
+ * override. */
+ bool operator ==(const NumberlikeArray<Blk> &x) const;
+
+ bool operator !=(const NumberlikeArray<Blk> &x) const {
+ return !operator ==(x);
+ }
+};
+
+/* BEGIN TEMPLATE DEFINITIONS. They are present here so that source files that
+ * include this header file can generate the necessary real definitions. */
+
+template <class Blk>
+const unsigned int NumberlikeArray<Blk>::N = 8 * sizeof(Blk);
+
+template <class Blk>
+void NumberlikeArray<Blk>::allocate(Index c) {
+ // If the requested capacity is more than the current capacity...
+ if (c > cap) {
+ // Delete the old number array
+ delete [] blk;
+ // Allocate the new array
+ cap = c;
+ blk = new Blk[cap];
+ }
+}
+
+template <class Blk>
+void NumberlikeArray<Blk>::allocateAndCopy(Index c) {
+ // If the requested capacity is more than the current capacity...
+ if (c > cap) {
+ Blk *oldBlk = blk;
+ // Allocate the new number array
+ cap = c;
+ blk = new Blk[cap];
+ // Copy number blocks
+ Index i;
+ for (i = 0; i < len; i++)
+ blk[i] = oldBlk[i];
+ // Delete the old array
+ delete [] oldBlk;
+ }
+}
+
+template <class Blk>
+NumberlikeArray<Blk>::NumberlikeArray(const NumberlikeArray<Blk> &x)
+ : len(x.len) {
+ // Create array
+ cap = len;
+ blk = new Blk[cap];
+ // Copy blocks
+ Index i;
+ for (i = 0; i < len; i++)
+ blk[i] = x.blk[i];
+}
+
+template <class Blk>
+void NumberlikeArray<Blk>::operator=(const NumberlikeArray<Blk> &x) {
+ /* Calls like a = a have no effect; catch them before the aliasing
+ * causes a problem */
+ if (this == &x)
+ return;
+ // Copy length
+ len = x.len;
+ // Expand array if necessary
+ allocate(len);
+ // Copy number blocks
+ Index i;
+ for (i = 0; i < len; i++)
+ blk[i] = x.blk[i];
+}
+
+template <class Blk>
+NumberlikeArray<Blk>::NumberlikeArray(const Blk *b, Index blen)
+ : cap(blen), len(blen) {
+ // Create array
+ blk = new Blk[cap];
+ // Copy blocks
+ Index i;
+ for (i = 0; i < len; i++)
+ blk[i] = b[i];
+}
+
+template <class Blk>
+bool NumberlikeArray<Blk>::operator ==(const NumberlikeArray<Blk> &x) const {
+ if (len != x.len)
+ // Definitely unequal.
+ return false;
+ else {
+ // Compare corresponding blocks one by one.
+ Index i;
+ for (i = 0; i < len; i++)
+ if (blk[i] != x.blk[i])
+ return false;
+ // No blocks differed, so the objects are equal.
+ return true;
+ }
+}
+
+#endif
diff --git a/bigint/README b/bigint/README
new file mode 100644
index 00000000..e1842381
--- /dev/null
+++ b/bigint/README
@@ -0,0 +1,81 @@
+
+Note by Clifford Wolf:
+This version of bigint was downloaded at 2012-08-29 from
+https://mattmccutchen.net/bigint/bigint-2010.04.30.tar.bz2
+
+Some minor changes were made to the source code (e.g. "using"
+was added to access declarations to prohibit compiler warnings).
+
+
+==============================================================================
+
+ C++ Big Integer Library
+ (see ChangeLog for version)
+
+ http://mattmccutchen.net/bigint/
+
+ Written and maintained by Matt McCutchen <matt@mattmccutchen.net>
+
+You can use this library in a C++ program to do arithmetic on integers of size
+limited only by your computer's memory. The library provides BigUnsigned and
+BigInteger classes that represent nonnegative integers and signed integers,
+respectively. Most of the C++ arithmetic operators are overloaded for these
+classes, so big-integer calculations are as easy as:
+
+ #include "BigIntegerLibrary.hh"
+
+ BigInteger a = 65536;
+ cout << (a * a * a * a * a * a * a * a);
+
+ (prints 340282366920938463463374607431768211456)
+
+The code in `sample.cc' demonstrates the most important features of the library.
+To get started quickly, read the code and explanations in that file and run it.
+If you want more detail or a feature not shown in `sample.cc', consult the
+consult the actual header and source files, which are thoroughly commented.
+
+This library emphasizes ease of use and clarity of implementation over speed;
+some users will prefer GMP (http://swox.com/gmp/), which is faster. The code is
+intended to be reasonably portable across computers and modern C++ compilers; in
+particular, it uses whatever word size the computer provides (32-bit, 64-bit, or
+otherwise).
+
+Compiling programs that use the library
+---------------------------------------
+The library consists of a folder full of C++ header files (`.hh') and source
+files (`.cc'). Your own programs should `#include' the necessary header files
+and link with the source files. A makefile that builds the sample program
+(`sample.cc') is included; you can adapt it to replace the sample with your own
+program.
+
+Alternatively, you can use your own build system or IDE. In that case, you must
+put the library header files where the compiler will find them and arrange to
+have your program linked with the library source files; otherwise, you will get
+errors about missing header files or "undefined references". To learn how to do
+this, consult the documentation for the build system or IDE; don't bother asking
+me. Adding all the library files to your project will work in many IDEs but may
+not be the most desirable approach.
+
+Resources
+---------
+The library's Web site (above) provides links to released versions, the current
+development version, and a mailing list for release announcements, questions,
+bug reports, and other discussion of the library. I would be delighted to hear
+from you if you like this library and/or find a good use for it.
+
+Bugs and enhancements
+---------------------
+The library has been tested by me and others but is by no means bug-free. If
+you find a bug, please report it, whether it comes in the form of compiling
+trouble, a mathematically inaccurate result, or a memory-management blooper
+(since I use Java, these are altogether too common in my C++). I generally fix
+all reported bugs. You are also welcome to request enhancements, but I am
+unlikely to do substantial amounts of work on enhancements at this point.
+
+Legal
+-----
+I, Matt McCutchen, the sole author of the original Big Integer Library, waive my
+copyright to it, placing it in the public domain. The library comes with
+absolutely no warranty.
+
+~~~~
diff --git a/bigint/run-testsuite b/bigint/run-testsuite
new file mode 100755
index 00000000..ff737291
--- /dev/null
+++ b/bigint/run-testsuite
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+bad=
+
+# If you encounter the following problem with Valgrind like I did:
+# https://bugzilla.redhat.com/show_bug.cgi?id=455644
+# you can pass the environment variable NO_VALGRIND=1 to run the testsuite
+# without it.
+if [ "$NO_VALGRIND" ]; then
+ cmd=(./testsuite)
+else
+ cmd=(valgrind --error-exitcode=1 --leak-check=full ./testsuite)
+fi
+
+set -o pipefail
+# Stdout goes directly to testsuite.out; stderr goes down the pipe.
+if ! "${cmd[@]}" 2>&1 >testsuite.out | tee testsuite.err; then
+ echo >&2 'Memory errors!'
+ bad=1
+fi
+
+if grep 'LEAK SUMMARY' testsuite.err >/dev/null; then
+ echo >&2 'Memory leaks!'
+ bad=1
+fi
+
+if ! diff -u testsuite.expected testsuite.out; then
+ echo >&2 'Output is incorrect!'
+ bad=1
+fi
+
+if [ $bad ]; then
+ echo >&2 'Test suite failed!'
+ exit 1
+else
+ echo 'Test suite passed.'
+fi
diff --git a/bigint/sample.cc b/bigint/sample.cc
new file mode 100644
index 00000000..62b41df3
--- /dev/null
+++ b/bigint/sample.cc
@@ -0,0 +1,125 @@
+// Sample program demonstrating the use of the Big Integer Library.
+
+// Standard libraries
+#include <string>
+#include <iostream>
+
+// `BigIntegerLibrary.hh' includes all of the library headers.
+#include "BigIntegerLibrary.hh"
+
+int main() {
+ /* The library throws `const char *' error messages when things go
+ * wrong. It's a good idea to catch them using a `try' block like this
+ * one. Your C++ compiler might need a command-line option to compile
+ * code that uses exceptions. */
+ try {
+ BigInteger a; // a is 0
+ int b = 535;
+
+ /* Any primitive integer can be converted implicitly to a
+ * BigInteger. */
+ a = b;
+
+ /* The reverse conversion requires a method call (implicit
+ * conversions were previously supported but caused trouble).
+ * If a were too big for an int, the library would throw an
+ * exception. */
+ b = a.toInt();
+
+ BigInteger c(a); // Copy a BigInteger.
+
+ // The int literal is converted to a BigInteger.
+ BigInteger d(-314159265);
+
+ /* This won't compile (at least on 32-bit machines) because the
+ * number is too big to be a primitive integer literal, and
+ * there's no such thing as a BigInteger literal. */
+ //BigInteger e(3141592653589793238462643383279);
+
+ // Instead you can convert the number from a string.
+ std::string s("3141592653589793238462643383279");
+ BigInteger f = stringToBigInteger(s);
+
+ // You can convert the other way too.
+ std::string s2 = bigIntegerToString(f);
+
+ // f is implicitly stringified and sent to std::cout.
+ std::cout << f << std::endl;
+
+ /* Let's do some math! The library overloads most of the
+ * mathematical operators (including assignment operators) to
+ * work on BigIntegers. There are also ``copy-less''
+ * operations; see `BigUnsigned.hh' for details. */
+
+ // Arithmetic operators
+ BigInteger g(314159), h(265);
+ std::cout << (g + h) << '\n'
+ << (g - h) << '\n'
+ << (g * h) << '\n'
+ << (g / h) << '\n'
+ << (g % h) << std::endl;
+
+ // Bitwise operators
+ BigUnsigned i(0xFF0000FF), j(0x0000FFFF);
+ // The library's << operator recognizes base flags.
+ std::cout.flags(std::ios::hex | std::ios::showbase);
+ std::cout << (i & j) << '\n'
+ << (i | j) << '\n'
+ << (i ^ j) << '\n'
+ // Shift distances are ordinary unsigned ints.
+ << (j << 21) << '\n'
+ << (j >> 10) << '\n';
+ std::cout.flags(std::ios::dec);
+
+ // Let's do some heavy lifting and calculate powers of 314.
+ int maxPower = 10;
+ BigUnsigned x(1), big314(314);
+ for (int power = 0; power <= maxPower; power++) {
+ std::cout << "314^" << power << " = " << x << std::endl;
+ x *= big314; // A BigInteger assignment operator
+ }
+
+ // Some big-integer algorithms (albeit on small integers).
+ std::cout << gcd(BigUnsigned(60), 72) << '\n'
+ << modinv(BigUnsigned(7), 11) << '\n'
+ << modexp(BigUnsigned(314), 159, 2653) << std::endl;
+
+ // Add your own code here to experiment with the library.
+ } catch(char const* err) {
+ std::cout << "The library threw an exception:\n"
+ << err << std::endl;
+ }
+
+ return 0;
+}
+
+/*
+The original sample program produces this output:
+
+3141592653589793238462643383279
+314424
+313894
+83252135
+1185
+134
+0xFF
+0xFF00FFFF
+0xFF00FF00
+0x1FFFE00000
+0x3F
+314^0 = 1
+314^1 = 314
+314^2 = 98596
+314^3 = 30959144
+314^4 = 9721171216
+314^5 = 3052447761824
+314^6 = 958468597212736
+314^7 = 300959139524799104
+314^8 = 94501169810786918656
+314^9 = 29673367320587092457984
+314^10 = 9317437338664347031806976
+12
+8
+1931
+
+*/
diff --git a/bigint/testsuite.cc b/bigint/testsuite.cc
new file mode 100644
index 00000000..7cb9768e
--- /dev/null
+++ b/bigint/testsuite.cc
@@ -0,0 +1,326 @@
+/* Test suite for the library. First, it ``tests'' that all the constructs it
+ * uses compile successfully. Then, its output to stdout is compared to the
+ * expected output automatically extracted from slash-slash comments below.
+ *
+ * NOTE: For now, the test suite expects a 32-bit system. On others, some tests
+ * may fail, and it may be ineffective at catching bugs. TODO: Remedy this. */
+
+#include "BigIntegerLibrary.hh"
+
+#include <string>
+#include <iostream>
+using namespace std;
+
+// Evaluate expr and print the result or "error" as appropriate.
+#define TEST(expr) do {\
+ cout << "Line " << __LINE__ << ": ";\
+ try {\
+ cout << (expr);\
+ } catch (const char *err) {\
+ cout << "error";\
+ }\
+ cout << endl;\
+} while (0)
+
+const BigUnsigned &check(const BigUnsigned &x) {
+ unsigned int l = x.getLength();
+ if (l != 0 && x.getBlock(l-1) == 0)
+ cout << "check: Unzapped number!" << endl;
+ if (l > x.getCapacity())
+ cout << "check: Capacity inconsistent with length!" << endl;
+ return x;
+}
+
+const BigInteger &check(const BigInteger &x) {
+ if (x.getSign() == 0 && !x.getMagnitude().isZero())
+ cout << "check: Sign should not be zero!" << endl;
+ if (x.getSign() != 0 && x.getMagnitude().isZero())
+ cout << "check: Sign should be zero!" << endl;
+ check(x.getMagnitude());
+ return x;
+}
+
+short pathologicalShort = ~((unsigned short)(~0) >> 1);
+int pathologicalInt = ~((unsigned int)(~0) >> 1);
+long pathologicalLong = ~((unsigned long)(~0) >> 1);
+
+int main() {
+
+try {
+
+BigUnsigned z(0), one(1), ten(10);
+TEST(z); //0
+TEST(1); //1
+TEST(10); //10
+
+// TODO: Comprehensively test the general and special cases of each function.
+
+// === Default constructors ===
+
+TEST(check(BigUnsigned())); //0
+TEST(check(BigInteger())); //0
+
+// === Block-array constructors ===
+
+BigUnsigned::Blk myBlocks[3];
+myBlocks[0] = 3;
+myBlocks[1] = 4;
+myBlocks[2] = 0;
+BigUnsigned bu(myBlocks, 3);
+TEST(check(bu)); //17179869187
+TEST(check(BigInteger(myBlocks, 3))); //17179869187
+TEST(check(BigInteger(bu ))); //17179869187
+
+// For nonzero magnitude, reject zero and invalid signs.
+TEST(check(BigInteger(myBlocks, 3, BigInteger::positive))); //17179869187
+TEST(check(BigInteger(myBlocks, 3, BigInteger::negative))); //-17179869187
+TEST(check(BigInteger(myBlocks, 3, BigInteger::zero ))); //error
+TEST(check(BigInteger(bu, BigInteger::positive))); //17179869187
+TEST(check(BigInteger(bu, BigInteger::negative))); //-17179869187
+TEST(check(BigInteger(bu, BigInteger::zero ))); //error
+
+// For zero magnitude, force the sign to zero without error.
+BigUnsigned::Blk myZeroBlocks[1];
+myZeroBlocks[0] = 0;
+TEST(check(BigInteger(myZeroBlocks, 1, BigInteger::positive))); //0
+TEST(check(BigInteger(myZeroBlocks, 1, BigInteger::negative))); //0
+TEST(check(BigInteger(myZeroBlocks, 1, BigInteger::zero ))); //0
+
+// === BigUnsigned conversion limits ===
+
+TEST(BigUnsigned(0).toUnsignedLong()); //0
+TEST(BigUnsigned(4294967295U).toUnsignedLong()); //4294967295
+TEST(stringToBigUnsigned("4294967296").toUnsignedLong()); //error
+
+TEST(BigUnsigned(0).toLong()); //0
+TEST(BigUnsigned(2147483647).toLong()); //2147483647
+TEST(BigUnsigned(2147483648U).toLong()); //error
+
+// int is the same as long on a 32-bit system
+TEST(BigUnsigned(0).toUnsignedInt()); //0
+TEST(BigUnsigned(4294967295U).toUnsignedInt()); //4294967295
+TEST(stringToBigUnsigned("4294967296").toUnsignedInt()); //error
+
+TEST(BigUnsigned(0).toInt()); //0
+TEST(BigUnsigned(2147483647).toInt()); //2147483647
+TEST(BigUnsigned(2147483648U).toInt()); //error
+
+TEST(BigUnsigned(0).toUnsignedShort()); //0
+TEST(BigUnsigned(65535).toUnsignedShort()); //65535
+TEST(BigUnsigned(65536).toUnsignedShort()); //error
+
+TEST(BigUnsigned(0).toShort()); //0
+TEST(BigUnsigned(32767).toShort()); //32767
+TEST(BigUnsigned(32768).toShort()); //error
+
+// === BigInteger conversion limits ===
+
+TEST(BigInteger(-1).toUnsignedLong()); //error
+TEST(BigInteger(0).toUnsignedLong()); //0
+TEST(BigInteger(4294967295U).toUnsignedLong()); //4294967295
+TEST(stringToBigInteger("4294967296").toUnsignedLong()); //error
+
+TEST(stringToBigInteger("-2147483649").toLong()); //error
+TEST(stringToBigInteger("-2147483648").toLong()); //-2147483648
+TEST(BigInteger(-2147483647).toLong()); //-2147483647
+TEST(BigInteger(0).toLong()); //0
+TEST(BigInteger(2147483647).toLong()); //2147483647
+TEST(BigInteger(2147483648U).toLong()); //error
+
+// int is the same as long on a 32-bit system
+TEST(BigInteger(-1).toUnsignedInt()); //error
+TEST(BigInteger(0).toUnsignedInt()); //0
+TEST(BigInteger(4294967295U).toUnsignedInt()); //4294967295
+TEST(stringToBigInteger("4294967296").toUnsignedInt()); //error
+
+TEST(stringToBigInteger("-2147483649").toInt()); //error
+TEST(stringToBigInteger("-2147483648").toInt()); //-2147483648
+TEST(BigInteger(-2147483647).toInt()); //-2147483647
+TEST(BigInteger(0).toInt()); //0
+TEST(BigInteger(2147483647).toInt()); //2147483647
+TEST(BigInteger(2147483648U).toInt()); //error
+
+TEST(BigInteger(-1).toUnsignedShort()); //error
+TEST(BigInteger(0).toUnsignedShort()); //0
+TEST(BigInteger(65535).toUnsignedShort()); //65535
+TEST(BigInteger(65536).toUnsignedShort()); //error
+
+TEST(BigInteger(-32769).toShort()); //error
+TEST(BigInteger(-32768).toShort()); //-32768
+TEST(BigInteger(-32767).toShort()); //-32767
+TEST(BigInteger(0).toShort()); //0
+TEST(BigInteger(32767).toShort()); //32767
+TEST(BigInteger(32768).toShort()); //error
+
+// === Negative BigUnsigneds ===
+
+// ...during construction
+TEST(BigUnsigned(short(-1))); //error
+TEST(BigUnsigned(pathologicalShort)); //error
+TEST(BigUnsigned(-1)); //error
+TEST(BigUnsigned(pathologicalInt)); //error
+TEST(BigUnsigned(long(-1))); //error
+TEST(BigUnsigned(pathologicalLong)); //error
+
+// ...during subtraction
+TEST(BigUnsigned(5) - BigUnsigned(6)); //error
+TEST(stringToBigUnsigned("314159265358979323") - stringToBigUnsigned("314159265358979324")); //error
+TEST(check(BigUnsigned(5) - BigUnsigned(5))); //0
+TEST(check(stringToBigUnsigned("314159265358979323") - stringToBigUnsigned("314159265358979323"))); //0
+TEST(check(stringToBigUnsigned("4294967296") - BigUnsigned(1))); //4294967295
+
+// === BigUnsigned addition ===
+
+TEST(check(BigUnsigned(0) + 0)); //0
+TEST(check(BigUnsigned(0) + 1)); //1
+// Ordinary carry
+TEST(check(stringToBigUnsigned("8589934591" /* 2^33 - 1*/)
+ + stringToBigUnsigned("4294967298" /* 2^32 + 2 */))); //12884901889
+// Creation of a new block
+TEST(check(BigUnsigned(0xFFFFFFFFU) + 1)); //4294967296
+
+// === BigUnsigned subtraction ===
+
+TEST(check(BigUnsigned(1) - 0)); //1
+TEST(check(BigUnsigned(1) - 1)); //0
+TEST(check(BigUnsigned(2) - 1)); //1
+// Ordinary borrow
+TEST(check(stringToBigUnsigned("12884901889")
+ - stringToBigUnsigned("4294967298"))); //8589934591
+// Borrow that removes a block
+TEST(check(stringToBigUnsigned("4294967296") - 1)); //4294967295
+
+// === BigUnsigned multiplication and division ===
+
+BigUnsigned a = check(BigUnsigned(314159265) * 358979323);
+TEST(a); //112776680263877595
+TEST(a / 123); //916883579381118
+TEST(a % 123); //81
+
+TEST(BigUnsigned(5) / 0); //error
+
+// === Block accessors ===
+
+BigUnsigned b;
+TEST(b); //0
+TEST(b.getBlock(0)); //0
+b.setBlock(1, 314);
+// Did b grow properly? And did we zero intermediate blocks?
+TEST(check(b)); //1348619730944
+TEST(b.getLength()); //2
+TEST(b.getBlock(0)); //0
+TEST(b.getBlock(1)); //314
+// Did b shrink properly?
+b.setBlock(1, 0);
+TEST(check(b)); //0
+
+BigUnsigned bb(314);
+bb.setBlock(1, 159);
+// Make sure we used allocateAndCopy, not allocate
+TEST(bb.getBlock(0)); //314
+TEST(bb.getBlock(1)); //159
+// Blocks beyond the number should be zero regardless of whether they are
+// within the capacity.
+bb.add(1, 2);
+TEST(bb.getBlock(0)); //3
+TEST(bb.getBlock(1)); //0
+TEST(bb.getBlock(2)); //0
+TEST(bb.getBlock(314159)); //0
+
+// === Bit accessors ===
+
+TEST(BigUnsigned(0).bitLength()); //0
+TEST(BigUnsigned(1).bitLength()); //1
+TEST(BigUnsigned(4095).bitLength()); //12
+TEST(BigUnsigned(4096).bitLength()); //13
+// 5 billion is between 2^32 (about 4 billion) and 2^33 (about 8 billion).
+TEST(stringToBigUnsigned("5000000000").bitLength()); //33
+
+// 25 is binary 11001.
+BigUnsigned bbb(25);
+TEST(bbb.getBit(4)); //1
+TEST(bbb.getBit(3)); //1
+TEST(bbb.getBit(2)); //0
+TEST(bbb.getBit(1)); //0
+TEST(bbb.getBit(0)); //1
+TEST(bbb.bitLength()); //5
+// Effectively add 2^32.
+bbb.setBit(32, true);
+TEST(bbb); //4294967321
+bbb.setBit(31, true);
+bbb.setBit(32, false);
+TEST(check(bbb)); //2147483673
+
+// === Combining BigUnsigned, BigInteger, and primitive integers ===
+
+BigUnsigned p1 = BigUnsigned(3) * 5;
+TEST(p1); //15
+/* In this case, we would like g++ to implicitly promote the BigUnsigned to a
+ * BigInteger, but it seems to prefer converting the -5 to a BigUnsigned, which
+ * causes an error. If I take out constructors for BigUnsigned from signed
+ * primitive integers, the BigUnsigned(3) becomes ambiguous, and if I take out
+ * all the constructors but BigUnsigned(unsigned long), g++ uses that
+ * constructor and gets a wrong (positive) answer. Thus, I think we'll just
+ * have to live with this cast. */
+BigInteger p2 = BigInteger(BigUnsigned(3)) * -5;
+TEST(p2); //-15
+
+// === Test some previous bugs ===
+
+{
+ /* Test that BigInteger division sets the sign to zero.
+ * Bug reported by David Allen. */
+ BigInteger num(3), denom(5), quotient;
+ num.divideWithRemainder(denom, quotient);
+ check(quotient);
+ num = 5;
+ num.divideWithRemainder(denom, quotient);
+ check(num);
+}
+
+{
+ /* Test that BigInteger subtraction sets the sign properly.
+ * Bug reported by Samuel Larkin. */
+ BigInteger zero(0), three(3), ans;
+ ans = zero - three;
+ TEST(check(ans).getSign()); //-1
+}
+
+{
+ /* Test that BigInteger multiplication shifts bits properly on systems
+ * where long is bigger than int. (Obviously, this would only catch the
+ * bug when run on such a system.)
+ * Bug reported by Mohand Mezmaz. */
+ BigInteger f=4; f*=3;
+ TEST(check(f)); //12
+}
+
+{
+ /* Test that bitwise XOR allocates the larger length.
+ * Bug reported by Sriram Sankararaman. */
+ BigUnsigned a(0), b(3), ans;
+ ans = a ^ b;
+ TEST(ans); //3
+}
+
+{
+ /* Test that an aliased multiplication works.
+ * Bug reported by Boris Dessy. */
+ BigInteger num(5);
+ num *= num;
+ TEST(check(num)); //25
+}
+
+{
+ /* Test that BigUnsignedInABase(std::string) constructor rejects digits
+ * too big for the specified base.
+ * Bug reported by Niakam Kazemi. */
+ TEST(BigUnsignedInABase("f", 10)); //error
+}
+
+} catch (const char *err) {
+ cout << "UNCAUGHT ERROR: " << err << endl;
+}
+
+return 0;
+}
diff --git a/frontends/ast/Makefile.inc b/frontends/ast/Makefile.inc
new file mode 100644
index 00000000..993ead92
--- /dev/null
+++ b/frontends/ast/Makefile.inc
@@ -0,0 +1,5 @@
+
+OBJS += frontends/ast/ast.o
+OBJS += frontends/ast/simplify.o
+OBJS += frontends/ast/genrtlil.o
+
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
new file mode 100644
index 00000000..160e9c42
--- /dev/null
+++ b/frontends/ast/ast.cc
@@ -0,0 +1,859 @@
+/*
+ * 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 is the AST frontend library.
+ *
+ * The AST frontend library is not a frontend on it's own but provides a
+ * generic abstract syntax tree (AST) abstraction for HDL code and can be
+ * used by HDL frontends. See "ast.h" for an overview of the API and the
+ * Verilog frontend for an usage example.
+ *
+ */
+
+#include "kernel/log.h"
+#include "kernel/sha1.h"
+#include "ast.h"
+
+#include <sstream>
+#include <stdarg.h>
+#include <assert.h>
+
+using namespace AST;
+using namespace AST_INTERNAL;
+
+// instanciate global variables (public API)
+namespace AST {
+ std::string current_filename;
+ void (*set_line_num)(int) = NULL;
+ int (*get_line_num)() = NULL;
+}
+
+// instanciate global variables (private API)
+namespace AST_INTERNAL {
+ bool flag_dump_ast, flag_dump_ast_diff, flag_dump_vlog, flag_nolatches, flag_nomem2reg;
+ 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;
+ AstNode *current_top_block, *current_block, *current_block_child;
+ AstModule *current_module;
+}
+
+// convert node types to string
+std::string AST::type2str(AstNodeType type)
+{
+ switch (type)
+ {
+#define X(_item) case _item: return #_item;
+ X(AST_NONE)
+ X(AST_DESIGN)
+ X(AST_MODULE)
+ X(AST_TASK)
+ X(AST_FUNCTION)
+ X(AST_WIRE)
+ X(AST_MEMORY)
+ X(AST_AUTOWIRE)
+ X(AST_PARAMETER)
+ X(AST_LOCALPARAM)
+ X(AST_PARASET)
+ X(AST_ARGUMENT)
+ X(AST_RANGE)
+ X(AST_CONSTANT)
+ X(AST_CELLTYPE)
+ X(AST_IDENTIFIER)
+ X(AST_FCALL)
+ X(AST_TO_SIGNED)
+ X(AST_TO_UNSIGNED)
+ X(AST_CONCAT)
+ X(AST_REPLICATE)
+ X(AST_BIT_NOT)
+ X(AST_BIT_AND)
+ X(AST_BIT_OR)
+ X(AST_BIT_XOR)
+ X(AST_BIT_XNOR)
+ X(AST_REDUCE_AND)
+ X(AST_REDUCE_OR)
+ X(AST_REDUCE_XOR)
+ X(AST_REDUCE_XNOR)
+ X(AST_REDUCE_BOOL)
+ X(AST_SHIFT_LEFT)
+ X(AST_SHIFT_RIGHT)
+ X(AST_SHIFT_SLEFT)
+ X(AST_SHIFT_SRIGHT)
+ X(AST_LT)
+ X(AST_LE)
+ X(AST_EQ)
+ X(AST_NE)
+ X(AST_GE)
+ X(AST_GT)
+ X(AST_ADD)
+ X(AST_SUB)
+ X(AST_MUL)
+ X(AST_DIV)
+ X(AST_MOD)
+ X(AST_POW)
+ X(AST_POS)
+ X(AST_NEG)
+ X(AST_LOGIC_AND)
+ X(AST_LOGIC_OR)
+ X(AST_LOGIC_NOT)
+ X(AST_TERNARY)
+ X(AST_MEMRD)
+ X(AST_MEMWR)
+ X(AST_TCALL)
+ X(AST_ASSIGN)
+ X(AST_CELL)
+ X(AST_PRIMITIVE)
+ X(AST_ALWAYS)
+ X(AST_BLOCK)
+ X(AST_ASSIGN_EQ)
+ X(AST_ASSIGN_LE)
+ X(AST_CASE)
+ X(AST_COND)
+ X(AST_DEFAULT)
+ X(AST_FOR)
+ X(AST_GENVAR)
+ X(AST_GENFOR)
+ X(AST_GENIF)
+ X(AST_GENBLOCK)
+ X(AST_POSEDGE)
+ X(AST_NEGEDGE)
+ X(AST_EDGE)
+#undef X
+ default:
+ assert(!"Missing enum to string def in AST::type2str().");
+ abort();
+ }
+}
+
+// create new node (AstNode constructor)
+// (the optional child arguments make it easier to create AST trees)
+AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2)
+{
+ this->type = type;
+ filename = current_filename;
+ linenum = get_line_num();
+ is_input = false;
+ is_output = false;
+ is_reg = false;
+ is_signed = false;
+ range_valid = false;
+ port_id = 0;
+ range_left = -1;
+ range_right = 0;
+ integer = 0;
+ id2ast = NULL;
+
+ if (child1)
+ children.push_back(child1);
+ if (child2)
+ children.push_back(child2);
+}
+
+// create a (deep recursive) copy of a node
+AstNode *AstNode::clone()
+{
+ AstNode *that = new AstNode;
+ *that = *this;
+ for (auto &it : that->children)
+ it = it->clone();
+ for (auto &it : that->attributes)
+ it.second = it.second->clone();
+ return that;
+}
+
+// create a (deep recursive) copy of a node use 'other' as target root node
+void AstNode::cloneInto(AstNode *other)
+{
+ AstNode *tmp = clone();
+ other->delete_children();
+ *other = *tmp;
+ tmp->children.clear();
+ tmp->attributes.clear();
+ delete tmp;
+}
+
+// delete all children in this node
+void AstNode::delete_children()
+{
+ for (auto &it : children)
+ delete it;
+ children.clear();
+
+ for (auto &it : attributes)
+ delete it.second;
+ attributes.clear();
+}
+
+// AstNode destructor
+AstNode::~AstNode()
+{
+ delete_children();
+}
+
+// create a nice text representation of the node
+// (traverse tree by recursion, use 'other' pointer for diffing two AST trees)
+void AstNode::dumpAst(FILE *f, std::string indent, AstNode *other)
+{
+ if (f == NULL) {
+ for (auto f : log_files)
+ dumpAst(f, indent, other);
+ return;
+ }
+ if (other != NULL) {
+ if (type != other->type)
+ goto found_diff_to_other;
+ if (children.size() != other->children.size())
+ goto found_diff_to_other;
+ if (str != other->str)
+ goto found_diff_to_other;
+ if (bits != other->bits)
+ goto found_diff_to_other;
+ if (is_input != other->is_input)
+ goto found_diff_to_other;
+ if (is_output != other->is_output)
+ goto found_diff_to_other;
+ if (is_reg != other->is_reg)
+ goto found_diff_to_other;
+ if (is_signed != other->is_signed)
+ goto found_diff_to_other;
+ if (range_valid != other->range_valid)
+ goto found_diff_to_other;
+ if (port_id != other->port_id)
+ goto found_diff_to_other;
+ if (range_left != other->range_left)
+ goto found_diff_to_other;
+ if (range_right != other->range_right)
+ goto found_diff_to_other;
+ if (integer != other->integer)
+ goto found_diff_to_other;
+ if (0) {
+ found_diff_to_other:
+ other->dumpAst(f, indent + "- ");
+ this->dumpAst(f, indent + "+ ");
+ return;
+ }
+ }
+
+ std::string type_name = type2str(type);
+ fprintf(f, "%s%s <%s:%d>", indent.c_str(), type_name.c_str(), filename.c_str(), linenum);
+ if (!str.empty())
+ fprintf(f, " str='%s'", str.c_str());
+ if (!bits.empty()) {
+ fprintf(f, " bits='");
+ for (size_t i = bits.size(); i > 0; i--)
+ fprintf(f, "%c", bits[i-1] == RTLIL::S0 ? '0' :
+ bits[i-1] == RTLIL::S1 ? '1' :
+ bits[i-1] == RTLIL::Sx ? 'x' :
+ bits[i-1] == RTLIL::Sz ? 'z' : '?');
+ fprintf(f, "'(%zd)", bits.size());
+ }
+ if (is_input)
+ fprintf(f, " input");
+ if (is_output)
+ fprintf(f, " output");
+ if (is_reg)
+ fprintf(f, " reg");
+ if (is_signed)
+ fprintf(f, " signed");
+ 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 ? "" : "!");
+ if (integer != 0)
+ fprintf(f, " int=%u", (int)integer);
+ fprintf(f, "\n");
+
+ for (size_t i = 0; i < children.size(); i++)
+ children[i]->dumpAst(f, indent + " ", other ? other->children[i] : NULL);
+}
+
+// helper function for AstNode::dumpVlog()
+static std::string id2vl(std::string txt)
+{
+ if (txt.size() > 1 && txt[0] == '\\')
+ txt = txt.substr(1);
+ for (size_t i = 0; i < txt.size(); i++) {
+ if ('A' <= txt[i] && txt[i] <= 'Z') continue;
+ if ('a' <= txt[i] && txt[i] <= 'z') continue;
+ if ('0' <= txt[i] && txt[i] <= '9') continue;
+ if (txt[i] == '_') continue;
+ txt = "\\" + txt + " ";
+ break;
+ }
+ return txt;
+}
+
+// dump AST node as verilog pseudo-code
+void AstNode::dumpVlog(FILE *f, std::string indent)
+{
+ bool first = true;
+ std::string txt;
+ std::vector<AstNode*> rem_children1, rem_children2;
+
+ if (f == NULL) {
+ for (auto f : log_files)
+ dumpVlog(f, indent);
+ return;
+ }
+
+ switch (type)
+ {
+ case AST_MODULE:
+ fprintf(f, "%s" "module %s(", indent.c_str(), id2vl(str).c_str());
+ for (auto child : children)
+ if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
+ fprintf(f, "%s%s", first ? "" : ", ", id2vl(child->str).c_str());
+ first = false;
+ }
+ fprintf(f, ");\n");
+
+ for (auto child : children)
+ if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
+ child->dumpVlog(f, indent + " ");
+ else
+ rem_children1.push_back(child);
+
+ for (auto child : rem_children1)
+ if (child->type == AST_WIRE || child->type == AST_AUTOWIRE || child->type == AST_MEMORY)
+ child->dumpVlog(f, indent + " ");
+ else
+ rem_children2.push_back(child);
+ rem_children1.clear();
+
+ for (auto child : rem_children2)
+ if (child->type == AST_TASK || child->type == AST_FUNCTION)
+ child->dumpVlog(f, indent + " ");
+ else
+ rem_children1.push_back(child);
+ rem_children2.clear();
+
+ for (auto child : rem_children1)
+ child->dumpVlog(f, indent + " ");
+ rem_children1.clear();
+
+ fprintf(f, "%s" "endmodule\n", indent.c_str());
+ break;
+
+ case AST_WIRE:
+ if (is_input && is_output)
+ fprintf(f, "%s" "inout", indent.c_str());
+ else if (is_input)
+ fprintf(f, "%s" "input", indent.c_str());
+ else if (is_output)
+ fprintf(f, "%s" "output", indent.c_str());
+ else if (!is_reg)
+ fprintf(f, "%s" "wire", indent.c_str());
+ if (is_reg)
+ fprintf(f, "%s" "reg", (is_input || is_output) ? " " : indent.c_str());
+ if (is_signed)
+ fprintf(f, " signed");
+ for (auto child : children) {
+ fprintf(f, " ");
+ child->dumpVlog(f, "");
+ }
+ fprintf(f, " %s", id2vl(str).c_str());
+ fprintf(f, ";\n");
+ break;
+
+ case AST_MEMORY:
+ fprintf(f, "%s" "memory", indent.c_str());
+ if (is_signed)
+ fprintf(f, " signed");
+ for (auto child : children) {
+ fprintf(f, " ");
+ child->dumpVlog(f, "");
+ if (first)
+ fprintf(f, " %s", id2vl(str).c_str());
+ first = false;
+ }
+ fprintf(f, ";\n");
+ break;
+
+ case AST_RANGE:
+ if (range_valid)
+ fprintf(f, "[%d:%d]", range_left, range_right);
+ else {
+ for (auto child : children) {
+ fprintf(f, "%c", first ? '[' : ':');
+ child->dumpVlog(f, "");
+ first = false;
+ }
+ fprintf(f, "]");
+ }
+ break;
+
+ case AST_ALWAYS:
+ fprintf(f, "%s" "always @(", indent.c_str());
+ for (auto child : children) {
+ if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
+ continue;
+ if (!first)
+ fprintf(f, ", ");
+ child->dumpVlog(f, "");
+ first = false;
+ }
+ fprintf(f, ")\n");
+ for (auto child : children) {
+ if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
+ child->dumpVlog(f, indent + " ");
+ }
+ break;
+
+ case AST_POSEDGE:
+ case AST_NEGEDGE:
+ case AST_EDGE:
+ if (type == AST_POSEDGE)
+ fprintf(f, "posedge ");
+ if (type == AST_NEGEDGE)
+ fprintf(f, "negedge ");
+ for (auto child : children)
+ child->dumpVlog(f, "");
+ break;
+
+ case AST_IDENTIFIER:
+ fprintf(f, "%s", id2vl(str).c_str());
+ for (auto child : children)
+ child->dumpVlog(f, "");
+ break;
+
+ case AST_CONSTANT:
+ if (!str.empty())
+ fprintf(f, "\"%s\"", str.c_str());
+ else if (bits.size() == 32)
+ fprintf(f, "%d", RTLIL::Const(bits).as_int());
+ else
+ fprintf(f, "%zd'b %s", bits.size(), RTLIL::Const(bits).as_string().c_str());
+ break;
+
+ case AST_BLOCK:
+ if (children.size() == 1) {
+ children[0]->dumpVlog(f, indent);
+ } else {
+ fprintf(f, "%s" "begin\n", indent.c_str());
+ for (auto child : children)
+ child->dumpVlog(f, indent + " ");
+ fprintf(f, "%s" "end\n", indent.c_str());
+ }
+ break;
+
+ case AST_CASE:
+ fprintf(f, "%s" "case (", indent.c_str());
+ children[0]->dumpVlog(f, "");
+ fprintf(f, ")\n");
+ for (size_t i = 1; i < children.size(); i++) {
+ AstNode *child = children[i];
+ child->dumpVlog(f, indent + " ");
+ }
+ fprintf(f, "%s" "endcase\n", indent.c_str());
+ break;
+
+ case AST_COND:
+ for (auto child : children) {
+ if (child->type == AST_BLOCK) {
+ fprintf(f, ":\n");
+ child->dumpVlog(f, indent + " ");
+ first = true;
+ } else {
+ fprintf(f, "%s", first ? indent.c_str() : ", ");
+ if (child->type == AST_DEFAULT)
+ fprintf(f, "default");
+ else
+ child->dumpVlog(f, "");
+ first = false;
+ }
+ }
+ break;
+
+ case AST_ASSIGN_EQ:
+ case AST_ASSIGN_LE:
+ fprintf(f, "%s", indent.c_str());
+ children[0]->dumpVlog(f, "");
+ fprintf(f, " %s ", type == AST_ASSIGN_EQ ? "=" : "<=");
+ children[1]->dumpVlog(f, "");
+ fprintf(f, ";\n");
+ break;
+
+ case AST_CONCAT:
+ fprintf(f, "{");
+ for (auto child : children) {
+ if (!first)
+ fprintf(f, ", ");
+ child->dumpVlog(f, "");
+ first = false;
+ }
+ fprintf(f, "}");
+ break;
+
+ case AST_REPLICATE:
+ fprintf(f, "{");
+ children[0]->dumpVlog(f, "");
+ fprintf(f, "{");
+ children[1]->dumpVlog(f, "");
+ fprintf(f, "}}");
+ break;
+
+ if (0) { case AST_BIT_NOT: txt = "~"; }
+ if (0) { case AST_REDUCE_AND: txt = "&"; }
+ if (0) { case AST_REDUCE_OR: txt = "|"; }
+ if (0) { case AST_REDUCE_XOR: txt = "^"; }
+ if (0) { case AST_REDUCE_XNOR: txt = "~^"; }
+ if (0) { case AST_REDUCE_BOOL: txt = "|"; }
+ if (0) { case AST_POS: txt = "+"; }
+ if (0) { case AST_NEG: txt = "-"; }
+ if (0) { case AST_LOGIC_NOT: txt = "!"; }
+ fprintf(f, "%s(", txt.c_str());
+ children[0]->dumpVlog(f, "");
+ fprintf(f, ")");
+ break;
+
+ if (0) { case AST_BIT_AND: txt = "&"; }
+ if (0) { case AST_BIT_OR: txt = "|"; }
+ if (0) { case AST_BIT_XOR: txt = "^"; }
+ if (0) { case AST_BIT_XNOR: txt = "~^"; }
+ if (0) { case AST_SHIFT_LEFT: txt = "<<"; }
+ if (0) { case AST_SHIFT_RIGHT: txt = ">>"; }
+ if (0) { case AST_SHIFT_SLEFT: txt = "<<<"; }
+ if (0) { case AST_SHIFT_SRIGHT: txt = ">>>"; }
+ if (0) { case AST_LT: txt = "<"; }
+ if (0) { case AST_LE: txt = "<="; }
+ if (0) { case AST_EQ: txt = "=="; }
+ if (0) { case AST_NE: txt = "!="; }
+ if (0) { case AST_GE: txt = ">="; }
+ if (0) { case AST_GT: txt = ">"; }
+ if (0) { case AST_ADD: txt = "+"; }
+ if (0) { case AST_SUB: txt = "-"; }
+ if (0) { case AST_MUL: txt = "*"; }
+ if (0) { case AST_DIV: txt = "/"; }
+ if (0) { case AST_MOD: txt = "%"; }
+ if (0) { case AST_POW: txt = "**"; }
+ if (0) { case AST_LOGIC_AND: txt = "&&"; }
+ if (0) { case AST_LOGIC_OR: txt = "||"; }
+ fprintf(f, "(");
+ children[0]->dumpVlog(f, "");
+ fprintf(f, ")%s(", txt.c_str());
+ children[1]->dumpVlog(f, "");
+ fprintf(f, ")");
+ break;
+
+ case AST_TERNARY:
+ fprintf(f, "(");
+ children[0]->dumpVlog(f, "");
+ fprintf(f, ") ? (");
+ children[1]->dumpVlog(f, "");
+ fprintf(f, ") : (");
+ children[2]->dumpVlog(f, "");
+ fprintf(f, ")");
+ break;
+
+ default:
+ std::string type_name = type2str(type);
+ fprintf(f, "%s" "/** %s **/%s", indent.c_str(), type_name.c_str(), indent.empty() ? "" : "\n");
+ // dumpAst(f, indent, NULL);
+ }
+}
+
+// check if two AST nodes are identical
+bool AstNode::operator==(const AstNode &other) const
+{
+ if (type != other.type)
+ return false;
+ if (children.size() != other.children.size())
+ return false;
+ if (str != other.str)
+ return false;
+ if (bits != other.bits)
+ return false;
+ if (is_input != other.is_input)
+ return false;
+ if (is_output != other.is_output)
+ return false;
+ if (is_reg != other.is_reg)
+ return false;
+ if (is_signed != other.is_signed)
+ return false;
+ if (range_valid != other.range_valid)
+ return false;
+ if (port_id != other.port_id)
+ return false;
+ if (range_left != other.range_left)
+ return false;
+ if (range_right != other.range_right)
+ return false;
+ if (integer != other.integer)
+ return false;
+ for (size_t i = 0; i < children.size(); i++)
+ if (*children[i] != *other.children[i])
+ return false;
+ return true;
+}
+
+// check if two AST nodes are not identical
+bool AstNode::operator!=(const AstNode &other) const
+{
+ return !(*this == other);
+}
+
+// check if this AST contains the given node
+bool AstNode::contains(const AstNode *other) const
+{
+ if (this == other)
+ return true;
+ for (auto child : children)
+ if (child->contains(other))
+ return true;
+ return false;
+}
+
+// create an AST node for a constant (using a 32 bit int as value)
+AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
+{
+ AstNode *node = new AstNode(AST_CONSTANT);
+ node->integer = v;
+ node->is_signed = is_signed;
+ for (int i = 0; i < width; i++) {
+ node->bits.push_back((v & 1) ? RTLIL::S1 : RTLIL::S0);
+ v = v >> 1;
+ }
+ node->range_valid = true;
+ node->range_left = width-1;
+ node->range_right = 0;
+ return node;
+}
+
+// create an AST node for a constant (using a bit vector as value)
+AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed)
+{
+ AstNode *node = new AstNode(AST_CONSTANT);
+ node->is_signed = is_signed;
+ node->bits = v;
+ for (size_t i = 0; i < 32; i++) {
+ if (i < node->bits.size())
+ node->integer |= (node->bits[i] == RTLIL::S1) << i;
+ else if (is_signed)
+ node->integer |= (node->bits.back() == RTLIL::S1) << i;
+ }
+ node->range_valid = true;
+ node->range_left = node->bits.size();
+ node->range_right = 0;
+ return node;
+}
+
+// create a new AstModule from an AST_MODULE AST node
+static AstModule* process_module(AstNode *ast)
+{
+ assert(ast->type == AST_MODULE);
+ log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str());
+
+ current_ast_mod = ast;
+ AstNode *ast_before_simplify = ast->clone();
+
+ while (ast->simplify(false, false, false, 0)) { }
+
+ if (flag_dump_ast) {
+ log("Dumping verilog AST (as requested by %s option):\n", flag_dump_ast_diff ? "dump_ast_diff" : "dump_ast");
+ ast->dumpAst(NULL, " ", flag_dump_ast_diff ? ast_before_simplify : 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");
+ }
+
+ current_module = new AstModule;
+ current_module->ast = NULL;
+ current_module->name = ast->str;
+ current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum);
+ 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].str = attr.second->str;
+ current_module->attributes[attr.first].bits = attr.second->bits;
+ }
+ 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->genRTLIL();
+ }
+
+ current_module->ast = ast_before_simplify;
+ current_module->nolatches = flag_nolatches;
+ current_module->nomem2reg = flag_nomem2reg;
+ 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_ast, bool dump_ast_diff, bool dump_vlog, bool nolatches, bool nomem2reg)
+{
+ current_ast = ast;
+ flag_dump_ast = dump_ast;
+ flag_dump_ast_diff = dump_ast_diff;
+ flag_dump_vlog = dump_vlog;
+ flag_nolatches = nolatches;
+ flag_nomem2reg = nomem2reg;
+
+ 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)
+ log_error("Re-definition of module `%s' at %s:%d!\n",
+ (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
+ design->modules[(*it)->str] = process_module(*it);
+ }
+}
+
+// AstModule destructor
+AstModule::~AstModule()
+{
+ if (ast != NULL)
+ delete ast;
+}
+
+// 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());
+
+ current_ast = NULL;
+ flag_dump_ast = false;
+ flag_dump_ast_diff = false;
+ flag_dump_vlog = false;
+ flag_nolatches = nolatches;
+ flag_nomem2reg = nomem2reg;
+ use_internal_line_num();
+
+ 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;
+ for (auto it = new_ast->children.begin(); it != new_ast->children.end(); it++) {
+ AstNode *child = *it;
+ if (child->type != AST_PARAMETER)
+ continue;
+ para_counter++;
+ std::string para_id = child->str;
+ if (parameters.count(child->str) > 0) {
+ log("Parameter %s = %s\n", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[child->str])));
+ rewrite_parameter:
+ child->delete_children();
+ child->children.push_back(AstNode::mkconst_bits(parameters[para_id].bits, false));
+ 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;
+ }
+ char buf[100];
+ snprintf(buf, 100, "$%d", para_counter);
+ if (parameters.count(buf) > 0) {
+ para_id = buf;
+ log("Parameter %d (%s) = %s\n", para_counter, child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id])));
+ goto rewrite_parameter;
+ }
+ }
+ if (parameters.size() > 0)
+ log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), name.c_str());
+
+ 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);
+
+ std::string modname = "$paramod$" + std::string(hexstring) + "$" + name;
+
+ if (design->modules.count(modname) == 0) {
+ new_ast->str = modname;
+ design->modules[modname] = process_module(new_ast);
+ } else {
+ log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
+ }
+
+ delete new_ast;
+ return modname;
+}
+
+// recompile a module from AST with updated widths for auto-wires
+// (auto-wires are wires that are used but not declared an thus have an automatically determined width)
+void AstModule::update_auto_wires(std::map<RTLIL::IdString, int> auto_sizes)
+{
+ log_header("Executing AST frontend in update_auto_wires mode using pre-parsed AST for module `%s'.\n", name.c_str());
+
+ current_ast = NULL;
+ flag_dump_ast = false;
+ flag_dump_ast_diff = false;
+ flag_dump_vlog = false;
+ flag_nolatches = nolatches;
+ flag_nomem2reg = nomem2reg;
+ use_internal_line_num();
+
+ for (auto it = auto_sizes.begin(); it != auto_sizes.end(); it++) {
+ log("Adding extra wire declaration to AST: wire [%d:0] %s\n", it->second - 1, it->first.c_str());
+ AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(it->second - 1, true), AstNode::mkconst_int(0, true)));
+ wire->str = it->first;
+ ast->children.insert(ast->children.begin(), wire);
+ }
+
+ AstModule *newmod = process_module(ast);
+
+ delete ast;
+ ast = newmod->ast;
+ newmod->ast = NULL;
+
+ wires.swap(newmod->wires);
+ cells.swap(newmod->cells);
+ processes.swap(newmod->processes);
+ connections.swap(newmod->connections);
+ attributes.swap(newmod->attributes);
+ delete newmod;
+}
+
+// internal dummy line number callbacks
+namespace {
+ int internal_line_num;
+ void internal_set_line_num(int n) {
+ internal_line_num = n;
+ }
+ int internal_get_line_num() {
+ return internal_line_num;
+ }
+}
+
+// use internal dummy line number callbacks
+void AST::use_internal_line_num()
+{
+ set_line_num = &internal_set_line_num;
+ get_line_num = &internal_get_line_num;
+}
+
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
new file mode 100644
index 00000000..f7c9328c
--- /dev/null
+++ b/frontends/ast/ast.h
@@ -0,0 +1,228 @@
+/*
+ * 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 is the AST frontend library.
+ *
+ * The AST frontend library is not a frontend on it's own but provides a
+ * generic abstract syntax tree (AST) abstraction for HDL code and can be
+ * used by HDL frontends. See "ast.h" for an overview of the API and the
+ * Verilog frontend for an usage example.
+ *
+ */
+
+#ifndef AST_H
+#define AST_H
+
+#include "kernel/rtlil.h"
+#include <stdint.h>
+#include <set>
+
+namespace AST
+{
+ // all node types, type2str() must be extended
+ // whenever a new node type is added here
+ enum AstNodeType
+ {
+ AST_NONE,
+ AST_DESIGN,
+ AST_MODULE,
+ AST_TASK,
+ AST_FUNCTION,
+
+ AST_WIRE,
+ AST_MEMORY,
+ AST_AUTOWIRE,
+ AST_PARAMETER,
+ AST_LOCALPARAM,
+ AST_PARASET,
+ AST_ARGUMENT,
+ AST_RANGE,
+ AST_CONSTANT,
+ AST_CELLTYPE,
+ AST_IDENTIFIER,
+
+ AST_FCALL,
+ AST_TO_SIGNED,
+ AST_TO_UNSIGNED,
+ AST_CONCAT,
+ AST_REPLICATE,
+ AST_BIT_NOT,
+ AST_BIT_AND,
+ AST_BIT_OR,
+ AST_BIT_XOR,
+ AST_BIT_XNOR,
+ AST_REDUCE_AND,
+ AST_REDUCE_OR,
+ AST_REDUCE_XOR,
+ AST_REDUCE_XNOR,
+ AST_REDUCE_BOOL,
+ AST_SHIFT_LEFT,
+ AST_SHIFT_RIGHT,
+ AST_SHIFT_SLEFT,
+ AST_SHIFT_SRIGHT,
+ AST_LT,
+ AST_LE,
+ AST_EQ,
+ AST_NE,
+ AST_GE,
+ AST_GT,
+ AST_ADD,
+ AST_SUB,
+ AST_MUL,
+ AST_DIV,
+ AST_MOD,
+ AST_POW,
+ AST_POS,
+ AST_NEG,
+ AST_LOGIC_AND,
+ AST_LOGIC_OR,
+ AST_LOGIC_NOT,
+ AST_TERNARY,
+ AST_MEMRD,
+ AST_MEMWR,
+
+ AST_TCALL,
+ AST_ASSIGN,
+ AST_CELL,
+ AST_PRIMITIVE,
+ AST_ALWAYS,
+ AST_BLOCK,
+ AST_ASSIGN_EQ,
+ AST_ASSIGN_LE,
+ AST_CASE,
+ AST_COND,
+ AST_DEFAULT,
+ AST_FOR,
+
+ AST_GENVAR,
+ AST_GENFOR,
+ AST_GENIF,
+ AST_GENBLOCK,
+
+ AST_POSEDGE,
+ AST_NEGEDGE,
+ AST_EDGE
+ };
+
+ // convert an node type to a string (e.g. for debug output)
+ std::string type2str(AstNodeType type);
+
+ // The AST is built using instances of this struct
+ struct AstNode
+ {
+ // this nodes type
+ AstNodeType type;
+
+ // the list of child nodes for this node
+ std::vector<AstNode*> children;
+
+ // the list of attributes assigned to this node
+ std::map<RTLIL::IdString, AstNode*> attributes;
+
+ // 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, range_valid;
+ int port_id, range_left, range_right;
+ uint32_t integer;
+
+ // this is set by simplify and used during RTLIL generation
+ AstNode *id2ast;
+
+ // this is the original sourcecode location that resulted in this AST node
+ // it is automatically set by the constructor using AST::current_filename and
+ // the AST::get_line_num() callback function.
+ std::string filename;
+ int linenum;
+
+ // creating and deleting nodes
+ AstNode(AstNodeType type = AST_NONE, AstNode *child1 = NULL, AstNode *child2 = NULL);
+ AstNode *clone();
+ void cloneInto(AstNode *other);
+ void delete_children();
+ ~AstNode();
+
+ // 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);
+ 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 mem2reg_as_needed_pass1(std::set<AstNode*> &mem2reg_set, std::set<AstNode*> &mem2reg_candidates, bool sync_proc, bool async_proc);
+ 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);
+
+ // create a human-readable text representation of the AST (for debugging)
+ void dumpAst(FILE *f, std::string indent, AstNode *other = NULL);
+ void dumpVlog(FILE *f, std::string indent);
+
+ // 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);
+ RTLIL::SigSpec genWidthRTLIL(int width, RTLIL::SigSpec *subst_from = NULL, RTLIL::SigSpec *subst_to = NULL);
+
+ // compare AST nodes
+ bool operator==(const AstNode &other) const;
+ bool operator!=(const AstNode &other) const;
+ bool contains(const AstNode *other) const;
+
+ // helper functions for creating AST nodes for constants
+ static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32);
+ static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed);
+ };
+
+ // 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_ast = false, bool dump_ast_diff = false, bool dump_vlog = false, bool nolatches = false, bool nomem2reg = false);
+
+ // 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;
+ virtual ~AstModule();
+ virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
+ virtual void update_auto_wires(std::map<RTLIL::IdString, int> auto_sizes);
+ };
+
+ // this must be set by the language frontend before parsing the sources
+ // the AstNode constructor then uses current_filename and get_line_num()
+ // to initialize the filename and linenum properties of new nodes
+ extern std::string current_filename;
+ extern void (*set_line_num)(int);
+ extern int (*get_line_num)();
+
+ // set set_line_num and get_line_num to internal dummy functions
+ // (done by simplify(), AstModule::derive and AstModule::update_auto_wires to control
+ // the filename and linenum properties of new nodes not generated by a frontend parser)
+ void use_internal_line_num();
+}
+
+namespace AST_INTERNAL
+{
+ // internal state variables
+ extern bool flag_dump_ast, flag_dump_ast_diff, flag_nolatches, flag_nomem2reg;
+ 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;
+ extern AST::AstNode *current_top_block, *current_block, *current_block_child;
+ extern AST::AstModule *current_module;
+ struct ProcessGenerator;
+}
+
+#endif
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
new file mode 100644
index 00000000..9f1acb61
--- /dev/null
+++ b/frontends/ast/genrtlil.cc
@@ -0,0 +1,1054 @@
+/*
+ * 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 is the AST frontend library.
+ *
+ * The AST frontend library is not a frontend on it's own but provides a
+ * generic abstract syntax tree (AST) abstraction for HDL code and can be
+ * used by HDL frontends. See "ast.h" for an overview of the API and the
+ * Verilog frontend for an usage example.
+ *
+ */
+
+#include "kernel/log.h"
+#include "kernel/sha1.h"
+#include "ast.h"
+
+#include <sstream>
+#include <stdarg.h>
+#include <assert.h>
+
+using namespace AST;
+using namespace AST_INTERNAL;
+
+// helper function for creating RTLIL code for unary operations
+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++);
+
+ RTLIL::Cell *cell = new RTLIL::Cell;
+ 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;
+ 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) {
+ if (attr.second->type != AST_CONSTANT)
+ log_error("Attribute `%s' with non-constant value at %s:%d!\n",
+ attr.first.c_str(), that->filename.c_str(), that->linenum);
+ cell->attributes[attr.first].str = attr.second->str;
+ cell->attributes[attr.first].bits = attr.second->bits;
+ }
+
+ 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["\\Y_WIDTH"] = result_width;
+ cell->connections["\\Y"] = sig;
+ return sig;
+}
+
+// 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++);
+
+ RTLIL::Cell *cell = new RTLIL::Cell;
+ 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;
+ 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)
+ log_error("Attribute `%s' with non-constant value at %s:%d!\n",
+ attr.first.c_str(), that->filename.c_str(), that->linenum);
+ cell->attributes[attr.first].str = attr.second->str;
+ cell->attributes[attr.first].bits = attr.second->bits;
+ }
+
+ 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->connections["\\A"] = left;
+ cell->connections["\\B"] = right;
+
+ cell->parameters["\\Y_WIDTH"] = result_width;
+ cell->connections["\\Y"] = sig;
+ return sig;
+}
+
+// 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);
+
+ std::stringstream sstr;
+ sstr << "$ternary$" << that->filename << ":" << that->linenum << "$" << (RTLIL::autoidx++);
+
+ RTLIL::Cell *cell = new RTLIL::Cell;
+ 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;
+ 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)
+ log_error("Attribute `%s' with non-constant value at %s:%d!\n",
+ attr.first.c_str(), that->filename.c_str(), that->linenum);
+ cell->attributes[attr.first].str = attr.second->str;
+ cell->attributes[attr.first].bits = attr.second->bits;
+ }
+
+ cell->parameters["\\WIDTH"] = RTLIL::Const(left.width);
+
+ cell->connections["\\A"] = right;
+ cell->connections["\\B"] = left;
+ cell->connections["\\S"] = cond;
+ cell->connections["\\Y"] = sig;
+
+ return sig;
+}
+
+// helper class for converting AST always nodes to RTLIL processes
+struct AST_INTERNAL::ProcessGenerator
+{
+ // input and output structures
+ AstNode *always;
+ RTLIL::Process *proc;
+
+ // 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
+ // 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;
+
+ // This two variables contain 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;
+
+ // 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.
+ std::map<RTLIL::Wire*, int> new_temp_count;
+
+ ProcessGenerator(AstNode *always) : always(always)
+ {
+ // generate process and simple root case
+ proc = new RTLIL::Process;
+ proc->name = stringf("$proc$%s:%d$%d", always->filename.c_str(), always->linenum, RTLIL::autoidx++);
+ for (auto &attr : always->attributes) {
+ if (attr.second->type != AST_CONSTANT)
+ log_error("Attribute `%s' with non-constant value at %s:%d!\n",
+ attr.first.c_str(), always->filename.c_str(), always->linenum);
+ proc->attributes[attr.first].str = attr.second->str;
+ proc->attributes[attr.first].bits = attr.second->bits;
+ }
+ current_module->processes[proc->name] = proc;
+ current_case = &proc->root_case;
+
+ // create initial temporary signal for all output registers
+ collect_lvalues(subst_lvalue_from, always, true, true);
+ subst_lvalue_to = new_temp_signal(subst_lvalue_from);
+
+ bool found_anyedge_syncs = false;
+ for (auto child : always->children)
+ if (child->type == AST_EDGE)
+ found_anyedge_syncs = true;
+
+ if (found_anyedge_syncs) {
+ log("Note: Assuming pure combinatorial block at %s:%d in\n", always->filename.c_str(), always->linenum);
+ log("compliance with IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002. Recommending\n");
+ log("use of @* instead of @(...) for better match of synthesis and simulation.\n");
+ }
+
+ // create syncs for the process
+ bool found_clocked_sync = false;
+ for (auto child : always->children)
+ if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) {
+ found_clocked_sync = true;
+ if (found_anyedge_syncs)
+ log_error("Found non-synthesizable event list at %s:%d!\n", always->filename.c_str(), always->linenum);
+ RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;
+ syncrule->type = child->type == AST_POSEDGE ? RTLIL::STp : RTLIL::STn;
+ syncrule->signal = child->children[0]->genRTLIL();
+ addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to);
+ proc->syncs.push_back(syncrule);
+ }
+ if (proc->syncs.empty()) {
+ RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;
+ syncrule->type = RTLIL::STa;
+ syncrule->signal = RTLIL::SigSpec();
+ addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to);
+ proc->syncs.push_back(syncrule);
+ }
+
+ // create initial assignments for the temporary signals
+ if ((flag_nolatches || always->attributes.count("\\nolatches") > 0 || current_module->attributes.count("\\nolatches")) && !found_clocked_sync) {
+ subst_rvalue_from = subst_lvalue_from;
+ subst_rvalue_to = RTLIL::SigSpec(RTLIL::State::Sx, subst_rvalue_from.width);
+ } else {
+ addChunkActions(current_case->actions, subst_lvalue_to, subst_lvalue_from);
+ }
+
+ // process the AST
+ for (auto child : always->children)
+ if (child->type == AST_BLOCK)
+ processAst(child);
+ }
+
+ // create new temporary signals
+ RTLIL::SigSpec new_temp_signal(RTLIL::SigSpec sig)
+ {
+ sig.optimize();
+ for (size_t i = 0; i < sig.chunks.size(); i++)
+ {
+ RTLIL::SigChunk &chunk = sig.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);
+ do {
+ wire->name = stringf("$%d%s[%d:%d]", new_temp_count[chunk.wire]++,
+ chunk.wire->name.c_str(), chunk.width+chunk.offset-1, chunk.offset);;
+ } while (current_module->wires.count(wire->name) > 0);
+ wire->width = chunk.width;
+ current_module->wires[wire->name] = wire;
+
+ chunk.wire = wire;
+ chunk.offset = 0;
+ }
+ return sig;
+ }
+
+ // recursively traverse the AST an collect all assigned signals
+ void collect_lvalues(RTLIL::SigSpec &reg, AstNode *ast, bool type_eq, bool type_le, bool run_sort_and_unify = true)
+ {
+ switch (ast->type)
+ {
+ case AST_CASE:
+ for (auto child : ast->children)
+ if (child != ast->children[0]) {
+ assert(child->type == AST_COND);
+ collect_lvalues(reg, child, type_eq, type_le, false);
+ }
+ break;
+
+ case AST_COND:
+ case AST_ALWAYS:
+ for (auto child : ast->children)
+ if (child->type == AST_BLOCK)
+ collect_lvalues(reg, child, type_eq, type_le, false);
+ break;
+
+ case AST_BLOCK:
+ for (auto child : ast->children) {
+ if (child->type == AST_ASSIGN_EQ && type_eq)
+ reg.append(child->children[0]->genRTLIL());
+ if (child->type == AST_ASSIGN_LE && type_le)
+ reg.append(child->children[0]->genRTLIL());
+ if (child->type == AST_CASE || child->type == AST_BLOCK)
+ collect_lvalues(reg, child, type_eq, type_le, false);
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+
+ if (run_sort_and_unify)
+ reg.sort_and_unify();
+ }
+
+ // remove all assignments to the given signal pattern in a case and all its children
+ // when the last statement in the code "a = 23; if (b) a = 42; a = 0;" is processed this
+ // function is acalled to clean up the first two assignments as they are overwritten by
+ // the third assignment.
+ void removeSignalFromCaseTree(RTLIL::SigSpec pattern, RTLIL::CaseRule *cs)
+ {
+ for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)
+ it->first.remove2(pattern, &it->second);
+
+ for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
+ for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
+ removeSignalFromCaseTree(pattern, *it2);
+ }
+
+ // add an assignment (aka "action") but split it up in chunks. this way huge assignments
+ // 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)
+ {
+ assert(lvalue.width == rvalue.width);
+ lvalue.optimize();
+ rvalue.optimize();
+
+ 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);
+ actions.push_back(RTLIL::SigSig(lhs, rhs));
+ offset += lhs.width;
+ }
+ }
+
+ // recursively process the AST and fill the RTLIL::Process
+ void processAst(AstNode *ast)
+ {
+ switch (ast->type)
+ {
+ case AST_BLOCK:
+ for (auto child : ast->children)
+ processAst(child);
+ break;
+
+ case AST_ASSIGN_EQ:
+ 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);
+
+ 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();
+ }
+
+ removeSignalFromCaseTree(lvalue, current_case);
+ current_case->actions.push_back(RTLIL::SigSig(lvalue, rvalue));
+ }
+ break;
+
+ case AST_CASE:
+ {
+ RTLIL::SwitchRule *sw = new RTLIL::SwitchRule;
+ sw->signal = ast->children[0]->genWidthRTLIL(-1, &subst_rvalue_from, &subst_rvalue_to);
+ current_case->switches.push_back(sw);
+
+ 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);
+ sw->attributes[attr.first].str = attr.second->str;
+ sw->attributes[attr.first].bits = attr.second->bits;
+ }
+
+ RTLIL::SigSpec this_case_eq_lvalue;
+ collect_lvalues(this_case_eq_lvalue, ast, true, false);
+
+ 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;
+
+ bool generated_default_case = false;
+ RTLIL::CaseRule *last_generated_case = NULL;
+ for (auto child : ast->children)
+ {
+ if (child == ast->children[0] || generated_default_case)
+ continue;
+ assert(child->type == AST_COND);
+
+ 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;
+
+ 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();
+
+ RTLIL::CaseRule *backup_case = current_case;
+ current_case = new RTLIL::CaseRule;
+ last_generated_case = current_case;
+ addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
+ for (auto node : child->children) {
+ if (node->type == AST_DEFAULT) {
+ generated_default_case = true;
+ current_case->compare.clear();
+ } else if (node->type == AST_BLOCK) {
+ processAst(node);
+ } else if (!generated_default_case)
+ current_case->compare.push_back(node->genWidthRTLIL(sw->signal.width));
+ }
+ sw->cases.push_back(current_case);
+ current_case = backup_case;
+ }
+
+ if (last_generated_case != NULL && ast->attributes.count("\\full_case") > 0) {
+ last_generated_case->compare.clear();
+ } else if (!generated_default_case) {
+ RTLIL::CaseRule *default_case = new RTLIL::CaseRule;
+ addChunkActions(default_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
+ 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;
+
+ 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);
+ addChunkActions(current_case->actions, this_case_eq_lvalue, this_case_eq_ltemp);
+ }
+ break;
+
+ case AST_TCALL:
+ case AST_FOR:
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+};
+
+// create RTLIL from an AST node
+// all generated cells, wires and processes are added to the module pointed to by 'current_module'
+// when the AST node is an expression (AST_ADD, AST_BIT_XOR, etc.), the result signal is returned.
+//
+// note that this function is influenced by a number of global variables that might be set when
+// called from genWidthRTLIL(). also note that this function recursively calls itself to transform
+// larger expressions into a netlist of cells.
+RTLIL::SigSpec AstNode::genRTLIL(int width_hint)
+{
+ // in the following big switch() statement there are some uses of
+ // Clifford's Device (http://www.clifford.at/cfun/cliffdev/). In this
+ // cases this variable is used to hold the type of the cell that should
+ // be instanciated for this type of AST node.
+ std::string type_name;
+
+ current_filename = filename;
+ set_line_num(linenum);
+
+ switch (type)
+ {
+ // simply ignore this nodes.
+ // they are eighter leftovers from simplify() or are referenced by other nodes
+ // and are only accessed here thru this references
+ case AST_TASK:
+ case AST_FUNCTION:
+ case AST_AUTOWIRE:
+ case AST_PARAMETER:
+ case AST_LOCALPARAM:
+ case AST_GENVAR:
+ case AST_GENFOR:
+ case AST_GENIF:
+ break;
+
+ // create an RTLIL::Wire for an AST_WIRE node
+ case AST_WIRE: {
+ if (current_module->wires.count(str) != 0)
+ log_error("Re-definition of signal `%s' at %s:%d!\n",
+ str.c_str(), filename.c_str(), linenum);
+ 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;
+ }
+
+ RTLIL::Wire *wire = new RTLIL::Wire;
+ 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;
+
+ for (auto &attr : attributes) {
+ if (attr.second->type != AST_CONSTANT)
+ log_error("Attribute `%s' with non-constant value at %s:%d!\n",
+ attr.first.c_str(), filename.c_str(), linenum);
+ wire->attributes[attr.first].str = attr.second->str;
+ wire->attributes[attr.first].bits = attr.second->bits;
+ }
+ }
+ break;
+
+ // create an RTLIL::Memory for an AST_MEMORY node
+ case AST_MEMORY: {
+ if (current_module->memories.count(str) != 0)
+ log_error("Re-definition of memory `%s' at %s:%d!\n",
+ str.c_str(), filename.c_str(), linenum);
+
+ assert(children.size() >= 2);
+ assert(children[0]->type == AST_RANGE);
+ assert(children[1]->type == AST_RANGE);
+
+ if (!children[0]->range_valid || !children[1]->range_valid)
+ log_error("Memory `%s' with non-constant width or size at %s:%d!\n",
+ str.c_str(), filename.c_str(), linenum);
+
+ RTLIL::Memory *memory = new RTLIL::Memory;
+ memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
+ memory->name = str;
+ memory->width = children[0]->range_left - children[0]->range_right + 1;
+ memory->start_offset = children[0]->range_right;
+ memory->size = children[1]->range_left - children[1]->range_right;
+ current_module->memories[memory->name] = memory;
+
+ if (memory->size < 0)
+ memory->size *= -1;
+ memory->size += std::min(children[1]->range_left, children[1]->range_right) + 1;
+
+ for (auto &attr : attributes) {
+ if (attr.second->type != AST_CONSTANT)
+ log_error("Attribute `%s' with non-constant value at %s:%d!\n",
+ attr.first.c_str(), filename.c_str(), linenum);
+ memory->attributes[attr.first].str = attr.second->str;
+ memory->attributes[attr.first].bits = attr.second->bits;
+ }
+ }
+ break;
+
+ // simply return the corresponding RTLIL::SigSpec for an AST_CONSTANT node
+ case AST_CONSTANT:
+ {
+ 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;
+ return sig;
+ }
+
+ // simply return the corresponding RTLIL::SigSpec for an AST_IDENTIFIER node
+ // for identifiers with dynamic bit ranges (e.g. "foo[bar]" or "foo[bar+3:bar]") a
+ // shifter cell is created and the output signal of this cell is returned
+ case AST_IDENTIFIER:
+ {
+ if (id2ast && id2ast->type == AST_AUTOWIRE && current_module->wires.count(str) == 0) {
+ RTLIL::Wire *wire = new RTLIL::Wire;
+ wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
+ wire->name = str;
+ if (width_hint >= 0) {
+ wire->width = width_hint;
+ log("Warning: Identifier `%s' is implicitly declared with width %d at %s:%d.\n",
+ str.c_str(), width_hint, filename.c_str(), linenum);
+ } else {
+ log("Warning: Identifier `%s' is implicitly declared at %s:%d.\n",
+ str.c_str(), filename.c_str(), linenum);
+ }
+ wire->auto_width = true;
+ current_module->wires[str] = wire;
+ }
+ else if (!id2ast || (id2ast->type != AST_WIRE && id2ast->type != AST_AUTOWIRE &&
+ id2ast->type != AST_MEMORY) || current_module->wires.count(str) == 0)
+ log_error("Identifier `%s' doesn't map to any signal at %s:%d!\n",
+ str.c_str(), filename.c_str(), linenum);
+
+ if (id2ast->type == AST_MEMORY)
+ log_error("Identifier `%s' does map to an unexpanded memory at %s:%d!\n",
+ str.c_str(), filename.c_str(), linenum);
+
+ RTLIL::Wire *wire = current_module->wires[str];
+
+ RTLIL::SigChunk chunk;
+ chunk.wire = wire;
+ chunk.width = wire->width;
+ chunk.offset = 0;
+
+ if (children.size() != 0) {
+ assert(children[0]->type == AST_RANGE);
+ 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)) { }
+ while (right_at_zero_ast->simplify(true, true, false, 1)) { }
+ 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;
+ 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());
+ 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);
+ }
+ }
+
+ RTLIL::SigSpec sig;
+ sig.chunks.push_back(chunk);
+ sig.width = chunk.width;
+
+ if (genRTLIL_subst_from && genRTLIL_subst_to)
+ sig.replace(*genRTLIL_subst_from, *genRTLIL_subst_to);
+
+ is_signed = id2ast->is_signed;
+ if (children.size() != 0)
+ is_signed = false;
+
+ return sig;
+ }
+
+ // just pass thru the signal. the parent will evaluated the is_signed property and inperpret the SigSpec accordingly
+ case AST_TO_SIGNED:
+ case AST_TO_UNSIGNED: {
+ RTLIL::SigSpec sig = children[0]->genRTLIL(width_hint);
+ is_signed = type == AST_TO_SIGNED;
+ return sig;
+ }
+
+ // 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;
+ }
+ }
+ return sig;
+ }
+
+ // replication of signals can be done directly using RTLIL::SigSpec
+ case AST_REPLICATE: {
+ RTLIL::SigSpec left = children[0]->genRTLIL();
+ RTLIL::SigSpec right = children[1]->genRTLIL();
+ if (!left.is_fully_const())
+ log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);
+ int count = left.as_int();
+ RTLIL::SigSpec sig;
+ for (int i = 0; i < count; i++)
+ sig.append(right);
+ is_signed = false;
+ return sig;
+ }
+
+ // generate cells for unary operations: $not, $pos, $neg
+ if (0) { case AST_BIT_NOT: type_name = "$not"; }
+ if (0) { case AST_POS: type_name = "$pos"; }
+ if (0) { case AST_NEG: type_name = "$neg"; }
+ {
+ RTLIL::SigSpec arg = children[0]->genRTLIL(width_hint);
+ is_signed = type == AST_NEG || (type == AST_POS && children[0]->is_signed);
+ int width = type == AST_NEG && arg.width < width_hint ? arg.width+1 : arg.width;
+ if (width > width_hint && width_hint > 0)
+ width = width_hint;
+ return uniop2rtlil(this, type_name, width, arg);
+ }
+
+ // generate cells for binary operations: $and, $or, $xor, $xnor
+ if (0) { case AST_BIT_AND: type_name = "$and"; }
+ if (0) { case AST_BIT_OR: type_name = "$or"; }
+ if (0) { case AST_BIT_XOR: type_name = "$xor"; }
+ if (0) { case AST_BIT_XNOR: type_name = "$xnor"; }
+ {
+ RTLIL::SigSpec left = children[0]->genRTLIL(width_hint);
+ RTLIL::SigSpec right = children[1]->genRTLIL(width_hint);
+ int width = std::max(left.width, right.width);
+ if (width > width_hint && width_hint > 0)
+ width = width_hint;
+ return binop2rtlil(this, type_name, width, left, right);
+ }
+
+ // generate cells for unary operations: $reduce_and, $reduce_or, $reduce_xor, $reduce_xnor
+ if (0) { case AST_REDUCE_AND: type_name = "$reduce_and"; }
+ if (0) { case AST_REDUCE_OR: type_name = "$reduce_or"; }
+ if (0) { case AST_REDUCE_XOR: type_name = "$reduce_xor"; }
+ if (0) { case AST_REDUCE_XNOR: type_name = "$reduce_xnor"; }
+ {
+ RTLIL::SigSpec arg = children[0]->genRTLIL();
+ RTLIL::SigSpec sig = uniop2rtlil(this, type_name, 1, arg);
+ return sig;
+ }
+
+ // generate cells for unary operations: $reduce_bool
+ // (this is actually just an $reduce_or, but for clearity a different cell type is used)
+ 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, 1, arg) : arg;
+ return sig;
+ }
+
+ // generate cells for binary operations: $shl, $shr, $sshl, $sshr
+ if (0) { case AST_SHIFT_LEFT: type_name = "$shl"; }
+ if (0) { case AST_SHIFT_RIGHT: type_name = "$shr"; }
+ if (0) { case AST_SHIFT_SLEFT: type_name = "$sshl"; is_signed = true; }
+ if (0) { case AST_SHIFT_SRIGHT: type_name = "$sshr"; is_signed = true; }
+ {
+ RTLIL::SigSpec left = children[0]->genRTLIL(width_hint);
+ RTLIL::SigSpec right = children[1]->genRTLIL(width_hint);
+ int width = width_hint > 0 ? width_hint : left.width;
+ return binop2rtlil(this, type_name, width, left, right);
+ }
+
+ // generate cells for binary operations: $lt, $le, $eq, $ne, $ge, $gt
+ if (0) { case AST_LT: type_name = "$lt"; }
+ if (0) { case AST_LE: type_name = "$le"; }
+ if (0) { case AST_EQ: type_name = "$eq"; }
+ if (0) { case AST_NE: type_name = "$ne"; }
+ if (0) { case AST_GE: type_name = "$ge"; }
+ if (0) { case AST_GT: type_name = "$gt"; }
+ {
+ RTLIL::SigSpec left = children[0]->genRTLIL();
+ RTLIL::SigSpec right = children[1]->genRTLIL();
+ RTLIL::SigSpec sig = binop2rtlil(this, type_name, 1, left, right);
+ return sig;
+ }
+
+ // generate cells for binary operations: $add, $sub, $mul, $div, $mod, $pow
+ if (0) { case AST_ADD: type_name = "$add"; }
+ if (0) { case AST_SUB: type_name = "$sub"; }
+ if (0) { case AST_MUL: type_name = "$mul"; }
+ if (0) { case AST_DIV: type_name = "$div"; }
+ if (0) { case AST_MOD: type_name = "$mod"; }
+ if (0) { case AST_POW: type_name = "$pow"; }
+ {
+ RTLIL::SigSpec left = children[0]->genRTLIL(width_hint);
+ RTLIL::SigSpec right = children[1]->genRTLIL(width_hint);
+ int width = std::max(left.width, right.width);
+ if (width > width_hint && width_hint > 0)
+ width = width_hint;
+ if (width < width_hint) {
+ if (type == AST_ADD || type == AST_SUB) {
+ width++;
+ if (width < width_hint && children[0]->is_signed != children[1]->is_signed)
+ width++;
+ }
+ 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);
+ }
+ is_signed = children[0]->is_signed || children[1]->is_signed;
+ return binop2rtlil(this, type_name, width, left, right);
+ }
+
+ // generate cells for binary operations: $logic_and, $logic_or
+ if (0) { case AST_LOGIC_AND: type_name = "$logic_and"; }
+ if (0) { case AST_LOGIC_OR: type_name = "$logic_or"; }
+ {
+ RTLIL::SigSpec left = children[0]->genRTLIL();
+ RTLIL::SigSpec right = children[1]->genRTLIL();
+ return binop2rtlil(this, type_name, 1, left, right);
+ }
+
+ // generate cells for unary operations: $logic_not
+ case AST_LOGIC_NOT:
+ {
+ RTLIL::SigSpec arg = children[0]->genRTLIL();
+ return uniop2rtlil(this, "$logic_not", 1, arg);
+ }
+
+ // generate multiplexer for ternary operator (aka ?:-operator)
+ case AST_TERNARY:
+ {
+ RTLIL::SigSpec cond = children[0]->genRTLIL();
+ RTLIL::SigSpec val1 = children[1]->genRTLIL();
+ RTLIL::SigSpec val2 = children[2]->genRTLIL();
+
+ if (cond.width > 1)
+ cond = uniop2rtlil(this, "$reduce_bool", 1, cond, false);
+
+ int width = std::max(val1.width, val2.width);
+ if (children[1]->is_signed && children[2]->is_signed) {
+ is_signed = true;
+ val1.extend(width, children[1]->is_signed);
+ val2.extend(width, children[2]->is_signed);
+ } else {
+ is_signed = false;
+ val1.extend(width);
+ val2.extend(width);
+ }
+
+ return mux2rtlil(this, cond, val1, val2);
+ }
+
+ // generate $memrd cells for memory read ports
+ case AST_MEMRD:
+ {
+ std::stringstream sstr;
+ sstr << "$memrd$" << str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+
+ RTLIL::Cell *cell = new RTLIL::Cell;
+ 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;
+ 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]->genRTLIL();
+ cell->connections["\\DATA"] = RTLIL::SigSpec(wire);
+
+ cell->parameters["\\MEMID"] = RTLIL::Const(str);
+ cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
+ cell->parameters["\\WIDTH"] = RTLIL::Const(wire->width);
+
+ cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
+ cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
+
+ return RTLIL::SigSpec(wire);
+ }
+
+ // generate $memwr cells for memory write ports
+ case AST_MEMWR:
+ {
+ std::stringstream sstr;
+ sstr << "$memwr$" << str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+
+ RTLIL::Cell *cell = new RTLIL::Cell;
+ 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]->genRTLIL();
+ cell->connections["\\DATA"] = children[1]->genRTLIL();
+ cell->connections["\\EN"] = children[2]->genRTLIL();
+
+ cell->parameters["\\MEMID"] = RTLIL::Const(str);
+ cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
+ cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width);
+
+ cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
+ cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
+ }
+ break;
+
+ // add entries to current_module->connections for assignments (outside of always blocks)
+ case AST_ASSIGN:
+ {
+ if (children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_AUTOWIRE) {
+ RTLIL::SigSpec right = children[1]->genRTLIL();
+ RTLIL::SigSpec left = children[0]->genWidthRTLIL(right.width);
+ current_module->connections.push_back(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));
+ }
+ }
+ break;
+
+ // create an RTLIL::Cell for an AST_CELL
+ case AST_CELL:
+ {
+ int port_counter = 0, para_counter = 0;
+ RTLIL::Cell *cell = new RTLIL::Cell;
+ 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) {
+ cell->type = child->str;
+ continue;
+ }
+ if (child->type == AST_PARASET) {
+ if (child->children[0]->type != AST_CONSTANT)
+ log_error("Parameter `%s' with non-constant value at %s:%d!\n",
+ child->str.c_str(), filename.c_str(), linenum);
+ if (child->str.size() == 0) {
+ char buf[100];
+ snprintf(buf, 100, "$%d", ++para_counter);
+ cell->parameters[buf].str = child->children[0]->str;
+ cell->parameters[buf].bits = child->children[0]->bits;
+ } else {
+ cell->parameters[child->str].str = child->children[0]->str;
+ cell->parameters[child->str].bits = child->children[0]->bits;
+ }
+ continue;
+ }
+ if (child->type == AST_ARGUMENT) {
+ RTLIL::SigSpec sig;
+ if (child->children.size() > 0)
+ sig = child->children[0]->genRTLIL();
+ if (child->str.size() == 0) {
+ char buf[100];
+ snprintf(buf, 100, "$%d", ++port_counter);
+ cell->connections[buf] = sig;
+ } else {
+ cell->connections[child->str] = sig;
+ }
+ continue;
+ }
+ assert(0);
+ }
+ for (auto &attr : attributes) {
+ if (attr.second->type != AST_CONSTANT)
+ log_error("Attribute `%s' with non-constant value at %s:%d!\n",
+ attr.first.c_str(), filename.c_str(), linenum);
+ cell->attributes[attr.first].str = attr.second->str;
+ cell->attributes[attr.first].bits = attr.second->bits;
+ }
+ 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;
+
+ // use ProcessGenerator for always blocks
+ case AST_ALWAYS: {
+ AstNode *always = this->clone();
+ ProcessGenerator generator(always);
+ delete always;
+ } break;
+
+ // everything should have been handled above -> print error if not.
+ default:
+ for (auto f : log_files)
+ current_ast->dumpAst(f, "verilog-ast> ");
+ type_name = type2str(type);
+ log_error("Don't know how to generate RTLIL code for %s node at %s:%d!\n",
+ type_name.c_str(), filename.c_str(), linenum);
+ }
+
+ return RTLIL::SigSpec();
+}
+
+// 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 *backup_subst_from = genRTLIL_subst_from;
+ RTLIL::SigSpec *backup_subst_to = genRTLIL_subst_to;
+
+ if (subst_from)
+ genRTLIL_subst_from = subst_from;
+ if (subst_to)
+ genRTLIL_subst_to = subst_to;
+
+ RTLIL::SigSpec sig = genRTLIL(width);
+
+ genRTLIL_subst_from = backup_subst_from;
+ genRTLIL_subst_to = backup_subst_to;
+
+ if (width >= 0)
+ sig.extend(width, is_signed);
+
+ return sig;
+}
+
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
new file mode 100644
index 00000000..cb8b1043
--- /dev/null
+++ b/frontends/ast/simplify.cc
@@ -0,0 +1,1081 @@
+/*
+ * 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 is the AST frontend library.
+ *
+ * The AST frontend library is not a frontend on it's own but provides a
+ * generic abstract syntax tree (AST) abstraction for HDL code and can be
+ * used by HDL frontends. See "ast.h" for an overview of the API and the
+ * Verilog frontend for an usage example.
+ *
+ */
+
+#include "kernel/log.h"
+#include "kernel/sha1.h"
+#include "ast.h"
+
+#include <sstream>
+#include <stdarg.h>
+#include <assert.h>
+
+using namespace AST;
+using namespace AST_INTERNAL;
+
+// convert the AST into a simpler AST that has all parameters subsitited by their
+// values, unrolled for-loops, expanded generate blocks, etc. when this function
+// is done with an AST it can be converted into RTLIL using genRTLIL().
+//
+// 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)
+{
+ AstNode *newNode = NULL;
+ bool did_something = false;
+
+ if (stage == 0)
+ {
+ assert(type == AST_MODULE);
+
+ while (simplify(const_fold, at_zero, in_lvalue, 1)) { }
+
+ if (!flag_nomem2reg && attributes.count("\\nomem2reg") == 0)
+ {
+ std::set<AstNode*> mem2reg_set, mem2reg_candidates;
+ mem2reg_as_needed_pass1(mem2reg_set, mem2reg_candidates, false, false);
+
+ for (auto node : mem2reg_set)
+ {
+ int mem_width, mem_size, addr_bits;
+ node->meminfo(mem_width, mem_size, addr_bits);
+
+ for (int i = 0; i < mem_size; i++) {
+ AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE,
+ mkconst_int(mem_width-1, true), mkconst_int(0, true)));
+ reg->str = stringf("%s[%d]", node->str.c_str(), i);
+ reg->is_reg = true;
+ reg->is_signed = node->is_signed;
+ children.push_back(reg);
+ }
+ }
+
+ mem2reg_as_needed_pass2(mem2reg_set, this, NULL);
+
+ for (size_t i = 0; i < children.size(); i++) {
+ if (mem2reg_set.count(children[i]) > 0) {
+ delete children[i];
+ children.erase(children.begin() + (i--));
+ }
+ }
+ }
+
+ while (simplify(const_fold, at_zero, in_lvalue, 2)) { }
+ return false;
+ }
+
+ current_filename = filename;
+ set_line_num(linenum);
+
+ // we do not look inside a task or function
+ // (but as soon as a task of function is instanciated we process the generated AST as usual)
+ if (type == AST_FUNCTION || type == AST_TASK)
+ return false;
+
+ // deactivate all calls non-synthesis system taks
+ if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$stop" || str == "$finish")) {
+ delete_children();
+ str = std::string();
+ }
+
+ // activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.)
+ if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_PARASET || type == AST_RANGE)
+ const_fold = true;
+ if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM))
+ const_fold = true;
+
+ std::map<std::string, AstNode*> backup_scope;
+
+ // create name resolution entries for all objects with names
+ // also merge multiple declarations for the same wire (e.g. "output foobar; reg foobar;")
+ if (type == AST_MODULE) {
+ current_scope.clear();
+ std::map<std::string, AstNode*> this_wire_scope;
+ for (size_t i = 0; i < children.size(); i++) {
+ AstNode *node = children[i];
+ if (node->type == AST_WIRE) {
+ if (this_wire_scope.count(node->str) > 0) {
+ AstNode *first_node = this_wire_scope[node->str];
+ if (first_node->children.size() != node->children.size())
+ goto wires_are_incompatible;
+ for (size_t j = 0; j < node->children.size(); j++) {
+ AstNode *n1 = first_node->children[j], *n2 = node->children[j];
+ if (n1->type == AST_RANGE && n2->type == AST_RANGE && n1->range_valid && n2->range_valid) {
+ if (n1->range_left != n2->range_left)
+ goto wires_are_incompatible;
+ if (n1->range_right != n2->range_right)
+ goto wires_are_incompatible;
+ } else if (*n1 != *n2)
+ goto wires_are_incompatible;
+ }
+ if (first_node->range_left != node->range_left)
+ goto wires_are_incompatible;
+ if (first_node->range_right != node->range_right)
+ goto wires_are_incompatible;
+ if (first_node->port_id == 0 && (node->is_input || node->is_output))
+ goto wires_are_incompatible;
+ if (node->is_input)
+ first_node->is_input = true;
+ if (node->is_output)
+ first_node->is_output = true;
+ if (node->is_reg)
+ first_node->is_reg = true;
+ if (node->is_signed)
+ first_node->is_signed = true;
+ for (auto &it : node->attributes) {
+ if (first_node->attributes.count(it.first) > 0)
+ delete first_node->attributes[it.first];
+ first_node->attributes[it.first] = it.second->clone();
+ }
+ children.erase(children.begin()+(i--));
+ did_something = true;
+ delete node;
+ 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) {
+ backup_scope[node->str] = current_scope[node->str];
+ current_scope[node->str] = node;
+ }
+ }
+ }
+
+ auto backup_current_block = current_block;
+ auto backup_current_block_child = current_block_child;
+ auto backup_current_top_block = current_top_block;
+
+ // 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++) {
+ bool did_something_here = true;
+ if ((type == AST_GENFOR || type == AST_FOR) && i >= 3)
+ break;
+ if (type == AST_GENIF && i >= 1)
+ break;
+ while (did_something_here && i < children.size()) {
+ bool const_fold_here = const_fold, in_lvalue_here = in_lvalue;
+ if (i == 0 && type == AST_REPLICATE)
+ const_fold_here = true;
+ if (i == 0 && (type == AST_ASSIGN || type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE))
+ in_lvalue_here = true;
+ if (type == AST_BLOCK) {
+ current_block = this;
+ current_block_child = children[i];
+ }
+ if (type == AST_ALWAYS && children[i]->type == AST_BLOCK)
+ current_top_block = children[i];
+ did_something_here = children[i]->simplify(const_fold_here, at_zero, in_lvalue_here, stage);
+ if (did_something_here)
+ did_something = true;
+ }
+ }
+ for (auto &attr : attributes) {
+ while (attr.second->simplify(true, false, false, stage)) { }
+ }
+
+ current_block = backup_current_block;
+ current_block_child = backup_current_block_child;
+ current_top_block = backup_current_top_block;
+
+ for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) {
+ if (it->second == NULL)
+ current_scope.erase(it->first);
+ else
+ current_scope[it->first] = it->second;
+ }
+
+ current_filename = filename;
+ set_line_num(linenum);
+
+ if (type == AST_MODULE)
+ current_scope.clear();
+
+ // annotate constant ranges
+ if (type == AST_RANGE) {
+ bool old_range_valid = range_valid;
+ range_valid = false;
+ range_left = -1;
+ range_right = 0;
+ assert(children.size() >= 1);
+ if (children[0]->type == AST_CONSTANT) {
+ range_valid = true;
+ range_left = children[0]->integer;
+ if (children.size() == 1)
+ range_right = range_left;
+ }
+ if (children.size() >= 2) {
+ if (children[1]->type == AST_CONSTANT)
+ range_right = children[1]->integer;
+ else
+ range_valid = false;
+ }
+ if (old_range_valid != range_valid)
+ did_something = true;
+ if (range_valid && range_left >= 0 && range_right > range_left) {
+ int tmp = range_right;
+ range_right = range_left;
+ range_left = tmp;
+ }
+ }
+
+ // annotate wires with their ranges
+ if (type == AST_WIRE) {
+ if (children.size() > 0) {
+ if (children[0]->range_valid) {
+ if (!range_valid)
+ did_something = true;
+ range_valid = true;
+ range_left = children[0]->range_left;
+ range_right = children[0]->range_right;
+ }
+ } else {
+ if (!range_valid)
+ did_something = true;
+ range_valid = true;
+ range_left = 0;
+ range_right = 0;
+ }
+ }
+
+ // annotate identifiers using scope resolution and create auto-wires as needed
+ if (type == AST_IDENTIFIER) {
+ 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) {
+ current_scope[node->str] = node;
+ break;
+ }
+ }
+ }
+ if (current_scope.count(str) == 0) {
+ log("Warning: Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str());
+ AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
+ auto_wire->str = str;
+ current_ast_mod->children.push_back(auto_wire);
+ current_scope[str] = auto_wire;
+ did_something = true;
+ }
+ id2ast = current_scope[str];
+ }
+
+ // unroll for loops and generate-for blocks
+ if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0)
+ {
+ AstNode *init_ast = children[0];
+ AstNode *while_ast = children[1];
+ AstNode *next_ast = children[2];
+ AstNode *body_ast = children[3];
+
+ if (init_ast->type != AST_ASSIGN_EQ)
+ log_error("Unsupported 1st expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum);
+ if (next_ast->type != AST_ASSIGN_EQ)
+ log_error("Unsupported 3rd expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum);
+
+ if (type == AST_GENFOR) {
+ if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_GENVAR)
+ log_error("Left hand side of 1st expression of generate for-loop at %s:%d is not a gen var!\n", filename.c_str(), linenum);
+ if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_GENVAR)
+ log_error("Left hand side of 3rd expression of generate for-loop at %s:%d is not a gen var!\n", filename.c_str(), linenum);
+ } else {
+ if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_WIRE)
+ log_error("Left hand side of 1st expression of generate for-loop at %s:%d is not a register!\n", filename.c_str(), linenum);
+ if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_WIRE)
+ log_error("Left hand side of 3rd expression of generate for-loop at %s:%d is not a register!\n", filename.c_str(), linenum);
+ }
+
+ if (init_ast->children[0]->id2ast != next_ast->children[0]->id2ast)
+ log_error("Incompatible left-hand sides in 1st and 3rd expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum);
+
+ // eval 1st expression
+ AstNode *varbuf = init_ast->children[1]->clone();
+ while (varbuf->simplify(true, false, false, stage)) { }
+
+ 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);
+
+ varbuf = new AstNode(AST_LOCALPARAM, varbuf);
+ varbuf->str = init_ast->children[0]->str;
+
+ AstNode *backup_scope_varbuf = current_scope[varbuf->str];
+ current_scope[varbuf->str] = varbuf;
+
+ size_t current_block_idx = 0;
+ if (type == AST_FOR) {
+ while (current_block_idx < current_block->children.size() &&
+ current_block->children[current_block_idx] != current_block_child)
+ current_block_idx++;
+ }
+
+ while (1)
+ {
+ // eval 2nd expression
+ AstNode *buf = while_ast->clone();
+ while (buf->simplify(true, false, false, stage)) { }
+
+ if (buf->type != AST_CONSTANT)
+ log_error("2nd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
+
+ if (buf->integer == 0) {
+ delete buf;
+ break;
+ }
+ delete buf;
+
+ // expand body
+ int index = varbuf->children[0]->integer;
+ if (body_ast->type == AST_GENBLOCK)
+ buf = body_ast->clone();
+ else
+ buf = new AstNode(AST_GENBLOCK, body_ast->clone());
+ if (buf->str.empty()) {
+ std::stringstream sstr;
+ sstr << "$genblock$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+ buf->str = sstr.str();
+ }
+ std::map<std::string, std::string> name_map;
+ std::stringstream sstr;
+ sstr << buf->str << "[" << index << "].";
+ buf->expand_genblock(varbuf->str, sstr.str(), name_map);
+
+ if (type == AST_GENFOR) {
+ for (size_t i = 0; i < buf->children.size(); i++)
+ current_ast_mod->children.push_back(buf->children[i]);
+ } else {
+ for (size_t i = 0; i < buf->children.size(); i++)
+ current_block->children.insert(current_block->children.begin() + current_block_idx++, buf->children[i]);
+ }
+ buf->children.clear();
+ delete buf;
+
+ // eval 3rd expression
+ buf = next_ast->children[1]->clone();
+ while (buf->simplify(true, false, false, stage)) { }
+
+ 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);
+
+ delete varbuf->children[0];
+ varbuf->children[0] = buf;
+ }
+
+ current_scope[varbuf->str] = backup_scope_varbuf;
+ delete varbuf;
+ delete_children();
+ did_something = true;
+ }
+
+ // simplify generate-if blocks
+ if (type == AST_GENIF && children.size() != 0)
+ {
+ AstNode *buf = children[0]->clone();
+ while (buf->simplify(true, false, false, stage)) { }
+ if (buf->type != AST_CONSTANT) {
+ for (auto f : log_files)
+ dumpAst(f, "verilog-ast> ");
+ log_error("Condition for generate if at %s:%d is not constant!\n", filename.c_str(), linenum);
+ }
+ if (buf->integer != 0) {
+ delete buf;
+ buf = children[1]->clone();
+ } else {
+ delete buf;
+ buf = children.size() > 2 ? children[2]->clone() : NULL;
+ }
+
+ if (buf)
+ {
+ if (buf->type != AST_GENBLOCK)
+ buf = new AstNode(AST_GENBLOCK, buf);
+
+ if (!buf->str.empty()) {
+ std::map<std::string, std::string> name_map;
+ buf->expand_genblock(std::string(), buf->str, name_map);
+ }
+
+ for (size_t i = 0; i < buf->children.size(); i++)
+ current_ast_mod->children.push_back(buf->children[i]);
+
+ buf->children.clear();
+ delete buf;
+ }
+
+ delete_children();
+ did_something = true;
+ }
+
+ // replace primitives with assignmens
+ if (type == AST_PRIMITIVE)
+ {
+ if (children.size() < 2)
+ log_error("Insufficient number of arguments for primitive `%s' at %s:%d!\n",
+ str.c_str(), filename.c_str(), linenum);
+
+ std::vector<AstNode*> children_list;
+ for (auto child : children) {
+ assert(child->type == AST_ARGUMENT);
+ assert(child->children.size() == 1);
+ children_list.push_back(child->children[0]);
+ child->children.clear();
+ delete child;
+ }
+ children.clear();
+
+ AstNodeType op_type = AST_NONE;
+ bool invert_results = false;
+
+ if (str == "and")
+ op_type = AST_BIT_AND;
+ if (str == "nand")
+ op_type = AST_BIT_AND, invert_results = true;
+ if (str == "or")
+ op_type = AST_BIT_OR;
+ if (str == "nor")
+ op_type = AST_BIT_OR, invert_results = true;
+ if (str == "xor")
+ op_type = AST_BIT_XOR;
+ if (str == "xnor")
+ op_type = AST_BIT_XOR, invert_results = true;
+ if (str == "buf")
+ op_type = AST_POS;
+ if (str == "not")
+ op_type = AST_POS, invert_results = true;
+ assert(op_type != AST_NONE);
+
+ AstNode *node = children_list[1];
+ if (op_type != AST_POS)
+ for (size_t i = 2; i < children_list.size(); i++)
+ node = new AstNode(op_type, node, children_list[i]);
+ if (invert_results)
+ node = new AstNode(AST_BIT_NOT, node);
+
+ str.clear();
+ type = AST_ASSIGN;
+ children.push_back(children_list[0]);
+ children.push_back(node);
+ did_something = true;
+ }
+
+ // replace dynamic ranges in left-hand side expressions (e.g. "foo[bar] <= 1'b1;") with
+ // a big case block that selects the correct single-bit assignment.
+ if (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) {
+ if (children[0]->type != AST_IDENTIFIER || children[0]->children.size() == 0)
+ goto skip_dynamic_range_lvalue_expansion;
+ if (children[0]->children[0]->range_valid || did_something)
+ goto skip_dynamic_range_lvalue_expansion;
+ if (children[0]->id2ast == NULL || children[0]->id2ast->type != AST_WIRE)
+ goto skip_dynamic_range_lvalue_expansion;
+ if (!children[0]->id2ast->range_valid)
+ goto skip_dynamic_range_lvalue_expansion;
+ int source_width = children[0]->id2ast->range_left - children[0]->id2ast->range_right + 1;
+ int result_width = 1;
+ AstNode *shift_expr = NULL;
+ AstNode *range = children[0]->children[0];
+ if (range->children.size() == 1) {
+ shift_expr = range->children[0]->clone();
+ } else {
+ 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)) { }
+ while (right_at_zero_ast->simplify(true, true, false, stage)) { }
+ if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
+ log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
+ str.c_str(), filename.c_str(), linenum);
+ result_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
+ }
+ did_something = true;
+ newNode = new AstNode(AST_CASE, shift_expr);
+ for (int i = 0; i <= source_width-result_width; i++) {
+ int start_bit = children[0]->id2ast->range_right + i;
+ AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true));
+ AstNode *lvalue = children[0]->clone();
+ lvalue->delete_children();
+ lvalue->children.push_back(new AstNode(AST_RANGE,
+ mkconst_int(start_bit+result_width-1, true), mkconst_int(start_bit, true)));
+ cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone())));
+ newNode->children.push_back(cond);
+ }
+ goto apply_newNode;
+ }
+skip_dynamic_range_lvalue_expansion:;
+
+ // found right-hand side identifier for memory -> replace with memory read port
+ if (stage > 1 && type == AST_IDENTIFIER && id2ast != NULL && id2ast->type == AST_MEMORY && !in_lvalue &&
+ children[0]->type == AST_RANGE && children[0]->children.size() == 1) {
+ newNode = new AstNode(AST_MEMRD, children[0]->children[0]->clone());
+ newNode->str = str;
+ goto apply_newNode;
+ }
+
+ // 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)
+ {
+ std::stringstream sstr;
+ sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::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",
+ filename.c_str(), linenum);
+
+ int mem_width, mem_size, addr_bits;
+ children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
+
+ AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true)));
+ wire_addr->str = id_addr;
+ current_ast_mod->children.push_back(wire_addr);
+ current_scope[wire_addr->str] = wire_addr;
+
+ 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;
+
+ AstNode *wire_en = new AstNode(AST_WIRE);
+ wire_en->str = id_en;
+ current_ast_mod->children.push_back(wire_en);
+ current_scope[wire_en->str] = wire_en;
+
+ std::vector<RTLIL::State> x_bits;
+ x_bits.push_back(RTLIL::State::Sx);
+
+ AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits, 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));
+ assign_data->children[0]->str = id_data;
+
+ AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, 1));
+ assign_en->children[0]->str = id_en;
+
+ AstNode *default_signals = new AstNode(AST_BLOCK);
+ default_signals->children.push_back(assign_addr);
+ default_signals->children.push_back(assign_data);
+ default_signals->children.push_back(assign_en);
+ current_top_block->children.insert(current_top_block->children.begin(), default_signals);
+
+ assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone());
+ 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;
+
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1));
+ assign_en->children[0]->str = id_en;
+
+ newNode = new AstNode(AST_BLOCK);
+ newNode->children.push_back(assign_addr);
+ newNode->children.push_back(assign_data);
+ newNode->children.push_back(assign_en);
+
+ AstNode *wrnode = new AstNode(AST_MEMWR);
+ wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
+ wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
+ wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
+ wrnode->str = children[0]->str;
+ wrnode->children[0]->str = id_addr;
+ wrnode->children[1]->str = id_data;
+ wrnode->children[2]->str = id_en;
+ current_ast_mod->children.push_back(wrnode);
+
+ goto apply_newNode;
+ }
+
+ // replace function and task calls with the code from the function or task
+ if ((type == AST_FCALL || type == AST_TCALL) && !str.empty())
+ {
+ if (type == AST_FCALL) {
+ 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);
+ }
+ if (type == AST_TCALL) {
+ if (current_scope.count(str) == 0 || current_scope[str]->type != AST_TASK)
+ log_error("Can't resolve task name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ }
+
+ AstNode *decl = current_scope[str];
+ std::stringstream sstr;
+ sstr << "$func$" << str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++) << "$";
+ std::string prefix = sstr.str();
+
+ size_t arg_count = 0;
+ std::map<std::string, std::string> replace_rules;
+
+ if (current_block == NULL)
+ {
+ 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);
+
+ wire->str = prefix + str;
+ wire->port_id = 0;
+ wire->is_input = false;
+ wire->is_output = false;
+
+ current_ast_mod->children.push_back(wire);
+
+ AstNode *lvalue = new AstNode(AST_IDENTIFIER);
+ lvalue->str = wire->str;
+
+ AstNode *always = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK,
+ new AstNode(AST_ASSIGN_EQ, lvalue, clone())));
+ current_ast_mod->children.push_back(always);
+
+ goto replace_fcall_with_id;
+ }
+
+ for (auto child : decl->children)
+ {
+ if (child->type == AST_WIRE)
+ {
+ 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);
+
+ replace_rules[child->str] = wire->str;
+
+ if (child->is_input && 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);
+
+ 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;
+ }
+ }
+ }
+ else
+ {
+ AstNode *stmt = child->clone();
+ stmt->replace_ids(replace_rules);
+
+ for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
+ if (*it != current_block_child)
+ continue;
+ current_block->children.insert(it, stmt);
+ break;
+ }
+ }
+ }
+
+ replace_fcall_with_id:
+ if (type == AST_FCALL) {
+ delete_children();
+ type = AST_IDENTIFIER;
+ str = prefix + str;
+ }
+ if (type == AST_TCALL)
+ str = "";
+ did_something = true;
+ }
+
+ // perform const folding when activated
+ if (const_fold && newNode == NULL)
+ {
+ RTLIL::Const (*const_func)(const RTLIL::Const&, const RTLIL::Const&, bool, bool, int);
+ RTLIL::Const dummy_arg;
+
+ switch (type)
+ {
+ case AST_IDENTIFIER:
+ if (current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM)) {
+ if (children.size() != 0 && children[0]->type == AST_RANGE && children[0]->range_valid) {
+ if (current_scope[str]->children[0]->type == AST_CONSTANT) {
+ 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]);
+ newNode = mkconst_bits(data, false);
+ }
+ } else
+ if (children.size() == 0)
+ newNode = current_scope[str]->children[0]->clone();
+ }
+ else if (at_zero && current_module->wires.count(str) > 0) {
+ assert(current_scope.count(str) > 0 && (current_scope[str]->type == AST_WIRE || current_scope[str]->type == AST_AUTOWIRE));
+ if (children.size() != 0 && children[0]->type == AST_RANGE && children[0]->range_valid)
+ newNode = mkconst_int(0, false, children[0]->range_left - children[0]->range_right + 1);
+ else
+ if (children.size() == 0)
+ newNode = mkconst_int(0, current_scope[str]->is_signed, current_module->wires[str]->width);
+ }
+ break;
+ case AST_BIT_NOT:
+ if (children[0]->type == AST_CONSTANT) {
+ RTLIL::Const y = RTLIL::const_not(RTLIL::Const(children[0]->bits), dummy_arg, children[0]->is_signed, false, -1);
+ newNode = mkconst_bits(y.bits, false);
+ }
+ break;
+ if (0) { case AST_BIT_AND: const_func = RTLIL::const_and; }
+ if (0) { case AST_BIT_OR: const_func = RTLIL::const_or; }
+ if (0) { case AST_BIT_XOR: const_func = RTLIL::const_xor; }
+ if (0) { case AST_BIT_XNOR: const_func = RTLIL::const_xnor; }
+ if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) {
+ 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);
+ }
+ break;
+ if (0) { case AST_REDUCE_AND: const_func = RTLIL::const_reduce_and; }
+ if (0) { case AST_REDUCE_OR: const_func = RTLIL::const_reduce_or; }
+ if (0) { case AST_REDUCE_XOR: const_func = RTLIL::const_reduce_xor; }
+ if (0) { case AST_REDUCE_XNOR: const_func = RTLIL::const_reduce_xnor; }
+ if (0) { case AST_REDUCE_BOOL: const_func = RTLIL::const_reduce_bool; }
+ if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) {
+ RTLIL::Const y = const_func(RTLIL::Const(children[0]->bits), dummy_arg, children[0]->is_signed, false, -1);
+ newNode = mkconst_bits(y.bits, false);
+ }
+ break;
+ case AST_LOGIC_NOT:
+ 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);
+ }
+ break;
+ if (0) { case AST_LOGIC_AND: const_func = RTLIL::const_logic_and; }
+ if (0) { case AST_LOGIC_OR: const_func = RTLIL::const_logic_or; }
+ if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) {
+ 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);
+ }
+ break;
+ if (0) { case AST_SHIFT_LEFT: const_func = RTLIL::const_shl; }
+ if (0) { case AST_SHIFT_RIGHT: const_func = RTLIL::const_shr; }
+ if (0) { case AST_SHIFT_SLEFT: const_func = RTLIL::const_sshl; }
+ if (0) { case AST_SHIFT_SRIGHT: const_func = RTLIL::const_sshr; }
+ if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) {
+ RTLIL::Const y = const_func(RTLIL::Const(children[0]->bits), RTLIL::Const(children[1]->bits), children[0]->is_signed, false, -1);
+ newNode = mkconst_bits(y.bits, children[0]->is_signed);
+ }
+ break;
+ if (0) { case AST_LT: const_func = RTLIL::const_lt; }
+ if (0) { case AST_LE: const_func = RTLIL::const_le; }
+ if (0) { case AST_EQ: const_func = RTLIL::const_eq; }
+ if (0) { case AST_NE: const_func = RTLIL::const_ne; }
+ if (0) { case AST_GE: const_func = RTLIL::const_ge; }
+ if (0) { case AST_GT: const_func = RTLIL::const_gt; }
+ if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) {
+ 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);
+ }
+ break;
+ if (0) { case AST_ADD: const_func = RTLIL::const_add; }
+ if (0) { case AST_SUB: const_func = RTLIL::const_sub; }
+ if (0) { case AST_MUL: const_func = RTLIL::const_mul; }
+ if (0) { case AST_DIV: const_func = RTLIL::const_div; }
+ if (0) { case AST_MOD: const_func = RTLIL::const_mod; }
+ if (0) { case AST_POW: const_func = RTLIL::const_pow; }
+ if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) {
+ 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, children[0]->is_signed && children[1]->is_signed);
+ }
+ break;
+ if (0) { case AST_POS: const_func = RTLIL::const_pos; }
+ if (0) { case AST_NEG: const_func = RTLIL::const_neg; }
+ if (children[0]->type == AST_CONSTANT) {
+ RTLIL::Const y = const_func(RTLIL::Const(children[0]->bits), dummy_arg, children[0]->is_signed, false, -1);
+ newNode = mkconst_bits(y.bits, children[0]->is_signed);
+ }
+ break;
+ case AST_TERNARY:
+ if (children[0]->type == AST_CONSTANT) {
+ if (children[0]->integer)
+ newNode = children[1]->clone();
+ else
+ newNode = children[2]->clone();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // if any of the above set 'newNode' -> use 'newNode' as template to update 'this'
+ if (newNode) {
+apply_newNode:
+ // fprintf(stderr, "----\n");
+ // dumpAst(stderr, "- ");
+ // newNode->dumpAst(stderr, "+ ");
+ assert(newNode != NULL);
+ newNode->filename = filename;
+ newNode->linenum = linenum;
+ newNode->cloneInto(this);
+ delete newNode;
+ did_something = true;
+ }
+
+ return did_something;
+}
+
+// annotate the names of all wires and other named objects in a generate block
+void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map)
+{
+ if (!index_var.empty() && type == AST_IDENTIFIER && str == index_var) {
+ current_scope[index_var]->children[0]->cloneInto(this);
+ return;
+ }
+
+ if ((type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL) && name_map.count(str) > 0) {
+ str = name_map[str];
+ return;
+ }
+
+ std::map<std::string, std::string> backup_name_map;
+
+ for (size_t i = 0; i < children.size(); i++) {
+ AstNode *child = children[i];
+ if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM ||
+ child->type == AST_FUNCTION || child->type == AST_TASK || child->type == AST_CELL) {
+ if (backup_name_map.size() == 0)
+ backup_name_map = name_map;
+ std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix;
+ size_t pos = child->str.rfind('.');
+ if (pos == std::string::npos)
+ pos = child->str[0] == '\\' ? 1 : 0;
+ else
+ pos = pos + 1;
+ new_name = child->str.substr(0, pos) + new_name + child->str.substr(pos);
+ if (new_name[0] != '$' && new_name[0] != '\\')
+ new_name = prefix[0] + new_name;
+ name_map[child->str] = new_name;
+ child->str = new_name;
+ }
+ }
+
+ for (size_t i = 0; i < children.size(); i++) {
+ AstNode *child = children[i];
+ if (child->type != AST_FUNCTION && child->type != AST_TASK)
+ child->expand_genblock(index_var, prefix, name_map);
+ }
+
+ if (backup_name_map.size() > 0)
+ name_map.swap(backup_name_map);
+}
+
+// rename stuff (used when tasks of functions are instanciated)
+void AstNode::replace_ids(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);
+}
+
+// find memories that should be replaced by registers
+void AstNode::mem2reg_as_needed_pass1(std::set<AstNode*> &mem2reg_set, std::set<AstNode*> &mem2reg_candidates, bool sync_proc, bool async_proc)
+{
+ if ((type == AST_ASSIGN_LE && async_proc) || (type == AST_ASSIGN_EQ && (sync_proc || async_proc)))
+ if (children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY &&
+ children[0]->id2ast->attributes.count("\\nomem2reg") == 0) {
+ if (async_proc || mem2reg_candidates.count(children[0]->id2ast) > 0) {
+ if (mem2reg_set.count(children[0]->id2ast) == 0)
+ log("Warning: Replacing memory %s with list of registers because of assignment in line %s:%d.\n",
+ children[0]->str.c_str(), filename.c_str(), linenum);
+ mem2reg_set.insert(children[0]->id2ast);
+ }
+ mem2reg_candidates.insert(children[0]->id2ast);
+ }
+
+ if (type == AST_ALWAYS) {
+ for (auto child : children) {
+ if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE)
+ sync_proc = true;
+ }
+ async_proc = !sync_proc;
+ }
+
+ for (auto child : children)
+ child->mem2reg_as_needed_pass1(mem2reg_set, mem2reg_candidates, sync_proc, async_proc);
+}
+
+// actually replace memories with registers
+void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
+{
+ if (type == AST_BLOCK)
+ block = this;
+
+ if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && block != NULL &&
+ children[0]->id2ast && mem2reg_set.count(children[0]->id2ast) > 0)
+ {
+ std::stringstream sstr;
+ sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+ std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA";
+
+ int mem_width, mem_size, addr_bits;
+ children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
+
+ AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true)));
+ wire_addr->str = id_addr;
+ wire_addr->is_reg = true;
+ mod->children.push_back(wire_addr);
+
+ 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;
+ mod->children.push_back(wire_data);
+
+ 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());
+
+ 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;
+ block->children.insert(block->children.begin()+assign_idx+1, assign_addr);
+
+ AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER));
+ case_node->children[0]->str = id_addr;
+ for (int i = 0; i < mem_size; i++) {
+ if (children[0]->children[0]->children[0]->type == AST_CONSTANT && int(children[0]->children[0]->children[0]->integer) != i)
+ continue;
+ AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK));
+ AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER));
+ assign_reg->children[0]->str = 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);
+ case_node->children.push_back(cond_node);
+ }
+ block->children.insert(block->children.begin()+assign_idx+2, case_node);
+
+ children[0]->delete_children();
+ children[0]->range_valid = false;
+ children[0]->id2ast = NULL;
+ children[0]->str = id_data;
+ }
+
+ if (type == AST_IDENTIFIER && id2ast && mem2reg_set.count(id2ast) > 0)
+ {
+ std::stringstream sstr;
+ sstr << "$mem2reg_rd$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+ std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA";
+
+ int mem_width, mem_size, addr_bits;
+ id2ast->meminfo(mem_width, mem_size, addr_bits);
+
+ AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true)));
+ wire_addr->str = id_addr;
+ mod->children.push_back(wire_addr);
+
+ 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;
+ mod->children.push_back(wire_data);
+
+ AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone());
+ assign_addr->children[0]->str = id_addr;
+
+ AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER));
+ case_node->children[0]->str = id_addr;
+
+ for (int i = 0; i < mem_size; i++) {
+ if (children[0]->children[0]->type == AST_CONSTANT && int(children[0]->children[0]->integer) != i)
+ continue;
+ AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK));
+ AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER));
+ assign_reg->children[0]->str = id_data;
+ assign_reg->children[1]->str = stringf("%s[%d]", str.c_str(), i);
+ cond_node->children[1]->children.push_back(assign_reg);
+ case_node->children.push_back(cond_node);
+ }
+
+ std::vector<RTLIL::State> x_bits;
+ x_bits.push_back(RTLIL::State::Sx);
+ AstNode *cond_node = new AstNode(AST_COND, new AstNode(AST_DEFAULT), new AstNode(AST_BLOCK));
+ AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false));
+ assign_reg->children[0]->str = id_data;
+ cond_node->children[1]->children.push_back(assign_reg);
+ case_node->children.push_back(cond_node);
+
+ if (block)
+ {
+ 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());
+ block->children.insert(block->children.begin()+assign_idx, case_node);
+ block->children.insert(block->children.begin()+assign_idx, assign_addr);
+ wire_addr->is_reg = true;
+ wire_data->is_reg = true;
+ }
+ else
+ {
+ AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK));
+ proc->children[0]->children.push_back(case_node);
+ mod->children.push_back(proc);
+ mod->children.push_back(assign_addr);
+ }
+
+ delete_children();
+ range_valid = false;
+ id2ast = NULL;
+ str = id_data;
+ }
+
+ assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0);
+
+ for (size_t i = 0; i < children.size(); i++)
+ children[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block);
+}
+
+// calulate memory dimensions
+void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits)
+{
+ 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;
+
+ if (mem_size < 0)
+ mem_size *= -1;
+ mem_size += std::min(children[1]->range_left, children[1]->range_right) + 1;
+
+ addr_bits = 1;
+ while ((1 << addr_bits) < mem_size)
+ addr_bits++;
+}
+
diff --git a/frontends/ilang/Makefile.inc b/frontends/ilang/Makefile.inc
new file mode 100644
index 00000000..07ebf085
--- /dev/null
+++ b/frontends/ilang/Makefile.inc
@@ -0,0 +1,16 @@
+
+GENFILES += frontends/ilang/parser.tab.cc
+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/lexer.cc: frontends/ilang/lexer.l
+ 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
new file mode 100644
index 00000000..f3ad3a19
--- /dev/null
+++ b/frontends/ilang/ilang_frontend.cc
@@ -0,0 +1,49 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * ---
+ *
+ * A very simple and straightforward frontend for the RTLIL text
+ * representation (as generated by the 'ilang' backend).
+ *
+ */
+
+#include "ilang_frontend.h"
+#include "kernel/register.h"
+#include "kernel/log.h"
+
+void rtlil_frontend_ilang_yyerror(char const *s)
+{
+ log_error("Parser error in line %d: %s\n", rtlil_frontend_ilang_yyget_lineno(), s);
+}
+
+struct IlangFrontend : public Frontend {
+ IlangFrontend() : Frontend("ilang") { }
+ virtual void execute(FILE *&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::current_design = design;
+ rtlil_frontend_ilang_yydebug = false;
+ rtlil_frontend_ilang_yyrestart(f);
+ rtlil_frontend_ilang_yyparse();
+ rtlil_frontend_ilang_yylex_destroy();
+ }
+} IlangFrontend;
+
diff --git a/frontends/ilang/ilang_frontend.h b/frontends/ilang/ilang_frontend.h
new file mode 100644
index 00000000..5e768c3b
--- /dev/null
+++ b/frontends/ilang/ilang_frontend.h
@@ -0,0 +1,45 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * ---
+ *
+ * A very simple and straightforward frontend for the RTLIL text
+ * representation (as generated by the 'ilang' backend).
+ *
+ */
+
+#ifndef ILANG_FRONTEND_H
+#define ILANG_FRONTEND_H
+
+#include "kernel/rtlil.h"
+#include <stdio.h>
+
+namespace ILANG_FRONTEND {
+ void ilang_frontend(FILE *f, RTLIL::Design *design);
+ extern RTLIL::Design *current_design;
+}
+
+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_yyget_lineno(void);
+
+#endif
+
diff --git a/frontends/ilang/lexer.l b/frontends/ilang/lexer.l
new file mode 100644
index 00000000..e331c267
--- /dev/null
+++ b/frontends/ilang/lexer.l
@@ -0,0 +1,122 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * ---
+ *
+ * A very simple and straightforward frontend for the RTLIL text
+ * representation (as generated by the 'ilang' backend).
+ *
+ */
+
+%{
+#include "kernel/rtlil.h"
+#include "parser.tab.h"
+%}
+
+%option yylineno
+%option noyywrap
+%option nounput
+%option prefix="rtlil_frontend_ilang_yy"
+
+%x STRING
+
+%%
+
+"module" { return TOK_MODULE; }
+"attribute" { return TOK_ATTRIBUTE; }
+"parameter" { return TOK_PARAMETER; }
+"wire" { return TOK_WIRE; }
+"memory" { return TOK_MEMORY; }
+"auto" { return TOK_AUTO; }
+"width" { return TOK_WIDTH; }
+"offset" { return TOK_OFFSET; }
+"size" { return TOK_SIZE; }
+"input" { return TOK_INPUT; }
+"output" { return TOK_OUTPUT; }
+"inout" { return TOK_INOUT; }
+"cell" { return TOK_CELL; }
+"connect" { return TOK_CONNECT; }
+"switch" { return TOK_SWITCH; }
+"case" { return TOK_CASE; }
+"assign" { return TOK_ASSIGN; }
+"sync" { return TOK_SYNC; }
+"low" { return TOK_LOW; }
+"high" { return TOK_HIGH; }
+"posedge" { return TOK_POSEDGE; }
+"negedge" { return TOK_NEGEDGE; }
+"edge" { return TOK_EDGE; }
+"always" { return TOK_ALWAYS; }
+"update" { return TOK_UPDATE; }
+"process" { return TOK_PROCESS; }
+"end" { return TOK_END; }
+
+[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); 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; }
+
+\" { BEGIN(STRING); }
+<STRING>\\. { yymore(); }
+<STRING>\" {
+ BEGIN(0);
+ char *yystr = strdup(yytext);
+ yystr[strlen(yytext) - 1] = 0;
+ int i = 0, j = 0;
+ while (yystr[i]) {
+ if (yystr[i] == '\\' && yystr[i + 1]) {
+ i++;
+ if (yystr[i] == 'n')
+ yystr[i] = '\n';
+ else if (yystr[i] == 't')
+ yystr[i] = '\t';
+ else if ('0' <= yystr[i] && yystr[i] <= '7') {
+ yystr[i] = yystr[i] - '0';
+ if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') {
+ yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0';
+ i++;
+ }
+ if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') {
+ yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0';
+ i++;
+ }
+ }
+ }
+ yystr[j++] = yystr[i++];
+ }
+ yystr[j] = 0;
+ rtlil_frontend_ilang_yylval.string = yystr;
+ return TOK_STRING;
+}
+<STRING>. { yymore(); }
+
+"#"[^\n]*\n /* ignore comments */
+[ \t] /* ignore non-newline whitespaces */
+[\r\n]+ { return TOK_EOL; }
+
+. { return *yytext; }
+
+%%
+
+// 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
new file mode 100644
index 00000000..61bac830
--- /dev/null
+++ b/frontends/ilang/parser.y
@@ -0,0 +1,416 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * ---
+ *
+ * A very simple and straightforward frontend for the RTLIL text
+ * representation (as generated by the 'ilang' backend).
+ *
+ */
+
+%{
+#include <list>
+#include "ilang_frontend.h"
+namespace ILANG_FRONTEND {
+ RTLIL::Design *current_design;
+ RTLIL::Module *current_module;
+ RTLIL::Wire *current_wire;
+ RTLIL::Memory *current_memory;
+ RTLIL::Cell *current_cell;
+ RTLIL::Process *current_process;
+ std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
+ std::vector<RTLIL::CaseRule*> case_stack;
+ std::map<RTLIL::IdString, RTLIL::Const> attrbuf;
+}
+using namespace ILANG_FRONTEND;
+%}
+
+%name-prefix="rtlil_frontend_ilang_yy"
+
+%union {
+ char *string;
+ int integer;
+ RTLIL::Const *data;
+ 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_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
+%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS
+%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
+%token TOK_PARAMETER TOK_ATTRIBUTE TOK_AUTO TOK_MEMORY TOK_SIZE
+
+%type <sigspec> sigspec sigspec_list
+%type <integer> sync_type
+%type <data> constant
+
+%expect 0
+%debug
+
+%%
+
+input:
+ optional_eol {
+ attrbuf.clear();
+ } design {
+ if (attrbuf.size() != 0)
+ rtlil_frontend_ilang_yyerror("dangling attribute");
+ };
+
+optional_eol:
+ optional_eol TOK_EOL | /* empty */;
+
+design:
+ design module |
+ design attr_stmt |
+ /* empty */;
+
+module:
+ TOK_MODULE TOK_ID TOK_EOL {
+ if (current_design->modules.count($2) != 0)
+ rtlil_frontend_ilang_yyerror("scope error");
+ current_module = new RTLIL::Module;
+ current_module->name = $2;
+ current_module->attributes = attrbuf;
+ current_design->modules[$2] = current_module;
+ attrbuf.clear();
+ free($2);
+ } module_body TOK_END {
+ if (attrbuf.size() != 0)
+ rtlil_frontend_ilang_yyerror("dangling attribute");
+ } TOK_EOL;
+
+module_body:
+ module_body module_stmt |
+ /* empty */;
+
+module_stmt:
+ attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt;
+
+attr_stmt:
+ TOK_ATTRIBUTE TOK_ID constant TOK_EOL {
+ attrbuf[$2] = *$3;
+ delete $3;
+ };
+
+wire_stmt:
+ TOK_WIRE {
+ current_wire = new RTLIL::Wire;
+ current_wire->attributes = attrbuf;
+ attrbuf.clear();
+ } wire_options TOK_ID TOK_EOL {
+ if (current_module->wires.count($4) != 0)
+ rtlil_frontend_ilang_yyerror("scope error");
+ current_wire->name = $4;
+ current_module->wires[$4] = current_wire;
+ free($4);
+ };
+
+wire_options:
+ wire_options TOK_AUTO {
+ current_wire->auto_width = true;
+ } |
+ wire_options TOK_WIDTH TOK_INT {
+ current_wire->width = $3;
+ } |
+ wire_options TOK_OFFSET TOK_INT {
+ current_wire->start_offset = $3;
+ } |
+ wire_options TOK_INPUT TOK_INT {
+ current_wire->port_id = $3;
+ current_wire->port_input = true;
+ current_wire->port_output = false;
+ } |
+ wire_options TOK_OUTPUT TOK_INT {
+ current_wire->port_id = $3;
+ current_wire->port_input = false;
+ current_wire->port_output = true;
+ } |
+ wire_options TOK_INOUT TOK_INT {
+ current_wire->port_id = $3;
+ current_wire->port_input = true;
+ current_wire->port_output = true;
+ } |
+ /* empty */;
+
+memory_stmt:
+ TOK_MEMORY {
+ current_memory = new RTLIL::Memory;
+ current_memory->attributes = attrbuf;
+ attrbuf.clear();
+ } memory_options TOK_ID TOK_EOL {
+ if (current_module->memories.count($4) != 0)
+ rtlil_frontend_ilang_yyerror("scope error");
+ current_memory->name = $4;
+ current_module->memories[$4] = current_memory;
+ free($4);
+ };
+
+memory_options:
+ memory_options TOK_WIDTH TOK_INT {
+ current_wire->width = $3;
+ } |
+ memory_options TOK_SIZE TOK_INT {
+ current_memory->size = $3;
+ } |
+ /* empty */;
+
+cell_stmt:
+ TOK_CELL TOK_ID TOK_ID TOK_EOL {
+ if (current_module->cells.count($3) != 0)
+ rtlil_frontend_ilang_yyerror("scope error");
+ current_cell = new RTLIL::Cell;
+ current_cell->type = $2;
+ current_cell->name = $3;
+ current_cell->attributes = attrbuf;
+ current_module->cells[$3] = current_cell;
+ attrbuf.clear();
+ free($2);
+ free($3);
+ } cell_body TOK_END TOK_EOL;
+
+cell_body:
+ cell_body TOK_PARAMETER TOK_ID constant TOK_EOL {
+ current_cell->parameters[$3] = *$4;
+ free($3);
+ delete $4;
+ } |
+ cell_body TOK_CONNECT TOK_ID sigspec TOK_EOL {
+ if (current_cell->connections.count($3) != 0)
+ rtlil_frontend_ilang_yyerror("scope error");
+ current_cell->connections[$3] = *$4;
+ delete $4;
+ free($3);
+ } |
+ /* empty */;
+
+proc_stmt:
+ TOK_PROCESS TOK_ID TOK_EOL {
+ if (current_module->processes.count($2) != 0)
+ rtlil_frontend_ilang_yyerror("scope error");
+ current_process = new RTLIL::Process;
+ current_process->name = $2;
+ current_process->attributes = attrbuf;
+ current_module->processes[$2] = current_process;
+ switch_stack.clear();
+ switch_stack.push_back(&current_process->root_case.switches);
+ case_stack.clear();
+ case_stack.push_back(&current_process->root_case);
+ free($2);
+ } case_body sync_list TOK_END TOK_EOL;
+
+switch_stmt:
+ attr_list TOK_SWITCH sigspec TOK_EOL {
+ RTLIL::SwitchRule *rule = new RTLIL::SwitchRule;
+ rule->signal = *$3;
+ rule->attributes = attrbuf;
+ switch_stack.back()->push_back(rule);
+ attrbuf.clear();
+ delete $3;
+ } switch_body TOK_END TOK_EOL;
+
+attr_list:
+ /* empty */ |
+ attr_list attr_stmt;
+
+switch_body:
+ switch_body TOK_CASE {
+ RTLIL::CaseRule *rule = new RTLIL::CaseRule;
+ switch_stack.back()->back()->cases.push_back(rule);
+ switch_stack.push_back(&rule->switches);
+ case_stack.push_back(rule);
+ } compare_list TOK_EOL case_body {
+ switch_stack.pop_back();
+ case_stack.pop_back();
+ } |
+ /* empty */;
+
+compare_list:
+ sigspec {
+ case_stack.back()->compare.push_back(*$1);
+ delete $1;
+ } |
+ compare_list ',' sigspec {
+ case_stack.back()->compare.push_back(*$3);
+ delete $3;
+ } |
+ /* empty */;
+
+case_body:
+ switch_stmt case_body |
+ assign_stmt case_body |
+ /* empty */;
+
+assign_stmt:
+ TOK_ASSIGN sigspec sigspec TOK_EOL {
+ case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3));
+ delete $2;
+ delete $3;
+ };
+
+sync_list:
+ sync_list TOK_SYNC sync_type sigspec TOK_EOL {
+ RTLIL::SyncRule *rule = new RTLIL::SyncRule;
+ rule->type = RTLIL::SyncType($3);
+ rule->signal = *$4;
+ current_process->syncs.push_back(rule);
+ delete $4;
+ } update_list |
+ sync_list TOK_SYNC TOK_ALWAYS TOK_EOL {
+ RTLIL::SyncRule *rule = new RTLIL::SyncRule;
+ rule->type = RTLIL::SyncType::STa;
+ rule->signal = RTLIL::SigSpec();
+ current_process->syncs.push_back(rule);
+ } update_list |
+ /* empty */;
+
+sync_type:
+ TOK_LOW { $$ = RTLIL::ST0; } |
+ TOK_HIGH { $$ = RTLIL::ST1; } |
+ TOK_POSEDGE { $$ = RTLIL::STp; } |
+ TOK_NEGEDGE { $$ = RTLIL::STn; } |
+ TOK_EDGE { $$ = RTLIL::STe; };
+
+update_list:
+ update_list TOK_UPDATE sigspec sigspec TOK_EOL {
+ current_process->syncs.back()->actions.push_back(RTLIL::SigSig(*$3, *$4));
+ delete $3;
+ delete $4;
+ } |
+ /* empty */;
+
+constant:
+ TOK_VALUE {
+ char *ep;
+ int width = strtol($1, &ep, 10);
+ std::list<RTLIL::State> bits;
+ while (*(++ep) != 0) {
+ RTLIL::State bit = RTLIL::Sx;
+ switch (*ep) {
+ case '0': bit = RTLIL::S0; break;
+ case '1': bit = RTLIL::S1; break;
+ case 'x': bit = RTLIL::Sx; break;
+ case 'z': bit = RTLIL::Sz; break;
+ case '-': bit = RTLIL::Sa; break;
+ case 'm': bit = RTLIL::Sm; break;
+ }
+ bits.push_front(bit);
+ }
+ if (bits.size() == 0)
+ bits.push_back(RTLIL::Sx);
+ while ((int)bits.size() < width) {
+ RTLIL::State bit = bits.back();
+ if (bit == RTLIL::S1)
+ bit = RTLIL::S0;
+ bits.push_back(bit);
+ }
+ while ((int)bits.size() > width)
+ bits.pop_back();
+ $$ = new RTLIL::Const;
+ for (auto it = bits.begin(); it != bits.end(); it++)
+ $$->bits.push_back(*it);
+ free($1);
+ } |
+ TOK_INT {
+ $$ = new RTLIL::Const($1, 32);
+ } |
+ TOK_STRING {
+ $$ = new RTLIL::Const($1);
+ free($1);
+ };
+
+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;
+ delete $1;
+ } |
+ TOK_ID {
+ if (current_module->wires.count($1) == 0)
+ rtlil_frontend_ilang_yyerror("scope error");
+ 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;
+ free($1);
+ } |
+ TOK_ID '[' TOK_INT ']' {
+ if (current_module->wires.count($1) == 0)
+ rtlil_frontend_ilang_yyerror("scope error");
+ RTLIL::SigChunk chunk;
+ chunk.wire = current_module->wires[$1];
+ chunk.offset = $3;
+ chunk.width = 1;
+ $$ = new RTLIL::SigSpec;
+ $$->chunks.push_back(chunk);
+ $$->width = 1;
+ free($1);
+ } |
+ TOK_ID '[' TOK_INT ':' TOK_INT ']' {
+ if (current_module->wires.count($1) == 0)
+ rtlil_frontend_ilang_yyerror("scope error");
+ 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;
+ free($1);
+ } |
+ '{' sigspec_list '}' {
+ $$ = $2;
+ };
+
+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;
+ }
+ delete $1;
+ delete $2;
+ } |
+ /* empty */ {
+ $$ = new RTLIL::SigSpec;
+ };
+
+conn_stmt:
+ TOK_CONNECT sigspec sigspec TOK_EOL {
+ if (attrbuf.size() != 0)
+ rtlil_frontend_ilang_yyerror("dangling attribute");
+ current_module->connections.push_back(RTLIL::SigSig(*$2, *$3));
+ delete $2;
+ delete $3;
+ };
+
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc
new file mode 100644
index 00000000..6693f2d1
--- /dev/null
+++ b/frontends/verilog/Makefile.inc
@@ -0,0 +1,19 @@
+
+GENFILES += frontends/verilog/parser.tab.cc
+GENFILES += frontends/verilog/parser.tab.h
+GENFILES += frontends/verilog/parser.output
+GENFILES += frontends/verilog/lexer.cc
+
+frontends/verilog/parser.tab.cc frontends/verilog/parser.tab.h: 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
+
+frontends/verilog/lexer.cc: frontends/verilog/lexer.l
+ flex -o frontends/verilog/lexer.cc frontends/verilog/lexer.l
+
+OBJS += frontends/verilog/parser.tab.o
+OBJS += frontends/verilog/lexer.o
+OBJS += frontends/verilog/preproc.o
+OBJS += frontends/verilog/verilog_frontend.o
+OBJS += frontends/verilog/const2ast.o
+
diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
new file mode 100644
index 00000000..e5beaead
--- /dev/null
+++ b/frontends/verilog/const2ast.cc
@@ -0,0 +1,197 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * ---
+ *
+ * The Verilog frontend.
+ *
+ * This frontend is using the AST frontend library (see frontends/ast/).
+ * Thus this frontend does not generate RTLIL code directly but creates an
+ * AST directly from the Verilog parse tree and then passes this AST to
+ * the AST frontend library.
+ *
+ * ---
+ *
+ * This file contains an ad-hoc parser for Verilog constants. The Verilog
+ * lexer does only recognize a constant but does not actually split it to its
+ * components. I.e. it just passes the Verilog code for the constant to the
+ * bison parser. The parser then uses the function const2ast() from this file
+ * to create an AST node for the constant.
+ *
+ */
+
+#include "verilog_frontend.h"
+#include "kernel/log.h"
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+
+using namespace AST;
+
+// divide an arbitrary length decimal number by two and return the rest
+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);
+ digits[i] += carry * 10;
+ carry = digits[i] % 2;
+ digits[i] /= 2;
+ }
+ return carry;
+}
+
+// find the number of significant bits in a binary number (not including the sign bit)
+static int my_ilog2(int x)
+{
+ int ret = 0;
+ while (x != 0 && x != -1) {
+ x = x >> 1;
+ ret++;
+ }
+ return ret;
+}
+
+// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
+static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type)
+{
+ // all digits in string (MSB at index 0)
+ std::vector<uint8_t> digits;
+
+ while (*str) {
+ if ('0' <= *str && *str <= '9')
+ digits.push_back(*str - '0');
+ else if ('a' <= *str && *str <= 'f')
+ digits.push_back(10 + *str - 'a');
+ else if ('A' <= *str && *str <= 'F')
+ digits.push_back(10 + *str - 'A');
+ else if (*str == 'x' || *str == 'X')
+ digits.push_back(0xf0);
+ else if (*str == 'z' || *str == 'Z')
+ digits.push_back(0xf1);
+ else if (*str == '?')
+ digits.push_back(0xf2);
+ str++;
+ }
+
+ 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);
+ return;
+ }
+
+ int bits_per_digit = my_ilog2(base-1);
+ if (len_in_bits < 0)
+ len_in_bits = digits.size() * bits_per_digit;
+
+ data.clear();
+ data.resize(len_in_bits);
+
+ for (int i = 0; i < len_in_bits; i++) {
+ int bitmask = 1 << (i % bits_per_digit);
+ int digitidx = digits.size() - (i / bits_per_digit) - 1;
+ if (digitidx < 0) {
+ if (i > 0 && (data[i-1] == RTLIL::Sz || data[i-1] == RTLIL::Sx || data[i-1] == RTLIL::Sa))
+ data[i] = data[i-1];
+ else
+ data[i] = RTLIL::S0;
+ } else if (digits[digitidx] == 0xf0)
+ data[i] = case_type == 'x' ? RTLIL::Sa : RTLIL::Sx;
+ else if (digits[digitidx] == 0xf1)
+ data[i] = case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz;
+ else if (digits[digitidx] == 0xf2)
+ data[i] = RTLIL::Sa;
+ else
+ data[i] = (digits[digitidx] & bitmask) ? RTLIL::S1 : RTLIL::S0;
+ }
+}
+
+// convert the verilog code for a constant to an AST node
+AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
+{
+ const char *str = code.c_str();
+
+ // Strings
+ if (*str == '"') {
+ int len = strlen(str) - 2;
+ std::vector<RTLIL::State> data;
+ data.reserve(len * 8);
+ for (int i = 0; i < len; i++) {
+ unsigned char ch = str[len - i];
+ for (int j = 0; j < 8; j++) {
+ data.push_back((ch & 1) ? RTLIL::S1 : RTLIL::S0);
+ ch = ch >> 1;
+ }
+ }
+ AstNode *ast = AstNode::mkconst_bits(data, false);
+ ast->str = code;
+ return ast;
+ }
+
+ for (size_t i = 0; i < code.size(); i++)
+ if (code[i] == '_' || code[i] == ' ' || code[i] == '\t' || code[i] == '\r' || code[i] == '\n')
+ code.erase(code.begin()+(i--));
+ str = code.c_str();
+
+ char *endptr;
+ long intval = strtol(str, &endptr, 10);
+
+ // Simple 32 bit integer
+ if (*endptr == 0)
+ return AstNode::mkconst_int(intval, true);
+
+ // variable length constant
+ if (str == endptr)
+ intval = -1;
+
+ // The "<bits>'[bodh]<digits>" syntax
+ if (*endptr == '\'')
+ {
+ int len_in_bits = intval;
+ std::vector<RTLIL::State> data;
+ bool is_signed = false;
+ if (*(endptr+1) == 's') {
+ is_signed = true;
+ endptr++;
+ }
+ switch (*(endptr+1))
+ {
+ case 'b':
+ my_strtobin(data, endptr+2, len_in_bits, 2, case_type);
+ break;
+ case 'o':
+ my_strtobin(data, endptr+2, len_in_bits, 8, case_type);
+ break;
+ case 'd':
+ my_strtobin(data, endptr+2, len_in_bits, 10, case_type);
+ break;
+ case 'h':
+ my_strtobin(data, endptr+2, len_in_bits, 16, case_type);
+ break;
+ default:
+ goto error;
+ }
+ return AstNode::mkconst_bits(data, is_signed);
+ }
+
+error:
+ log_error("Value conversion failed: `%s'\n", code.c_str());
+}
+
diff --git a/frontends/verilog/lexer.l b/frontends/verilog/lexer.l
new file mode 100644
index 00000000..a269c072
--- /dev/null
+++ b/frontends/verilog/lexer.l
@@ -0,0 +1,264 @@
+/*
+ * 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 Verilog frontend.
+ *
+ * This frontend is using the AST frontend library (see frontends/ast/).
+ * Thus this frontend does not generate RTLIL code directly but creates an
+ * AST directly from the Verilog parse tree and then passes this AST to
+ * the AST frontend library.
+ *
+ * ---
+ *
+ * A simple lexer for Verilog code. Non-preprocessor compiler directives are
+ * handled here. The preprocessor stuff is handled in preproc.cc. Everything
+ * else is left to the bison parser (see parser.y).
+ *
+ */
+
+%{
+
+#include "kernel/log.h"
+#include "verilog_frontend.h"
+#include "frontends/ast/ast.h"
+#include "parser.tab.h"
+
+using namespace AST;
+using namespace VERILOG_FRONTEND;
+
+namespace VERILOG_FRONTEND {
+ std::vector<std::string> fn_stack;
+ std::vector<int> ln_stack;
+ bool lexer_feature_defattr;
+}
+
+%}
+
+%option yylineno
+%option noyywrap
+%option nounput
+%option prefix="frontend_verilog_yy"
+
+%x COMMENT
+%x STRING
+%x SYNOPSYS_TRANSLATE_OFF
+%x SYNOPSYS_FLAGS
+
+%%
+
+"`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 {
+ current_filename = fn_stack.back();
+ frontend_verilog_yyset_lineno(ln_stack.back());
+}
+
+"`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 */
+
+"`yosys_enable_defattr" lexer_feature_defattr = true;
+"`yosys_disable_defattr" lexer_feature_defattr = false;
+
+"`"[a-zA-Z_$][a-zA-Z0-9_$]* {
+ frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext);
+}
+
+"module" { return TOK_MODULE; }
+"endmodule" { return TOK_ENDMODULE; }
+"function" { return TOK_FUNCTION; }
+"endfunction" { return TOK_ENDFUNCTION; }
+"task" { return TOK_TASK; }
+"endtask" { return TOK_ENDTASK; }
+"parameter" { return TOK_PARAMETER; }
+"localparam" { return TOK_LOCALPARAM; }
+"assign" { return TOK_ASSIGN; }
+"always" { return TOK_ALWAYS; }
+"initial" { return TOK_INITIAL; }
+"begin" { return TOK_BEGIN; }
+"end" { return TOK_END; }
+"if" { return TOK_IF; }
+"else" { return TOK_ELSE; }
+"for" { return TOK_FOR; }
+"posedge" { return TOK_POSEDGE; }
+"negedge" { return TOK_NEGEDGE; }
+"or" { return TOK_OR; }
+"case" { return TOK_CASE; }
+"casex" { return TOK_CASEX; }
+"casez" { return TOK_CASEZ; }
+"endcase" { return TOK_ENDCASE; }
+"default" { return TOK_DEFAULT; }
+"generate" { return TOK_GENERATE; }
+"endgenerate" { return TOK_ENDGENERATE; }
+
+"input" { return TOK_INPUT; }
+"output" { return TOK_OUTPUT; }
+"inout" { return TOK_INOUT; }
+"wire" { return TOK_WIRE; }
+"reg" { return TOK_REG; }
+"integer" { return TOK_INTEGER; }
+"signed" { return TOK_SIGNED; }
+"genvar" { return TOK_GENVAR; }
+
+[0-9]+ {
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_CONST;
+}
+
+[0-9]*[ \t]*\'s?[bodh][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_CONST;
+}
+
+\" { BEGIN(STRING); }
+<STRING>\\. { yymore(); }
+<STRING>\" {
+ BEGIN(0);
+ char *yystr = strdup(yytext);
+ yystr[strlen(yytext) - 1] = 0;
+ int i = 0, j = 0;
+ while (yystr[i]) {
+ if (yystr[i] == '\\' && yystr[i + 1]) {
+ i++;
+ if (yystr[i] == 'n')
+ yystr[i] = '\n';
+ else if (yystr[i] == 't')
+ yystr[i] = '\t';
+ else if ('0' <= yystr[i] && yystr[i] <= '7') {
+ yystr[i] = yystr[i] - '0';
+ if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') {
+ yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0';
+ i++;
+ }
+ if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') {
+ yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0';
+ i++;
+ }
+ }
+ }
+ yystr[j++] = yystr[i++];
+ }
+ yystr[j] = 0;
+ frontend_verilog_yylval.string = new std::string(yystr);
+ free(yystr);
+ return TOK_STRING;
+}
+<STRING>. { yymore(); }
+
+and|nand|or|nor|xor|xnor|not|buf {
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_PRIMITIVE;
+}
+
+supply0 { return TOK_SUPPLY0; }
+supply1 { return TOK_SUPPLY1; }
+
+"$"(display|time|stop|finish) {
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_ID;
+}
+
+"$signed" { return TOK_TO_SIGNED; }
+"$unsigned" { return TOK_TO_UNSIGNED; }
+
+[a-zA-Z_$][a-zA-Z0-9_$]* {
+ frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
+ return TOK_ID;
+}
+
+"/*"[ \t]*synopsys[ \t]*translate_off[ \t]*"*/" {
+ log("Warning: Found one of those horrible `synopsys translate_off' comments.\n");
+ log("It is strongly suggested to use `ifdef constructs instead!\n");
+ BEGIN(SYNOPSYS_TRANSLATE_OFF);
+}
+<SYNOPSYS_TRANSLATE_OFF>. /* ignore synopsys translate_off body */
+<SYNOPSYS_TRANSLATE_OFF>\n /* ignore synopsys translate_off body */
+<SYNOPSYS_TRANSLATE_OFF>"/*"[ \t]*"synopsys"[ \t]*"translate_on"[ \t]*"*/" { BEGIN(0); }
+
+"/*"[ \t]*"synopsys"[ \t]+ {
+ BEGIN(SYNOPSYS_FLAGS);
+}
+<SYNOPSYS_FLAGS>full_case {
+ log("Warning: Found one of those horrible `synopsys full_case' comments.\n");
+ log("It is strongly suggested to use verilog x-values and default branches instead!\n");
+ return TOK_SYNOPSYS_FULL_CASE;
+}
+<SYNOPSYS_FLAGS>parallel_case {
+ log("Warning: Found one of those horrible `synopsys parallel_case' comments.\n");
+ log("It is strongly suggested to use verilog `parallel_case' attributes instead!\n");
+ return TOK_SYNOPSYS_PARALLEL_CASE;
+}
+<SYNOPSYS_FLAGS>. /* ignore everything else */
+<SYNOPSYS_FLAGS>"*/" { BEGIN(0); }
+
+"\\"[^ \t\r\n]+ {
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_ID;
+}
+
+"(*" { return ATTR_BEGIN; }
+"*)" { return ATTR_END; }
+
+"{*" { if (lexer_feature_defattr) return DEFATTR_BEGIN; else REJECT; }
+"*}" { if (lexer_feature_defattr) return DEFATTR_END; else REJECT; }
+
+"**" { return OP_POW; }
+"||" { return OP_LOR; }
+"&&" { return OP_LAND; }
+"==" { return OP_EQ; }
+"!=" { return OP_NE; }
+"<=" { return OP_LE; }
+">=" { return OP_GE; }
+
+ /* "~&" { return OP_NAND; } */
+ /* "~|" { return OP_NOR; } */
+"~^" { return OP_XNOR; }
+"^~" { return OP_XNOR; }
+
+"<<" { return OP_SHL; }
+">>" { return OP_SHR; }
+"<<<" { return OP_SSHL; }
+">>>" { return OP_SSHR; }
+
+"/*" { BEGIN(COMMENT); }
+<COMMENT>. /* ignore comment body */
+<COMMENT>\n /* ignore comment body */
+<COMMENT>"*/" { BEGIN(0); }
+
+[ \t\r\n] /* ignore whitespaces */
+\\[\r\n] /* ignore continuation sequence */
+"//"[^\r\n]* /* ignore one-line comments */
+"#"[$a-zA-Z_0-9\.]+ /* ignore simulation timings */
+
+. { return *yytext; }
+
+%%
+
+// this is a hack to avoid the 'yyinput defined but not used' error msgs
+void *frontend_verilog_avoid_input_warnings() {
+ return (void*)&yyinput;
+}
+
diff --git a/frontends/verilog/parser.y b/frontends/verilog/parser.y
new file mode 100644
index 00000000..7c12bd56
--- /dev/null
+++ b/frontends/verilog/parser.y
@@ -0,0 +1,1074 @@
+/*
+ * 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 Verilog frontend.
+ *
+ * This frontend is using the AST frontend library (see frontends/ast/).
+ * Thus this frontend does not generate RTLIL code directly but creates an
+ * AST directly from the Verilog parse tree and then passes this AST to
+ * the AST frontend library.
+ *
+ * ---
+ *
+ * This is the actual bison parser for Verilog code. The AST ist created directly
+ * from the bison reduce functions here. Note that this code uses a few global
+ * variables to hold the state of the AST generator and therefore this parser is
+ * not reentrant.
+ *
+ */
+
+%{
+#include <list>
+#include <assert.h>
+#include "verilog_frontend.h"
+#include "kernel/log.h"
+
+using namespace AST;
+using namespace VERILOG_FRONTEND;
+
+namespace VERILOG_FRONTEND {
+ int port_counter;
+ std::map<std::string, int> port_stubs;
+ std::map<std::string, AstNode*> attr_list, default_attr_list;
+ std::map<std::string, AstNode*> *albuf;
+ std::vector<AstNode*> ast_stack;
+ struct AstNode *astbuf1, *astbuf2, *astbuf3;
+ struct AstNode *current_function_or_task;
+ struct AstNode *current_ast, *current_ast_mod;
+ int current_function_or_task_port_id;
+ std::vector<char> case_type_stack;
+}
+
+static void append_attr(AstNode *ast, std::map<std::string, AstNode*> *al)
+{
+ for (auto &it : *al) {
+ if (ast->attributes.count(it.first) > 0)
+ delete ast->attributes[it.first];
+ ast->attributes[it.first] = it.second;
+ }
+ delete al;
+}
+
+static void append_attr_clone(AstNode *ast, std::map<std::string, AstNode*> *al)
+{
+ for (auto &it : *al) {
+ if (ast->attributes.count(it.first) > 0)
+ delete ast->attributes[it.first];
+ ast->attributes[it.first] = it.second->clone();
+ }
+}
+
+static void free_attr(std::map<std::string, AstNode*> *al)
+{
+ for (auto &it : *al)
+ delete it.second;
+ delete al;
+}
+
+%}
+
+%name-prefix="frontend_verilog_yy"
+
+%union {
+ std::string *string;
+ struct AstNode *ast;
+ std::map<std::string, AstNode*> *al;
+ bool boolean;
+}
+
+%token <string> TOK_STRING TOK_ID TOK_CONST TOK_PRIMITIVE
+%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
+%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM
+%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_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_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
+%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
+
+%type <ast> wire_type range expr basic_expr concat_list lvalue lvalue_concat_list
+%type <string> opt_label tok_prim_wrapper
+%type <boolean> opt_signed
+%type <al> attr
+
+// operator precedence from low to high
+%left OP_LOR
+%left OP_LAND
+%left '|'
+%left '^' OP_XNOR
+%left '&'
+%left OP_EQ OP_NE
+%left '<' OP_LE OP_GE '>'
+%left OP_SHL OP_SHR OP_SSHL OP_SSHR
+%left '+' '-'
+%left '*' '/' '%'
+%left OP_POW
+%right UNARY_OPS
+
+%expect 2
+%debug
+
+%%
+
+input:
+ module input |
+ defattr input |
+ /* empty */ {
+ for (auto &it : default_attr_list)
+ delete it.second;
+ default_attr_list.clear();
+ };
+
+attr:
+ {
+ for (auto &it : attr_list)
+ delete it.second;
+ attr_list.clear();
+ for (auto &it : default_attr_list)
+ attr_list[it.first] = it.second->clone();
+ } attr_opt {
+ std::map<std::string, AstNode*> *al = new std::map<std::string, AstNode*>;
+ al->swap(attr_list);
+ $$ = al;
+ };
+
+attr_opt:
+ attr_opt ATTR_BEGIN opt_attr_list ATTR_END |
+ /* empty */;
+
+defattr:
+ DEFATTR_BEGIN {
+ for (auto &it : default_attr_list)
+ delete it.second;
+ default_attr_list.clear();
+ for (auto &it : attr_list)
+ delete it.second;
+ attr_list.clear();
+ } opt_attr_list {
+ default_attr_list = attr_list;
+ attr_list.clear();
+ } DEFATTR_END;
+
+opt_attr_list:
+ attr_list | /* empty */;
+
+attr_list:
+ attr_assign |
+ attr_list ',' attr_assign;
+
+attr_assign:
+ TOK_ID {
+ if (attr_list.count(*$1) != 0)
+ delete attr_list[*$1];
+ attr_list[*$1] = AstNode::mkconst_int(0, false, 0);
+ delete $1;
+ } |
+ TOK_ID '=' expr {
+ if (attr_list.count(*$1) != 0)
+ delete attr_list[*$1];
+ attr_list[*$1] = $3;
+ delete $1;
+ };
+
+module:
+ attr TOK_MODULE TOK_ID {
+ AstNode *mod = new AstNode(AST_MODULE);
+ current_ast->children.push_back(mod);
+ current_ast_mod = mod;
+ ast_stack.push_back(mod);
+ port_stubs.clear();
+ port_counter = 0;
+ mod->str = *$3;
+ append_attr(mod, $1);
+ delete $3;
+ } module_para_opt module_args_opt ';' module_body TOK_ENDMODULE {
+ if (port_stubs.size() != 0)
+ frontend_verilog_yyerror("Missing details for module port `%s'.",
+ port_stubs.begin()->first.c_str());
+ ast_stack.pop_back();
+ assert(ast_stack.size() == 0);
+ };
+
+module_para_opt:
+ '#' '(' TOK_PARAMETER param_decl_list optional_comma ')' | /* empty */;
+
+module_args_opt:
+ '(' ')' | /* empty */ | '(' module_args optional_comma ')';
+
+module_args:
+ module_arg | module_args ',' module_arg;
+
+optional_comma:
+ ',' | /* empty */;
+
+module_arg:
+ TOK_ID range {
+ if (port_stubs.count(*$1) != 0)
+ frontend_verilog_yyerror("Duplicate module port `%s'.", $1->c_str());
+ port_stubs[*$1] = ++port_counter;
+ if ($2 != NULL)
+ delete $2;
+ delete $1;
+ } |
+ attr wire_type range TOK_ID {
+ AstNode *node = $2;
+ node->str = *$4;
+ node->port_id = ++port_counter;
+ if ($3 != NULL)
+ node->children.push_back($3);
+ if (!node->is_input && !node->is_output)
+ frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $4->c_str());
+ if (node->is_reg && node->is_input && !node->is_output)
+ frontend_verilog_yyerror("Input port `%s' is declared as register.", $4->c_str());
+ ast_stack.back()->children.push_back(node);
+ append_attr(node, $1);
+ delete $4;
+ };
+
+wire_type:
+ {
+ astbuf3 = new AstNode(AST_WIRE);
+ } wire_type_token_list {
+ $$ = astbuf3;
+ };
+
+wire_type_token_list:
+ wire_type_token | wire_type_token_list wire_type_token;
+
+wire_type_token:
+ TOK_INPUT {
+ astbuf3->is_input = true;
+ } |
+ TOK_OUTPUT {
+ astbuf3->is_output = true;
+ } |
+ TOK_INOUT {
+ astbuf3->is_input = true;
+ astbuf3->is_output = true;
+ } |
+ TOK_WIRE {
+ } |
+ TOK_REG {
+ astbuf3->is_reg = true;
+ } |
+ TOK_INTEGER {
+ astbuf3->is_reg = true;
+ astbuf3->range_left = 31;
+ astbuf3->range_right = 0;
+ } |
+ TOK_GENVAR {
+ astbuf3->type = AST_GENVAR;
+ astbuf3->is_reg = true;
+ astbuf3->range_left = 31;
+ astbuf3->range_right = 0;
+ } |
+ TOK_SIGNED {
+ astbuf3->is_signed = true;
+ };
+
+range:
+ '[' expr ':' expr ']' {
+ $$ = new AstNode(AST_RANGE);
+ $$->children.push_back($2);
+ $$->children.push_back($4);
+ } |
+ '[' expr ']' {
+ $$ = new AstNode(AST_RANGE);
+ $$->children.push_back($2);
+ } |
+ /* empty */ {
+ $$ = NULL;
+ };
+
+module_body:
+ module_body module_body_stmt |
+ /* empty */;
+
+module_body_stmt:
+ task_func_decl | param_decl | localparam_decl | wire_decl | assign_stmt | cell_stmt |
+ always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr;
+
+task_func_decl:
+ TOK_TASK TOK_ID ';' {
+ current_function_or_task = new AstNode(AST_TASK);
+ current_function_or_task->str = *$2;
+ 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;
+ } task_func_body TOK_ENDTASK {
+ current_function_or_task = NULL;
+ ast_stack.pop_back();
+ } |
+ TOK_FUNCTION opt_signed range TOK_ID ';' {
+ current_function_or_task = new AstNode(AST_FUNCTION);
+ current_function_or_task->str = *$4;
+ 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;
+ current_function_or_task->children.push_back(outreg);
+ current_function_or_task_port_id = 1;
+ delete $4;
+ } task_func_body TOK_ENDFUNCTION {
+ current_function_or_task = NULL;
+ ast_stack.pop_back();
+ };
+
+opt_signed:
+ TOK_SIGNED {
+ $$ = true;
+ } |
+ /* empty */ {
+ $$ = false;
+ };
+
+task_func_body:
+ task_func_body wire_decl |
+ task_func_body behavioral_stmt |
+ /* empty */;
+
+param_decl:
+ TOK_PARAMETER param_decl_list ';';
+
+param_decl_list:
+ single_param_decl | param_decl_list ',' single_param_decl;
+
+single_param_decl:
+ range TOK_ID '=' expr {
+ AstNode *node = new AstNode(AST_PARAMETER);
+ node->str = *$2;
+ node->children.push_back($4);
+ if ($1 != NULL)
+ node->children.push_back($1);
+ ast_stack.back()->children.push_back(node);
+ delete $2;
+ };
+
+localparam_decl:
+ TOK_LOCALPARAM localparam_decl_list ';';
+
+localparam_decl_list:
+ single_localparam_decl | localparam_decl_list ',' single_localparam_decl;
+
+single_localparam_decl:
+ range TOK_ID '=' expr {
+ AstNode *node = new AstNode(AST_LOCALPARAM);
+ node->str = *$2;
+ node->children.push_back($4);
+ if ($1 != NULL)
+ node->children.push_back($1);
+ ast_stack.back()->children.push_back(node);
+ delete $2;
+ };
+
+wire_decl:
+ attr wire_type range {
+ albuf = $1;
+ astbuf1 = $2;
+ astbuf2 = $3;
+ if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
+ if (astbuf2) {
+ frontend_verilog_yyerror("Syntax error.");
+ } else {
+ astbuf2 = new AstNode(AST_RANGE);
+ astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
+ astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_right, true));
+ }
+ }
+ if (astbuf2 && astbuf2->children.size() != 2)
+ frontend_verilog_yyerror("Syntax error.");
+ } wire_name_list ';' {
+ delete astbuf1;
+ if (astbuf2 != NULL)
+ delete astbuf2;
+ free_attr(albuf);
+ } |
+ attr TOK_SUPPLY0 TOK_ID ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_WIRE));
+ ast_stack.back()->children.back()->str = *$3;
+ append_attr(ast_stack.back()->children.back(), $1);
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1)));
+ ast_stack.back()->children.back()->children[0]->str = *$3;
+ delete $3;
+ } |
+ attr TOK_SUPPLY1 TOK_ID ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_WIRE));
+ ast_stack.back()->children.back()->str = *$3;
+ append_attr(ast_stack.back()->children.back(), $1);
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1)));
+ ast_stack.back()->children.back()->children[0]->str = *$3;
+ delete $3;
+ };
+
+wire_name_list:
+ wire_name_and_opt_assign | wire_name_list ',' wire_name_and_opt_assign;
+
+wire_name_and_opt_assign:
+ wire_name |
+ wire_name '=' expr {
+ if (!astbuf1->is_reg) {
+ AstNode *wire = new AstNode(AST_IDENTIFIER);
+ wire->str = ast_stack.back()->children.back()->str;
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $3));
+ }
+ };
+
+wire_name:
+ TOK_ID range {
+ AstNode *node = astbuf1->clone();
+ node->str = *$1;
+ append_attr_clone(node, albuf);
+ if (astbuf2 != NULL)
+ node->children.push_back(astbuf2->clone());
+ if ($2 != NULL) {
+ if (node->is_input || node->is_output)
+ frontend_verilog_yyerror("Syntax error.");
+ if (!astbuf2) {
+ AstNode *rng = new AstNode(AST_RANGE);
+ rng->children.push_back(AstNode::mkconst_int(0, true));
+ rng->children.push_back(AstNode::mkconst_int(0, true));
+ node->children.push_back(rng);
+ }
+ node->type = AST_MEMORY;
+ node->children.push_back($2);
+ }
+ if (current_function_or_task == NULL) {
+ 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());
+ if (node->is_reg && node->is_input && !node->is_output)
+ frontend_verilog_yyerror("Input port `%s' is declared as register.", $1->c_str());
+ node->port_id = port_stubs[*$1];
+ port_stubs.erase(*$1);
+ } else {
+ 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);
+ }
+ delete $1;
+ };
+
+assign_stmt:
+ TOK_ASSIGN assign_expr_list ';';
+
+assign_expr_list:
+ assign_expr | assign_expr_list ',' assign_expr;
+
+assign_expr:
+ expr '=' expr {
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, $1, $3));
+ };
+
+cell_stmt:
+ attr TOK_ID {
+ astbuf1 = new AstNode(AST_CELL);
+ append_attr(astbuf1, $1);
+ astbuf1->children.push_back(new AstNode(AST_CELLTYPE));
+ astbuf1->children[0]->str = *$2;
+ delete $2;
+ } cell_parameter_list_opt cell_list ';' {
+ delete astbuf1;
+ } |
+ attr tok_prim_wrapper {
+ astbuf1 = new AstNode(AST_PRIMITIVE);
+ astbuf1->str = *$2;
+ append_attr(astbuf1, $1);
+ delete $2;
+ } prim_list ';' {
+ delete astbuf1;
+ };
+
+tok_prim_wrapper:
+ TOK_PRIMITIVE {
+ $$ = $1;
+ } |
+ TOK_OR {
+ $$ = new std::string("or");
+ };
+
+cell_list:
+ single_cell |
+ cell_list ',' single_cell;
+
+single_cell:
+ TOK_ID {
+ astbuf2 = astbuf1->clone();
+ if (astbuf2->type != AST_PRIMITIVE)
+ astbuf2->str = *$1;
+ delete $1;
+ ast_stack.back()->children.push_back(astbuf2);
+ } '(' cell_port_list ')';
+
+prim_list:
+ single_prim |
+ prim_list ',' single_prim;
+
+single_prim:
+ single_cell |
+ /* no name */ {
+ astbuf2 = astbuf1->clone();
+ ast_stack.back()->children.push_back(astbuf2);
+ } '(' cell_port_list ')';
+
+cell_parameter_list_opt:
+ '#' '(' cell_parameter_list ')' | /* empty */;
+
+cell_parameter_list:
+ /* empty */ | cell_parameter |
+ cell_parameter ',' cell_parameter_list;
+
+cell_parameter:
+ expr {
+ AstNode *node = new AstNode(AST_PARASET);
+ astbuf1->children.push_back(node);
+ node->children.push_back($1);
+ } |
+ '.' TOK_ID '(' expr ')' {
+ AstNode *node = new AstNode(AST_PARASET);
+ node->str = *$2;
+ astbuf1->children.push_back(node);
+ node->children.push_back($4);
+ delete $2;
+ };
+
+cell_port_list:
+ /* empty */ | cell_port |
+ cell_port ',' cell_port_list |
+ /* empty */ ',' {
+ AstNode *node = new AstNode(AST_ARGUMENT);
+ astbuf2->children.push_back(node);
+ } cell_port_list;
+
+cell_port:
+ expr {
+ AstNode *node = new AstNode(AST_ARGUMENT);
+ astbuf2->children.push_back(node);
+ node->children.push_back($1);
+ } |
+ '.' TOK_ID '(' expr ')' {
+ AstNode *node = new AstNode(AST_ARGUMENT);
+ node->str = *$2;
+ astbuf2->children.push_back(node);
+ node->children.push_back($4);
+ delete $2;
+ } |
+ '.' TOK_ID '(' ')' {
+ AstNode *node = new AstNode(AST_ARGUMENT);
+ node->str = *$2;
+ astbuf2->children.push_back(node);
+ delete $2;
+ };
+
+always_stmt:
+ attr TOK_ALWAYS {
+ AstNode *node = new AstNode(AST_ALWAYS);
+ append_attr(node, $1);
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ } always_cond {
+ AstNode *block = new AstNode(AST_BLOCK);
+ ast_stack.back()->children.push_back(block);
+ ast_stack.push_back(block);
+ } behavioral_stmt {
+ ast_stack.pop_back();
+ ast_stack.pop_back();
+ } |
+ attr TOK_INITIAL {
+ AstNode *node = new AstNode(AST_ALWAYS);
+ append_attr(node, $1);
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ AstNode *block = new AstNode(AST_BLOCK);
+ ast_stack.back()->children.push_back(block);
+ ast_stack.push_back(block);
+ } behavioral_stmt {
+ ast_stack.pop_back();
+ ast_stack.pop_back();
+ };
+
+always_cond:
+ '@' '(' always_events ')' |
+ '@' '*' |
+ /* empty */;
+
+always_events:
+ always_event |
+ always_events TOK_OR always_event |
+ always_events ',' always_event;
+
+always_event:
+ TOK_POSEDGE expr {
+ AstNode *node = new AstNode(AST_POSEDGE);
+ ast_stack.back()->children.push_back(node);
+ node->children.push_back($2);
+ } |
+ TOK_NEGEDGE expr {
+ AstNode *node = new AstNode(AST_NEGEDGE);
+ ast_stack.back()->children.push_back(node);
+ node->children.push_back($2);
+ } |
+ expr {
+ AstNode *node = new AstNode(AST_EDGE);
+ ast_stack.back()->children.push_back(node);
+ node->children.push_back($1);
+ };
+
+opt_label:
+ ':' TOK_ID {
+ $$ = $2;
+ } |
+ /* empty */ {
+ $$ = NULL;
+ };
+
+simple_behavioral_stmt:
+ lvalue '=' expr {
+ AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3);
+ ast_stack.back()->children.push_back(node);
+ } |
+ lvalue OP_LE expr {
+ AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $3);
+ ast_stack.back()->children.push_back(node);
+ };
+
+// this production creates the obligatory if-else shift/reduce conflict
+behavioral_stmt:
+ defattr |
+ simple_behavioral_stmt ';' |
+ TOK_ID attr {
+ AstNode *node = new AstNode(AST_TCALL);
+ node->str = *$1;
+ delete $1;
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ append_attr(node, $2);
+ } opt_arg_list ';'{
+ ast_stack.pop_back();
+ } |
+ attr TOK_BEGIN opt_label {
+ AstNode *node = new AstNode(AST_BLOCK);
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ append_attr(node, $1);
+ } behavioral_stmt_list TOK_END opt_label {
+ if ($3 != NULL)
+ delete $3;
+ if ($7 != NULL)
+ delete $7;
+ ast_stack.pop_back();
+ } |
+ attr TOK_FOR '(' {
+ AstNode *node = new AstNode(AST_FOR);
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ append_attr(node, $1);
+ } simple_behavioral_stmt ';' expr {
+ ast_stack.back()->children.push_back($7);
+ } ';' simple_behavioral_stmt ')' {
+ AstNode *block = new AstNode(AST_BLOCK);
+ 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);
+ AstNode *cond = new AstNode(AST_COND, AstNode::mkconst_int(1, false, 1), block);
+ ast_stack.back()->children.push_back(node);
+ node->children.push_back(new AstNode(AST_REDUCE_BOOL, $4));
+ node->children.push_back(cond);
+ ast_stack.push_back(node);
+ ast_stack.push_back(block);
+ append_attr(node, $1);
+ } behavioral_stmt optional_else {
+ ast_stack.pop_back();
+ ast_stack.pop_back();
+ } |
+ attr case_type '(' expr ')' {
+ AstNode *node = new AstNode(AST_CASE, $4);
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ append_attr(node, $1);
+ } opt_synopsys_attr case_body TOK_ENDCASE {
+ case_type_stack.pop_back();
+ ast_stack.pop_back();
+ };
+
+case_type:
+ TOK_CASE {
+ case_type_stack.push_back(0);
+ } |
+ TOK_CASEX {
+ case_type_stack.push_back('x');
+ } |
+ TOK_CASEZ {
+ case_type_stack.push_back('z');
+ };
+
+opt_synopsys_attr:
+ opt_synopsys_attr TOK_SYNOPSYS_FULL_CASE {
+ if (ast_stack.back()->attributes.count("\\full_case") == 0)
+ ast_stack.back()->attributes["\\full_case"] = AstNode::mkconst_int(0, false, 0);
+ } |
+ opt_synopsys_attr TOK_SYNOPSYS_PARALLEL_CASE {
+ if (ast_stack.back()->attributes.count("\\parallel_case") == 0)
+ ast_stack.back()->attributes["\\parallel_case"] = AstNode::mkconst_int(0, false, 0);
+ } |
+ /* empty */;
+
+behavioral_stmt_opt:
+ behavioral_stmt |
+ ';' ;
+
+behavioral_stmt_list:
+ behavioral_stmt_list behavioral_stmt |
+ /* empty */;
+
+optional_else:
+ TOK_ELSE {
+ AstNode *block = new AstNode(AST_BLOCK);
+ AstNode *cond = new AstNode(AST_COND, new AstNode(AST_DEFAULT), block);
+ ast_stack.pop_back();
+ ast_stack.back()->children.push_back(cond);
+ ast_stack.push_back(block);
+ } behavioral_stmt |
+ /* empty */;
+
+case_body:
+ case_body case_item |
+ /* empty */;
+
+case_item:
+ {
+ AstNode *node = new AstNode(AST_COND);
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ } case_select {
+ AstNode *block = new AstNode(AST_BLOCK);
+ ast_stack.back()->children.push_back(block);
+ ast_stack.push_back(block);
+ case_type_stack.push_back(0);
+ } behavioral_stmt_opt {
+ case_type_stack.pop_back();
+ ast_stack.pop_back();
+ ast_stack.pop_back();
+ };
+
+case_select:
+ case_expr_list ':' |
+ TOK_DEFAULT;
+
+case_expr_list:
+ TOK_DEFAULT {
+ ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT));
+ } |
+ expr {
+ ast_stack.back()->children.push_back($1);
+ } |
+ case_expr_list ',' expr {
+ ast_stack.back()->children.push_back($3);
+ };
+
+lvalue:
+ TOK_ID range {
+ $$ = new AstNode(AST_IDENTIFIER);
+ $$->str = *$1;
+ if ($2)
+ $$->children.push_back($2);
+ delete $1;
+ } |
+ '{' lvalue_concat_list '}' {
+ $$ = $2;
+ };
+
+lvalue_concat_list:
+ expr {
+ $$ = new AstNode(AST_CONCAT);
+ $$->children.push_back($1);
+ } |
+ expr ',' lvalue_concat_list {
+ $$ = $3;
+ $$->children.push_back($1);
+ };
+
+opt_arg_list:
+ '(' arg_list optional_comma ')' |
+ /* empty */;
+
+arg_list:
+ arg_list2 |
+ /* empty */;
+
+arg_list2:
+ single_arg |
+ arg_list ',' single_arg;
+
+single_arg:
+ expr {
+ ast_stack.back()->children.push_back($1);
+ };
+
+module_gen_body:
+ module_gen_body gen_stmt |
+ module_gen_body module_body_stmt |
+ /* empty */;
+
+// this production creates the obligatory if-else shift/reduce conflict
+gen_stmt:
+ TOK_FOR '(' {
+ AstNode *node = new AstNode(AST_GENFOR);
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ } simple_behavioral_stmt ';' expr {
+ ast_stack.back()->children.push_back($6);
+ } ';' simple_behavioral_stmt ')' gen_stmt {
+ ast_stack.pop_back();
+ } |
+ TOK_IF '(' expr ')' {
+ AstNode *node = new AstNode(AST_GENIF);
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ ast_stack.back()->children.push_back($3);
+ } gen_stmt opt_gen_else {
+ ast_stack.pop_back();
+ } |
+ TOK_BEGIN opt_label {
+ AstNode *node = new AstNode(AST_GENBLOCK);
+ node->str = $2 ? *$2 : std::string();
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ } module_gen_body TOK_END opt_label {
+ if ($2 != NULL)
+ delete $2;
+ if ($6 != NULL)
+ delete $6;
+ ast_stack.pop_back();
+ };
+
+opt_gen_else:
+ TOK_ELSE gen_stmt | /* empty */;
+
+expr:
+ basic_expr {
+ $$ = $1;
+ } |
+ basic_expr '?' attr expr ':' expr {
+ $$ = new AstNode(AST_TERNARY);
+ $$->children.push_back($1);
+ $$->children.push_back($4);
+ $$->children.push_back($6);
+ append_attr($$, $3);
+ };
+
+basic_expr:
+ TOK_CONST {
+ $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
+ delete $1;
+ } |
+ TOK_STRING {
+ std::string str = *$1;
+ std::vector<RTLIL::State> data;
+ data.reserve(str.size() * 8);
+ for (size_t i = 0; i < str.size(); i++) {
+ unsigned char ch = str[str.size() - i - 1];
+ for (int j = 0; j < 8; j++) {
+ data.push_back((ch & 1) ? RTLIL::S1 : RTLIL::S0);
+ ch = ch >> 1;
+ }
+ }
+ $$ = AstNode::mkconst_bits(data, false);
+ $$->str = str;
+ delete $1;
+ } |
+ TOK_ID range {
+ $$ = new AstNode(AST_IDENTIFIER, $2);
+ $$->str = *$1;
+ delete $1;
+ } |
+ TOK_ID attr {
+ AstNode *node = new AstNode(AST_FCALL);
+ node->str = *$1;
+ delete $1;
+ ast_stack.push_back(node);
+ append_attr(node, $2);
+ } '(' arg_list optional_comma ')' {
+ $$ = ast_stack.back();
+ ast_stack.pop_back();
+ } |
+ TOK_TO_SIGNED attr '(' expr ')' {
+ $$ = new AstNode(AST_TO_SIGNED, $4);
+ append_attr($$, $2);
+ } |
+ TOK_TO_UNSIGNED attr '(' expr ')' {
+ $$ = new AstNode(AST_TO_UNSIGNED, $4);
+ append_attr($$, $2);
+ } |
+ '(' expr ')' {
+ $$ = $2;
+ } |
+ '{' concat_list '}' {
+ $$ = $2;
+ } |
+ '{' expr '{' expr '}' '}' {
+ $$ = new AstNode(AST_REPLICATE, $2, $4);
+ } |
+ '~' attr basic_expr %prec UNARY_OPS {
+ $$ = new AstNode(AST_BIT_NOT, $3);
+ append_attr($$, $2);
+ } |
+ basic_expr '&' attr basic_expr {
+ $$ = new AstNode(AST_BIT_AND, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr '|' attr basic_expr {
+ $$ = new AstNode(AST_BIT_OR, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr '^' attr basic_expr {
+ $$ = new AstNode(AST_BIT_XOR, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr OP_XNOR attr basic_expr {
+ $$ = new AstNode(AST_BIT_XNOR, $1, $4);
+ append_attr($$, $3);
+ } |
+ '&' attr basic_expr %prec UNARY_OPS {
+ $$ = new AstNode(AST_REDUCE_AND, $3);
+ append_attr($$, $2);
+ } |
+ '|' attr basic_expr %prec UNARY_OPS {
+ $$ = new AstNode(AST_REDUCE_OR, $3);
+ append_attr($$, $2);
+ } |
+ '^' attr basic_expr %prec UNARY_OPS {
+ $$ = new AstNode(AST_REDUCE_XOR, $3);
+ append_attr($$, $2);
+ } |
+ OP_XNOR attr basic_expr %prec UNARY_OPS {
+ $$ = new AstNode(AST_REDUCE_XNOR, $3);
+ append_attr($$, $2);
+ } |
+ basic_expr OP_SHL attr basic_expr {
+ $$ = new AstNode(AST_SHIFT_LEFT, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr OP_SHR attr basic_expr {
+ $$ = new AstNode(AST_SHIFT_RIGHT, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr OP_SSHL attr basic_expr {
+ $$ = new AstNode(AST_SHIFT_SLEFT, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr OP_SSHR attr basic_expr {
+ $$ = new AstNode(AST_SHIFT_SRIGHT, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr '<' attr basic_expr {
+ $$ = new AstNode(AST_LT, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr OP_LE attr basic_expr {
+ $$ = new AstNode(AST_LE, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr OP_EQ attr basic_expr {
+ $$ = new AstNode(AST_EQ, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr OP_NE attr basic_expr {
+ $$ = new AstNode(AST_NE, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr OP_GE attr basic_expr {
+ $$ = new AstNode(AST_GE, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr '>' attr basic_expr {
+ $$ = new AstNode(AST_GT, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr '+' attr basic_expr {
+ $$ = new AstNode(AST_ADD, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr '-' attr basic_expr {
+ $$ = new AstNode(AST_SUB, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr '*' attr basic_expr {
+ $$ = new AstNode(AST_MUL, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr '/' attr basic_expr {
+ $$ = new AstNode(AST_DIV, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr '%' attr basic_expr {
+ $$ = new AstNode(AST_MOD, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr OP_POW attr basic_expr {
+ $$ = new AstNode(AST_POW, $1, $4);
+ append_attr($$, $3);
+ } |
+ '+' attr basic_expr %prec UNARY_OPS {
+ $$ = new AstNode(AST_POS, $3);
+ append_attr($$, $2);
+ } |
+ '-' attr basic_expr %prec UNARY_OPS {
+ $$ = new AstNode(AST_NEG, $3);
+ append_attr($$, $2);
+ } |
+ basic_expr OP_LAND attr basic_expr {
+ $$ = new AstNode(AST_LOGIC_AND, $1, $4);
+ append_attr($$, $3);
+ } |
+ basic_expr OP_LOR attr basic_expr {
+ $$ = new AstNode(AST_LOGIC_OR, $1, $4);
+ append_attr($$, $3);
+ } |
+ '!' attr basic_expr %prec UNARY_OPS {
+ $$ = new AstNode(AST_LOGIC_NOT, $3);
+ append_attr($$, $2);
+ };
+
+concat_list:
+ expr {
+ $$ = new AstNode(AST_CONCAT, $1);
+ } |
+ expr ',' concat_list {
+ $$ = $3;
+ $$->children.push_back($1);
+ };
+
diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc
new file mode 100644
index 00000000..e6fdc1ff
--- /dev/null
+++ b/frontends/verilog/preproc.cc
@@ -0,0 +1,360 @@
+/*
+ * 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 Verilog frontend.
+ *
+ * This frontend is using the AST frontend library (see frontends/ast/).
+ * Thus this frontend does not generate RTLIL code directly but creates an
+ * AST directly from the Verilog parse tree and then passes this AST to
+ * the AST frontend library.
+ *
+ * ---
+ *
+ * Ad-hoc implementation of a Verilog preprocessor. The directives `define,
+ * `include, `ifdef, `ifndef, `else and `endif are handled here. All other
+ * directives are handled by the lexer (see lexer.l).
+ *
+ */
+
+#include "verilog_frontend.h"
+#include "kernel/log.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <list>
+
+static std::list<std::string> output_code;
+static std::list<std::string> input_buffer;
+static size_t input_buffer_charp;
+
+static void return_char(char ch)
+{
+ if (input_buffer_charp == 0)
+ input_buffer.push_front(std::string() + ch);
+ else
+ input_buffer.front()[--input_buffer_charp] = ch;
+}
+
+static void insert_input(std::string str)
+{
+ if (input_buffer_charp != 0) {
+ input_buffer.front() = input_buffer.front().substr(input_buffer_charp);
+ input_buffer_charp = 0;
+ }
+ input_buffer.push_front(str);
+}
+
+static char next_char()
+{
+ if (input_buffer.size() == 0)
+ return 0;
+
+ assert(input_buffer_charp <= input_buffer.front().size());
+ if (input_buffer_charp == input_buffer.front().size()) {
+ input_buffer_charp = 0;
+ input_buffer.pop_front();
+ return next_char();
+ }
+
+ char ch = input_buffer.front()[input_buffer_charp++];
+ return ch == '\r' ? next_char() : ch;
+}
+
+static void skip_spaces()
+{
+ while (1) {
+ char ch = next_char();
+ if (ch == 0)
+ break;
+ if (ch != ' ' && ch != '\t') {
+ return_char(ch);
+ break;
+ }
+ }
+}
+
+static std::string next_token(bool pass_newline = false)
+{
+ std::string token;
+
+ char ch = next_char();
+ if (ch == 0)
+ return token;
+
+ token += ch;
+ if (ch == '\n') {
+ if (pass_newline) {
+ output_code.push_back(token);
+ return "";
+ }
+ return token;
+ }
+
+ if (ch == ' ' || ch == '\t')
+ {
+ while ((ch = next_char()) != 0) {
+ if (ch != ' ' && ch != '\t') {
+ return_char(ch);
+ break;
+ }
+ token += ch;
+ }
+ }
+ else if (ch == '"')
+ {
+ while ((ch = next_char()) != 0) {
+ token += ch;
+ if (ch == '"')
+ break;
+ if (ch == '\\') {
+ if ((ch = next_char()) != 0)
+ token += ch;
+ }
+ }
+ }
+ else if (ch == '/')
+ {
+ if ((ch = next_char()) != 0) {
+ if (ch == '/') {
+ token += '*';
+ char last_ch = 0;
+ while ((ch = next_char()) != 0) {
+ if (ch == '\n') {
+ return_char(ch);
+ break;
+ }
+ if (last_ch != '*' || ch != '/') {
+ token += ch;
+ last_ch = ch;
+ }
+ }
+ token += " */";
+ }
+ else if (ch == '*') {
+ token += '*';
+ int newline_count = 0;
+ char last_ch = 0;
+ while ((ch = next_char()) != 0) {
+ if (ch == '\n') {
+ newline_count++;
+ token += ' ';
+ } else
+ token += ch;
+ if (last_ch == '*' && ch == '/')
+ break;
+ last_ch = ch;
+ }
+ while (newline_count-- > 0)
+ return_char('\n');
+ }
+ else
+ return_char(ch);
+ }
+ }
+ else
+ {
+ const char *ok = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789";
+ while ((ch = next_char()) != 0) {
+ if (strchr(ok, ch) == NULL) {
+ return_char(ch);
+ break;
+ }
+ token += ch;
+ }
+ }
+
+ return token;
+}
+
+static void input_file(FILE *f, std::string filename)
+{
+ char buffer[513];
+ int rc;
+
+ insert_input("");
+ auto it = input_buffer.begin();
+
+ input_buffer.insert(it, "`file_push " + filename + "\n");
+ while ((rc = fread(buffer, 1, sizeof(buffer)-1, f)) > 0) {
+ buffer[rc] = 0;
+ input_buffer.insert(it, buffer);
+ }
+ input_buffer.insert(it, "`file_pop\n");
+}
+
+static std::string define_to_feature(std::string defname)
+{
+ if (defname == "__YOSYS_ENABLE_DEFATTR__")
+ return "defattr";
+ return std::string();
+}
+
+std::string frontend_verilog_preproc(FILE *f, std::string filename)
+{
+ std::map<std::string, std::string> defines_map;
+ int ifdef_fail_level = 0;
+
+ output_code.clear();
+ input_buffer.clear();
+ input_buffer_charp = 0;
+
+ input_file(f, filename);
+ defines_map["__YOSYS__"] = "1";
+
+ while (!input_buffer.empty())
+ {
+ std::string tok = next_token();
+ // printf("token: >>%s<<\n", tok != "\n" ? tok.c_str() : "NEWLINE");
+
+ if (tok == "`endif") {
+ if (ifdef_fail_level > 0)
+ ifdef_fail_level--;
+ continue;
+ }
+
+ if (tok == "`else") {
+ if (ifdef_fail_level == 0)
+ ifdef_fail_level = 1;
+ else if (ifdef_fail_level == 1)
+ ifdef_fail_level = 0;
+ continue;
+ }
+
+ if (tok == "`ifdef") {
+ skip_spaces();
+ std::string name = next_token(true);
+ if (ifdef_fail_level > 0 || defines_map.count(name) == 0)
+ ifdef_fail_level++;
+ continue;
+ }
+
+ if (tok == "`ifndef") {
+ skip_spaces();
+ std::string name = next_token(true);
+ if (ifdef_fail_level > 0 || defines_map.count(name) != 0)
+ ifdef_fail_level++;
+ continue;
+ }
+
+ if (ifdef_fail_level > 0) {
+ if (tok == "\n")
+ output_code.push_back(tok);
+ continue;
+ }
+
+ if (tok == "`include") {
+ skip_spaces();
+ std::string fn = next_token(true);
+ while (1) {
+ size_t pos = fn.find('"');
+ if (pos == std::string::npos)
+ break;
+ if (pos == 0)
+ fn = fn.substr(1);
+ 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::string fn2 = filename.substr(0, filename.rfind('/')+1) + fn;
+ fp = fopen(fn2.c_str(), "r");
+ }
+ if (fp != NULL) {
+ input_file(fp, fn);
+ fclose(fp);
+ } else
+ output_code.push_back("`file_notfound " + fn + "\n");
+ continue;
+ }
+
+ if (tok == "`define") {
+ std::string name, value;
+ skip_spaces();
+ name = next_token(true);
+ if (!define_to_feature(name).empty())
+ output_code.push_back("`yosys_enable_" + define_to_feature(name));
+ skip_spaces();
+ int newline_count = 0;
+ while (!tok.empty()) {
+ tok = next_token();
+ if (tok == "\n") {
+ return_char('\n');
+ break;
+ }
+ if (tok == "\\") {
+ char ch = next_char();
+ if (ch == '\n') {
+ value += " ";
+ newline_count++;
+ } else {
+ value += std::string("\\");
+ return_char(ch);
+ }
+ } else
+ value += tok;
+ }
+ while (newline_count-- > 0)
+ return_char('\n');
+ // printf("define: >>%s<< -> >>%s<<\n", name.c_str(), value.c_str());
+ defines_map[name] = value;
+ continue;
+ }
+
+ if (tok == "`undef") {
+ std::string name;
+ skip_spaces();
+ name = next_token(true);
+ if (!define_to_feature(name).empty())
+ output_code.push_back("`yosys_disable_" + define_to_feature(name));
+ // printf("undef: >>%s<<\n", name.c_str());
+ defines_map.erase(name);
+ continue;
+ }
+
+ if (tok == "`timescale") {
+ std::string name;
+ skip_spaces();
+ while (!tok.empty() && tok != "\n")
+ tok = next_token(true);
+ if (tok == "\n")
+ return_char('\n');
+ continue;
+ }
+
+ if (tok.size() > 1 && tok[0] == '`' && defines_map.count(tok.substr(1)) > 0) {
+ // printf("expand: >>%s<< -> >>%s<<\n", tok.c_str(), defines_map[tok.substr(1)].c_str());
+ insert_input(defines_map[tok.substr(1)]);
+ continue;
+ }
+
+ output_code.push_back(tok);
+ }
+
+ std::string output;
+ for (auto &str : output_code)
+ output += str;
+
+ output_code.clear();
+ input_buffer.clear();
+ input_buffer_charp = 0;
+
+ return output;
+}
+
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
new file mode 100644
index 00000000..c1823379
--- /dev/null
+++ b/frontends/verilog/verilog_frontend.cc
@@ -0,0 +1,148 @@
+/*
+ * 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 Verilog frontend.
+ *
+ * This frontend is using the AST frontend library (see frontends/ast/).
+ * Thus this frontend does not generate RTLIL code directly but creates an
+ * AST directly from the Verilog parse tree and then passes this AST to
+ * the AST frontend library.
+ *
+ */
+
+#include "verilog_frontend.h"
+#include "kernel/register.h"
+#include "kernel/log.h"
+#include "kernel/sha1.h"
+#include <sstream>
+#include <stdarg.h>
+#include <assert.h>
+
+using namespace VERILOG_FRONTEND;
+
+// use the Verilog bison/flex parser to generate an AST and use AST::process() to convert it to RTLIL
+
+struct VerilogFrontend : public Frontend {
+ VerilogFrontend() : Frontend("verilog") { }
+ virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ {
+ bool flag_dump_ast = false;
+ bool flag_dump_ast_diff = false;
+ bool flag_dump_vlog = false;
+ bool flag_nolatches = false;
+ bool flag_nomem2reg = false;
+ bool flag_ppdump = false;
+ bool flag_nopp = false;
+ frontend_verilog_yydebug = false;
+
+ log_header("Executing Verilog-2005 frontend.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ std::string arg = args[argidx];
+ if (arg == "-dump_ast") {
+ flag_dump_ast = true;
+ continue;
+ }
+ if (arg == "-dump_ast_diff") {
+ flag_dump_ast = true;
+ flag_dump_ast_diff = true;
+ continue;
+ }
+ if (arg == "-dump_vlog") {
+ flag_dump_vlog = true;
+ continue;
+ }
+ if (arg == "-yydebug") {
+ frontend_verilog_yydebug = true;
+ continue;
+ }
+ if (arg == "-nolatches") {
+ flag_nolatches = true;
+ continue;
+ }
+ if (arg == "-nomem2reg") {
+ flag_nomem2reg = true;
+ continue;
+ }
+ if (arg == "-ppdump") {
+ flag_ppdump = true;
+ continue;
+ }
+ if (arg == "-nopp") {
+ flag_nopp = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ log("Parsing Verilog input from `%s' to AST representation.\n", filename.c_str());
+
+ AST::current_filename = filename;
+ AST::set_line_num = &frontend_verilog_yyset_lineno;
+ AST::get_line_num = &frontend_verilog_yyget_lineno;
+
+ current_ast = new AST::AstNode(AST::AST_DESIGN);
+
+ FILE *fp = f;
+ std::string code_after_preproc;
+
+ if (!flag_nopp) {
+ code_after_preproc = frontend_verilog_preproc(f, filename);
+ 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");
+ }
+
+ lexer_feature_defattr = false;
+
+ frontend_verilog_yyset_lineno(1);
+ frontend_verilog_yyrestart(fp);
+ frontend_verilog_yyparse();
+ frontend_verilog_yylex_destroy();
+
+ AST::process(design, current_ast, flag_dump_ast, flag_dump_ast_diff, flag_dump_vlog, flag_nolatches, flag_nomem2reg);
+
+ if (!flag_nopp)
+ fclose(fp);
+
+ delete current_ast;
+ current_ast = NULL;
+
+ log("Successfully finished Verilog frontend.\n");
+ }
+} VerilogFrontend;
+
+// the yyerror function used by bison to report parser errors
+void frontend_verilog_yyerror(char const *fmt, ...)
+{
+ va_list ap;
+ char buffer[1024];
+ char *p = buffer;
+ p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ",
+ AST::current_filename.c_str(), frontend_verilog_yyget_lineno());
+ va_start(ap, fmt);
+ p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
+ va_end(ap);
+ p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
+ log_error("%s", buffer);
+ exit(1);
+}
+
diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h
new file mode 100644
index 00000000..808edfc7
--- /dev/null
+++ b/frontends/verilog/verilog_frontend.h
@@ -0,0 +1,62 @@
+/*
+ * 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 Verilog frontend.
+ *
+ * This frontend is using the AST frontend library (see frontends/ast/).
+ * Thus this frontend does not generate RTLIL code directly but creates an
+ * AST directly from the Verilog parse tree and then passes this AST to
+ * the AST frontend library.
+ *
+ */
+
+#ifndef VERILOG_FRONTEND_H
+#define VERILOG_FRONTEND_H
+
+#include "kernel/rtlil.h"
+#include "frontends/ast/ast.h"
+#include <stdio.h>
+#include <stdint.h>
+
+namespace VERILOG_FRONTEND
+{
+ // this variable is set to a new AST_DESIGN node and then filled with the AST by the bison parser
+ extern struct AST::AstNode *current_ast;
+
+ // this function converts a Verilog constant to an AST_CONSTANT node
+ AST::AstNode *const2ast(std::string code, char case_type = 0);
+
+ // lexer state variables
+ extern bool lexer_feature_defattr;
+}
+
+// the pre-processor
+std::string frontend_verilog_preproc(FILE *f, std::string filename);
+
+// the usual bison/flex stuff
+extern int frontend_verilog_yydebug;
+int frontend_verilog_yylex(void);
+void frontend_verilog_yyerror(char const *fmt, ...);
+void frontend_verilog_yyrestart(FILE *f);
+int frontend_verilog_yyparse(void);
+int frontend_verilog_yylex_destroy(void);
+int frontend_verilog_yyget_lineno(void);
+void frontend_verilog_yyset_lineno (int);
+
+#endif
diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h
new file mode 100644
index 00000000..aaefa50f
--- /dev/null
+++ b/kernel/bitpattern.h
@@ -0,0 +1,143 @@
+/*
+ * 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 BITPATTERN_H
+#define BITPATTERN_H
+
+#include "kernel/log.h"
+#include "kernel/rtlil.h"
+
+struct BitPatternPool
+{
+ int width;
+ typedef std::vector<RTLIL::State> bits_t;
+ std::set<bits_t> pool;
+
+ BitPatternPool(RTLIL::SigSpec sig)
+ {
+ width = sig.width;
+ 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];
+ else
+ pattern[i] = RTLIL::State::Sa;
+ }
+ pool.insert(pattern);
+ }
+ }
+
+ BitPatternPool(int width)
+ {
+ this->width = width;
+ if (width > 0) {
+ std::vector<RTLIL::State> pattern(width);
+ for (int i = 0; i < width; i++)
+ pattern[i] = RTLIL::State::Sa;
+ pool.insert(pattern);
+ }
+ }
+
+ 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;
+ for (auto &b : bits)
+ if (b > RTLIL::State::S1)
+ b = RTLIL::State::Sa;
+ return bits;
+ }
+
+ bool match(bits_t a, bits_t b)
+ {
+ assert(int(a.size()) == width);
+ 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;
+ return true;
+ }
+
+ bool has_any(RTLIL::SigSpec sig)
+ {
+ bits_t bits = sig2bits(sig);
+ for (auto &it : pool)
+ if (match(it, bits))
+ return true;
+ return false;
+ }
+
+ bool has_all(RTLIL::SigSpec sig)
+ {
+ bits_t bits = sig2bits(sig);
+ for (auto &it : pool)
+ if (match(it, bits)) {
+ for (int i = 0; i < width; i++)
+ if (bits[i] > RTLIL::State::S1 && it[i] <= RTLIL::State::S1)
+ goto next_pool_entry;
+ return true;
+ next_pool_entry:;
+ }
+ return false;
+ }
+
+ bool take(RTLIL::SigSpec sig)
+ {
+ bool status = false;
+ bits_t bits = sig2bits(sig);
+ std::vector<bits_t> pattern_list;
+ for (auto &it : pool)
+ if (match(it, bits))
+ pattern_list.push_back(it);
+ for (auto pattern : pattern_list) {
+ pool.erase(pattern);
+ for (int i = 0; i < width; i++) {
+ if (pattern[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa)
+ continue;
+ bits_t new_pattern = pattern;
+ new_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1;
+ pool.insert(new_pattern);
+ }
+ status = true;
+ }
+ return status;
+ }
+
+ bool take_all()
+ {
+ if (pool.empty())
+ return false;
+ pool.clear();
+ return true;
+ }
+
+ bool empty()
+ {
+ return pool.empty();
+ }
+};
+
+#endif
diff --git a/kernel/calc.cc b/kernel/calc.cc
new file mode 100644
index 00000000..f31fed7d
--- /dev/null
+++ b/kernel/calc.cc
@@ -0,0 +1,392 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/rtlil.h"
+#include "bigint/BigIntegerLibrary.hh"
+#include <assert.h>
+
+static BigInteger const2big(const RTLIL::Const &val, bool as_signed, int &undef_bit_pos)
+{
+ BigInteger result = 0, this_bit = 1;
+ for (size_t i = 0; i < val.bits.size(); i++) {
+ if (val.bits[i] == RTLIL::State::S1) {
+ if (as_signed && i+1 == val.bits.size())
+ result -= this_bit;
+ else
+ result += this_bit;
+ }
+ else if (val.bits[i] != RTLIL::State::S0) {
+ if (undef_bit_pos < 0)
+ undef_bit_pos = i;
+ }
+ this_bit *= 2;
+ }
+ return result;
+}
+
+static RTLIL::Const big2const(const BigInteger &val, int result_len, int undef_bit_pos)
+{
+ BigUnsigned mag = val.getMagnitude();
+ RTLIL::Const result(0, result_len);
+
+ if (!mag.isZero())
+ {
+ if (val.getSign() < 0)
+ {
+ mag--;
+ for (int i = 0; i < result_len; i++)
+ result.bits[i] = mag.getBit(i) ? RTLIL::State::S0 : RTLIL::State::S1;
+ }
+ else
+ {
+ for (int i = 0; i < result_len; i++)
+ result.bits[i] = mag.getBit(i) ? RTLIL::State::S1 : RTLIL::State::S0;
+ }
+ }
+
+ if (undef_bit_pos >= 0)
+ for (int i = undef_bit_pos; i < result_len; i++)
+ result.bits[i] = RTLIL::State::Sx;
+
+ return result;
+}
+
+static RTLIL::State logic_and(RTLIL::State a, RTLIL::State b)
+{
+ if (a == RTLIL::State::S0) return RTLIL::State::S0;
+ if (b == RTLIL::State::S0) return RTLIL::State::S0;
+ if (a != RTLIL::State::S1) return RTLIL::State::Sx;
+ if (b != RTLIL::State::S1) return RTLIL::State::Sx;
+ return RTLIL::State::S1;
+}
+
+static RTLIL::State logic_or(RTLIL::State a, RTLIL::State b)
+{
+ if (a == RTLIL::State::S1) return RTLIL::State::S1;
+ if (b == RTLIL::State::S1) return RTLIL::State::S1;
+ if (a != RTLIL::State::S0) return RTLIL::State::Sx;
+ if (b != RTLIL::State::S0) return RTLIL::State::Sx;
+ return RTLIL::State::S0;
+}
+
+static RTLIL::State logic_xor(RTLIL::State a, RTLIL::State b)
+{
+ if (a != RTLIL::State::S0 && a != RTLIL::State::S1) return RTLIL::State::Sx;
+ if (b != RTLIL::State::S0 && b != RTLIL::State::S1) return RTLIL::State::Sx;
+ return a != b ? RTLIL::State::S1 : RTLIL::State::S0;
+}
+
+static RTLIL::State logic_xnor(RTLIL::State a, RTLIL::State b)
+{
+ if (a != RTLIL::State::S0 && a != RTLIL::State::S1) return RTLIL::State::Sx;
+ if (b != RTLIL::State::S0 && b != RTLIL::State::S1) return RTLIL::State::Sx;
+ return a == b ? RTLIL::State::S1 : RTLIL::State::S0;
+}
+
+RTLIL::Const RTLIL::const_not(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int result_len)
+{
+ if (result_len < 0)
+ result_len = arg1.bits.size();
+
+ RTLIL::Const result(RTLIL::State::Sx, result_len);
+ for (size_t i = 0; i < size_t(result_len); i++) {
+ if (i >= arg1.bits.size())
+ result.bits[i] = RTLIL::State::S0;
+ else if (arg1.bits[i] == RTLIL::State::S0)
+ result.bits[i] = RTLIL::State::S1;
+ else if (arg1.bits[i] == RTLIL::State::S1)
+ result.bits[i] = RTLIL::State::S0;
+ }
+
+ return result;
+}
+
+static RTLIL::Const logic_wrapper(RTLIL::State(*logic_func)(RTLIL::State, RTLIL::State),
+ const RTLIL::Const &arg1, const RTLIL::Const &arg2, int result_len = -1)
+{
+ if (result_len < 0)
+ result_len = std::max(arg1.bits.size(), arg2.bits.size());
+
+ RTLIL::Const result(RTLIL::State::Sx, result_len);
+ for (size_t i = 0; i < size_t(result_len); i++) {
+ RTLIL::State a = i < arg1.bits.size() ? arg1.bits[i] : RTLIL::State::S0;
+ RTLIL::State b = i < arg2.bits.size() ? arg2.bits[i] : RTLIL::State::S0;
+ result.bits[i] = logic_func(a, b);
+ }
+
+ return result;
+}
+
+RTLIL::Const RTLIL::const_and(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return logic_wrapper(logic_and, arg1, arg2, result_len);
+}
+
+RTLIL::Const RTLIL::const_or(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return logic_wrapper(logic_or, arg1, arg2, result_len);
+}
+
+RTLIL::Const RTLIL::const_xor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return logic_wrapper(logic_xor, arg1, arg2, result_len);
+}
+
+RTLIL::Const RTLIL::const_xnor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return logic_wrapper(logic_xnor, arg1, arg2, result_len);
+}
+
+static RTLIL::Const logic_reduce_wrapper(RTLIL::State(*logic_func)(RTLIL::State, RTLIL::State), const RTLIL::Const &arg1)
+{
+ RTLIL::State temp = RTLIL::State::S0;
+
+ for (size_t i = 0; i < arg1.bits.size(); i++)
+ temp = logic_func(temp, arg1.bits[i]);
+
+ return RTLIL::Const(temp);
+}
+
+RTLIL::Const RTLIL::const_reduce_and(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
+{
+ return logic_reduce_wrapper(logic_and, arg1);
+}
+
+RTLIL::Const RTLIL::const_reduce_or(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
+{
+ return logic_reduce_wrapper(logic_or, arg1);
+}
+
+RTLIL::Const RTLIL::const_reduce_xor(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
+{
+ return logic_reduce_wrapper(logic_xor, arg1);
+}
+
+RTLIL::Const RTLIL::const_reduce_xnor(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
+{
+ return logic_reduce_wrapper(logic_xnor, arg1);
+}
+
+RTLIL::Const RTLIL::const_reduce_bool(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
+{
+ return logic_reduce_wrapper(logic_or, arg1);
+}
+
+RTLIL::Const RTLIL::const_logic_not(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int)
+{
+ int undef_bit_pos_a = -1;
+ BigInteger a = const2big(arg1, signed1, undef_bit_pos_a);
+
+ if (a.isZero()) {
+ if (undef_bit_pos_a >= 0)
+ return RTLIL::Const(RTLIL::State::Sx);
+ return RTLIL::Const(RTLIL::State::S1);
+ }
+
+ return RTLIL::Const(RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_logic_and(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos_a = -1, undef_bit_pos_b = -1;
+ BigInteger a = const2big(arg1, signed1, undef_bit_pos_a);
+ BigInteger b = const2big(arg2, signed2, undef_bit_pos_b);
+
+ if (a.isZero() || b.isZero()) {
+ if (undef_bit_pos_a >= 0 && undef_bit_pos_b >= 0)
+ return RTLIL::Const(RTLIL::State::Sx);
+ return RTLIL::Const(RTLIL::State::S0);
+ }
+
+ return RTLIL::Const(RTLIL::State::S1);
+}
+
+RTLIL::Const RTLIL::const_logic_or(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos_a = -1, undef_bit_pos_b = -1;
+ BigInteger a = const2big(arg1, signed1, undef_bit_pos_a);
+ BigInteger b = const2big(arg2, signed2, undef_bit_pos_b);
+
+ if (a.isZero() && b.isZero()) {
+ if (undef_bit_pos_a >= 0 || undef_bit_pos_b >= 0)
+ return RTLIL::Const(RTLIL::State::Sx);
+ return RTLIL::Const(RTLIL::State::S0);
+ }
+
+ return RTLIL::Const(RTLIL::State::S1);
+}
+
+static RTLIL::Const const_shift(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;
+
+ 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)
+ result.bits[i] = RTLIL::State::S0;
+ else if (pos >= arg1.bits.size())
+ result.bits[i] = sign_ext ? arg1.bits.back() : RTLIL::State::S0;
+ else
+ result.bits[i] = arg1.bits[pos.toInt()];
+ }
+
+ return result;
+}
+
+RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return const_shift(arg1, arg2, false, -1, result_len);
+}
+
+RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return const_shift(arg1, arg2, false, +1, result_len);
+}
+
+RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return const_shift(arg1, arg2, true, -1, result_len);
+}
+
+RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return const_shift(arg1, arg2, true, +1, result_len);
+}
+
+RTLIL::Const RTLIL::const_lt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos = -1;
+ bool y = const2big(arg1, signed1, undef_bit_pos) < const2big(arg2, signed2, undef_bit_pos);
+ return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_le(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos = -1;
+ bool y = const2big(arg1, signed1, undef_bit_pos) <= const2big(arg2, signed2, undef_bit_pos);
+ return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_eq(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos = -1;
+ bool y = const2big(arg1, signed1, undef_bit_pos) == const2big(arg2, signed2, undef_bit_pos);
+ return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_ne(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos = -1;
+ bool y = const2big(arg1, signed1, undef_bit_pos) != const2big(arg2, signed2, undef_bit_pos);
+ return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_ge(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos = -1;
+ bool y = const2big(arg1, signed1, undef_bit_pos) >= const2big(arg2, signed2, undef_bit_pos);
+ return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_gt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos = -1;
+ bool y = const2big(arg1, signed1, undef_bit_pos) > const2big(arg2, signed2, undef_bit_pos);
+ return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_add(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ int undef_bit_pos = -1;
+ BigInteger y = const2big(arg1, signed1, undef_bit_pos) + const2big(arg2, signed2, undef_bit_pos);
+ return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), undef_bit_pos);
+}
+
+RTLIL::Const RTLIL::const_sub(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ int undef_bit_pos = -1;
+ BigInteger y = const2big(arg1, signed1, undef_bit_pos) - const2big(arg2, signed2, undef_bit_pos);
+ return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), undef_bit_pos);
+}
+
+RTLIL::Const RTLIL::const_mul(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ int undef_bit_pos = -1;
+ BigInteger y = const2big(arg1, signed1, undef_bit_pos) * const2big(arg2, signed2, undef_bit_pos);
+ return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
+}
+
+RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ int undef_bit_pos = -1;
+ BigInteger y = const2big(arg1, signed1, undef_bit_pos) / const2big(arg2, signed2, undef_bit_pos);
+ return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
+}
+
+RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ int undef_bit_pos = -1;
+ BigInteger y = const2big(arg1, signed1, undef_bit_pos) % const2big(arg2, signed2, undef_bit_pos);
+ return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
+}
+
+RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ int undef_bit_pos = -1;
+
+ BigInteger a = const2big(arg1, signed1, undef_bit_pos);
+ BigInteger b = const2big(arg2, signed2, undef_bit_pos);
+ BigInteger y = 1;
+
+ if (b < 0 || a == 0) {
+ y = 0;
+ } else {
+ while (b > 0) {
+ y = y * a;
+ if (y.getLength() > 0x10000) {
+ undef_bit_pos = 0;
+ break;
+ }
+ b--;
+ }
+ }
+
+ return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
+}
+
+RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
+{
+ RTLIL::Const zero(RTLIL::State::S0, 1);
+ return RTLIL::const_add(zero, arg1, false, signed1, result_len);
+}
+
+RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
+{
+ RTLIL::Const zero(RTLIL::State::S0, 1);
+ return RTLIL::const_sub(zero, arg1, false, signed1, result_len);
+}
+
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
new file mode 100644
index 00000000..a13cbf32
--- /dev/null
+++ b/kernel/celltypes.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.
+ *
+ */
+
+#ifndef CELLTYPES_H
+#define CELLTYPES_H
+
+#include <set>
+#include <string>
+#include <stdlib.h>
+
+struct CellTypes
+{
+ std::set<std::string> cell_types;
+
+ void setup_internals()
+ {
+ cell_types.insert("$not");
+ cell_types.insert("$pos");
+ 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("$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("$safe_pmux");
+ }
+
+ void setup_internals_mem()
+ {
+ cell_types.insert("$dff");
+ cell_types.insert("$adff");
+ cell_types.insert("$memrd");
+ cell_types.insert("$memwr");
+ cell_types.insert("$mem");
+ cell_types.insert("$fsm");
+ }
+
+ void setup_stdcells()
+ {
+ cell_types.insert("$_INV_");
+ cell_types.insert("$_AND_");
+ cell_types.insert("$_OR_");
+ cell_types.insert("$_XOR_");
+ cell_types.insert("$_MUX_");
+ }
+
+ void setup_stdcells_mem()
+ {
+ 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_");
+ }
+
+ void clear()
+ {
+ cell_types.clear();
+ }
+
+ bool cell_known(std::string type)
+ {
+ return cell_types.count(type) > 0;
+ }
+
+ bool cell_output(std::string type, std::string port)
+ {
+ if (!cell_known(type))
+ 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;
+ return false;
+ }
+
+ bool cell_input(std::string type, std::string port)
+ {
+ if (!cell_known(type))
+ return false;
+ return !cell_output(type, port);
+ }
+
+ static RTLIL::Const eval(std::string type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+ {
+#define HANDLE_CELL_TYPE(_t) if (type == "$" #_t) return const_ ## _t(arg1, arg2, signed1, signed2, result_len);
+ HANDLE_CELL_TYPE(not)
+ HANDLE_CELL_TYPE(and)
+ HANDLE_CELL_TYPE(or)
+ HANDLE_CELL_TYPE(xor)
+ HANDLE_CELL_TYPE(xnor)
+ HANDLE_CELL_TYPE(reduce_and)
+ HANDLE_CELL_TYPE(reduce_or)
+ HANDLE_CELL_TYPE(reduce_xor)
+ HANDLE_CELL_TYPE(reduce_xnor)
+ HANDLE_CELL_TYPE(reduce_bool)
+ HANDLE_CELL_TYPE(logic_not)
+ HANDLE_CELL_TYPE(logic_and)
+ HANDLE_CELL_TYPE(logic_or)
+ HANDLE_CELL_TYPE(shl)
+ HANDLE_CELL_TYPE(shr)
+ HANDLE_CELL_TYPE(sshl)
+ HANDLE_CELL_TYPE(sshr)
+ HANDLE_CELL_TYPE(lt)
+ HANDLE_CELL_TYPE(le)
+ HANDLE_CELL_TYPE(eq)
+ HANDLE_CELL_TYPE(ne)
+ HANDLE_CELL_TYPE(ge)
+ HANDLE_CELL_TYPE(gt)
+ HANDLE_CELL_TYPE(add)
+ HANDLE_CELL_TYPE(sub)
+ HANDLE_CELL_TYPE(mul)
+ HANDLE_CELL_TYPE(div)
+ HANDLE_CELL_TYPE(mod)
+ HANDLE_CELL_TYPE(pow)
+ HANDLE_CELL_TYPE(pos)
+ HANDLE_CELL_TYPE(neg)
+#undef HANDLE_CELL_TYPE
+
+ if (type == "$_INV_")
+ return const_not(arg1, arg2, false, false, 1);
+ if (type == "$_AND_")
+ return const_and(arg1, arg2, false, false, 1);
+ if (type == "$_OR_")
+ return const_or(arg1, arg2, false, false, 1);
+ if (type == "$_XOR_")
+ return const_xor(arg1, arg2, false, false, 1);
+
+ assert(!"Called CellType.eval() with unsupported cell type!");
+ abort();
+ }
+
+ static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2)
+ {
+ 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)
+ {
+ if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_") {
+ RTLIL::Const ret = arg1;
+ for (size_t i = 0; i < sel.bits.size(); i++)
+ if (sel.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);
+ 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);
+ }
+};
+
+#endif
+
diff --git a/kernel/consteval.h b/kernel/consteval.h
new file mode 100644
index 00000000..d48771fe
--- /dev/null
+++ b/kernel/consteval.h
@@ -0,0 +1,198 @@
+/*
+ * 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 CONSTEVAL_H
+#define CONSTEVAL_H
+
+#include "kernel/rtlil.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+
+struct ConstEval
+{
+ RTLIL::Module *module;
+ SigMap assign_map;
+ SigMap values_map;
+ SigPool stop_signals;
+ SigSet<RTLIL::Cell*> sig2driver;
+ std::set<RTLIL::Cell*> busy;
+ std::vector<SigMap> stack;
+
+ ConstEval(RTLIL::Module *module) : module(module), assign_map(module)
+ {
+ CellTypes ct;
+ ct.setup_internals();
+ ct.setup_stdcells();
+
+ for (auto &it : module->cells) {
+ if (!ct.cell_known(it.second->type))
+ continue;
+ for (auto &it2 : it.second->connections)
+ if (ct.cell_output(it.second->type, it2.first))
+ sig2driver.insert(assign_map(it2.second), it.second);
+ }
+ }
+
+ void clear()
+ {
+ values_map.clear();
+ stop_signals.clear();
+ }
+
+ void push()
+ {
+ stack.push_back(values_map);
+ }
+
+ void pop()
+ {
+ values_map.swap(stack.back());
+ stack.pop_back();
+ }
+
+ void set(RTLIL::SigSpec sig, RTLIL::Const value)
+ {
+ 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]);
+ }
+#endif
+ values_map.add(sig, RTLIL::SigSpec(value));
+ }
+
+ void stop(RTLIL::SigSpec sig)
+ {
+ assign_map.apply(sig);
+ stop_signals.add(sig);
+ }
+
+ bool eval(RTLIL::Cell *cell, RTLIL::SigSpec &undef)
+ {
+ RTLIL::SigSpec sig_a, sig_b, sig_s, sig_y;
+ bool ignore_sig_a = false, ignore_sig_b = false;
+ int sig_b_shift = -1;
+
+ assert(cell->connections.count("\\Y") > 0);
+ sig_y = values_map(assign_map(cell->connections["\\Y"]));
+ if (sig_y.is_fully_const())
+ return true;
+
+ if (cell->connections.count("\\S") > 0) {
+ sig_s = cell->connections["\\S"];
+ if (!eval(sig_s, undef, cell))
+ return false;
+ }
+
+ if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_") {
+ bool found_collision = false;
+ for (int i = 0; i < sig_s.width; i++)
+ if (sig_s.extract(i, 1).as_bool()) {
+ if (sig_b_shift >= 0)
+ found_collision = true;
+ sig_b_shift = i;
+ ignore_sig_a = true;
+ if (cell->type != "$safe_pmux")
+ break;
+ }
+ if (found_collision) {
+ sig_b_shift = -1;
+ ignore_sig_a = false;
+ }
+ if (sig_b_shift < 0)
+ ignore_sig_b = true;
+ }
+
+ if (!ignore_sig_a && cell->connections.count("\\A") > 0) {
+ sig_a = cell->connections["\\A"];
+ if (!eval(sig_a, undef, cell))
+ return false;
+ }
+
+ if (!ignore_sig_b && cell->connections.count("\\B") > 0) {
+ sig_b = cell->connections["\\B"];
+ if (sig_b_shift >= 0)
+ sig_b = sig_b.extract(sig_y.width*sig_b_shift, sig_y.width);
+ if (!eval(sig_b, undef, cell))
+ return false;
+ }
+
+ if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_")
+ set(sig_y, sig_s.as_bool() ? sig_b.as_const() : sig_a.as_const());
+ else
+ set(sig_y, CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const()));
+
+ return true;
+ }
+
+ bool eval(RTLIL::SigSpec &sig, RTLIL::SigSpec &undef, RTLIL::Cell *busy_cell = NULL)
+ {
+ assign_map.apply(sig);
+ values_map.apply(sig);
+
+ if (sig.is_fully_const())
+ return true;
+
+ if (stop_signals.check_any(sig)) {
+ undef = stop_signals.extract(sig);
+ return false;
+ }
+
+ if (busy_cell) {
+ if (busy.count(busy_cell) > 0) {
+ undef = sig;
+ return false;
+ }
+ busy.insert(busy_cell);
+ }
+
+ std::set<RTLIL::Cell*> driver_cells;
+ sig2driver.find(sig, driver_cells);
+ for (auto cell : driver_cells) {
+ if (!eval(cell, undef)) {
+ if (busy_cell)
+ busy.erase(busy_cell);
+ return false;
+ }
+ }
+
+ if (busy_cell)
+ busy.erase(busy_cell);
+
+ values_map.apply(sig);
+ 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]);
+ return false;
+ }
+
+ bool eval(RTLIL::SigSpec &sig)
+ {
+ RTLIL::SigSpec undef;
+ return eval(sig, undef);
+ }
+};
+
+#endif
diff --git a/kernel/driver.cc b/kernel/driver.cc
new file mode 100644
index 00000000..c49bf657
--- /dev/null
+++ b/kernel/driver.cc
@@ -0,0 +1,253 @@
+/*
+ * 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 <stdio.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "kernel/rtlil.h"
+#include "kernel/register.h"
+#include "kernel/log.h"
+#include <string.h>
+#include <unistd.h>
+
+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 = "ilang";
+ 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 = 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));
+ char buffer[4096];
+ while (fgets(buffer, 4096, f) != NULL) {
+ Pass::call(design, buffer);
+ design->check();
+ }
+ 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);
+ design->check();
+}
+
+static void run_pass(std::string command, RTLIL::Design *design)
+{
+ log("\n-- Running pass `%s' --\n", command.c_str());
+
+ Pass::call(design, command);
+ design->check();
+}
+
+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 == "-")
+ command = "ilang";
+ else
+ log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str());
+ }
+
+ 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);
+ design->check();
+}
+
+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_completion(const char *text, int start, int)
+{
+ if (start == 0)
+ return rl_completion_matches(text, readline_cmd_generator);
+ return NULL;
+}
+
+static const char *create_prompt(RTLIL::Design *design)
+{
+ static char buffer[100];
+ std::string str = "\nyosys";
+ if (!design->selected_active_module.empty())
+ str += stringf(" [%s]", design->selected_active_module.c_str());
+ 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;
+}
+
+int main(int argc, char **argv)
+{
+ std::string frontend_command = "auto";
+ std::string backend_command = "auto";
+ std::vector<std::string> passes_commands;
+ std::string output_filename = "-";
+ std::string scriptfile = "";
+ bool got_output_filename = false;
+
+ RTLIL::Design *design = new RTLIL::Design;
+ design->selection_stack.push_back(RTLIL::Selection());
+ log_push();
+
+ int opt;
+ while ((opt = getopt(argc, argv, "f:b:o:p:l:qts:")) != -1)
+ {
+ switch (opt)
+ {
+ case 'f':
+ frontend_command = optarg;
+ break;
+ case 'b':
+ backend_command = optarg;
+ break;
+ case 'p':
+ passes_commands.push_back(optarg);
+ break;
+ case 'o':
+ output_filename = optarg;
+ got_output_filename = true;
+ break;
+ case 'l':
+ log_files.push_back(fopen(optarg, "wt"));
+ if (log_files.back() == NULL) {
+ fprintf(stderr, "Can't open log file `%s' for writing!\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'q':
+ log_errfile = stderr;
+ break;
+ case 't':
+ log_time = true;
+ break;
+ case 's':
+ scriptfile = optarg;
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [-q] [-t] [-l logfile] [-o <outfile>] [-f <frontend>] [-s <scriptfile>] [-p <pass> [-p ..]] [-b <backend>] [<infile> [..]]\n", argv[0]);
+ exit(1);
+ }
+ }
+
+ if (log_errfile == NULL)
+ log_files.push_back(stderr);
+
+ if (optind == argc && passes_commands.size() == 0 && scriptfile.empty())
+ {
+ log_cmd_error_throw = true;
+
+ rl_readline_name = "yosys";
+ rl_attempted_completion_function = readline_completion;
+
+ char *command = NULL;
+ while ((command = readline(create_prompt(design))) != NULL)
+ {
+ if (command[strspn(command, " \t\r\n")] == 0)
+ continue;
+ add_history(command);
+
+ 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 (!got_output_filename)
+ backend_command = "";
+ log_cmd_error_throw = false;
+ }
+
+ while (optind < argc)
+ run_frontend(argv[optind++], frontend_command, design, output_filename == "-" ? &backend_command : NULL);
+
+ if (!scriptfile.empty())
+ run_frontend(scriptfile, "script", design, output_filename == "-" ? &backend_command : NULL);
+
+ for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
+ run_pass(*it, design);
+
+ if (!backend_command.empty())
+ run_backend(output_filename, backend_command, design);
+
+ delete design;
+
+ log("\nREADY.\n");
+ log_pop();
+
+ for (auto f : log_files)
+ if (f != stderr)
+ fclose(f);
+ log_errfile = NULL;
+ log_files.clear();
+
+ return 0;
+}
+
diff --git a/kernel/log.cc b/kernel/log.cc
new file mode 100644
index 00000000..9bf8705e
--- /dev/null
+++ b/kernel/log.cc
@@ -0,0 +1,197 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/log.h"
+#include "backends/ilang/ilang_backend.h"
+
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <vector>
+#include <list>
+
+std::vector<FILE*> log_files;
+FILE *log_errfile = NULL;
+bool log_time = false;
+bool log_cmd_error_throw = false;
+
+std::vector<int> header_count;
+std::list<std::string> string_buf;
+
+static struct timeval initial_tv = { 0, 0 };
+static bool next_print_log = false;
+
+std::string stringf(const char *fmt, ...)
+{
+ std::string string;
+ char *str = NULL;
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (vasprintf(&str, fmt, ap) < 0)
+ str = NULL;
+ va_end(ap);
+
+ if (str != NULL) {
+ string = str;
+ free(str);
+ }
+
+ return string;
+}
+
+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;
+ gettimeofday(&tv, NULL);
+ if (initial_tv.tv_sec == 0)
+ initial_tv = tv;
+ if (tv.tv_usec < initial_tv.tv_usec) {
+ tv.tv_sec--;
+ tv.tv_usec += 1000000;
+ }
+ 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));
+ }
+ 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);
+ }
+}
+
+void logv_header(const char *format, va_list ap)
+{
+ log("\n");
+ if (header_count.size() > 0)
+ header_count.back()++;
+ for (int c : header_count)
+ log("%d.", c);
+ log(" ");
+ logv(format, ap);
+ log_flush();
+}
+
+void logv_error(const char *format, va_list ap)
+{
+ log("ERROR: ");
+ logv(format, ap);
+ if (log_errfile != NULL) {
+ fprintf(log_errfile, "ERROR: ");
+ vfprintf(log_errfile, format, ap);
+ }
+ log_flush();
+ exit(1);
+}
+
+void log(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ logv(format, ap);
+ va_end(ap);
+}
+
+void log_header(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ logv_header(format, ap);
+ va_end(ap);
+}
+
+void log_error(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ logv_error(format, ap);
+}
+
+void log_cmd_error(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+
+ if (log_cmd_error_throw) {
+ log("ERROR: ");
+ logv(format, ap);
+ log_flush();
+ throw 0;
+ }
+
+ logv_error(format, ap);
+}
+
+void log_push()
+{
+ header_count.push_back(0);
+}
+
+void log_pop()
+{
+ header_count.pop_back();
+ string_buf.clear();
+ log_flush();
+}
+
+void log_reset_stack()
+{
+ while (header_count.size() > 1)
+ header_count.pop_back();
+ string_buf.clear();
+ log_flush();
+}
+
+void log_flush()
+{
+ for (auto f : log_files)
+ fflush(f);
+}
+
+const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
+{
+ char *ptr;
+ size_t size;
+
+ 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);
+
+ return string_buf.back().c_str();
+}
+
diff --git a/kernel/log.h b/kernel/log.h
new file mode 100644
index 00000000..9023854d
--- /dev/null
+++ b/kernel/log.h
@@ -0,0 +1,51 @@
+/*
+ * 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 LOG_H
+#define LOG_H
+
+#include "kernel/rtlil.h"
+#include <stdio.h>
+#include <vector>
+
+extern std::vector<FILE*> log_files;
+extern FILE *log_errfile;
+extern bool log_time;
+extern bool log_cmd_error_throw;
+
+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));
+
+void log(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+void log_header(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+void log_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
+void log_cmd_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
+
+void log_push();
+void log_pop();
+
+void log_reset_stack();
+void log_flush();
+
+const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
+
+#endif
diff --git a/kernel/register.cc b/kernel/register.cc
new file mode 100644
index 00000000..fb70c80d
--- /dev/null
+++ b/kernel/register.cc
@@ -0,0 +1,288 @@
+/*
+ * 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 "register.h"
+#include "log.h"
+#include <assert.h>
+#include <string.h>
+
+using namespace REGISTER_INTERN;
+
+namespace REGISTER_INTERN {
+ 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) : pass_name(name)
+{
+ assert(pass_register.count(name) == 0);
+ pass_register[name] = this;
+}
+
+Pass::~Pass()
+{
+ pass_register.erase(pass_name);
+}
+
+void Pass::help()
+{
+ log("No help message for this command.\n");
+}
+
+void Pass::cmd_log_args(const std::vector<std::string> &args)
+{
+ if (args.size() <= 1)
+ return;
+ log("Full command line:");
+ for (size_t i = 0; i < args.size(); i++)
+ log(" %s", args[i].c_str());
+ log("\n");
+}
+
+void Pass::cmd_error(const std::vector<std::string> &args, size_t argidx, std::string msg)
+{
+ std::string command_text;
+ int error_pos = 0;
+
+ for (size_t i = 0; i < args.size(); i++) {
+ if (i < argidx)
+ error_pos += args[i].size() + 1;
+ command_text = command_text + (command_text.empty() ? "" : " ") + args[i];
+ }
+
+ log("\nSyntax error in command `%s':\n", command_text.c_str());
+ help();
+
+ log_cmd_error("Command syntax error: %s\n> %s\n> %*s^\n",
+ msg.c_str(), command_text.c_str(), error_pos, "");
+}
+
+void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Design *)
+{
+ for (; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+
+ if (arg.substr(0, 1) == "-")
+ cmd_error(args, argidx, "Unkown option or option in arguments.");
+ cmd_error(args, argidx, "Extra argument.");
+ }
+ cmd_log_args(args);
+}
+
+void Pass::call(RTLIL::Design *design, std::string command)
+{
+ std::vector<std::string> args;
+ char *s = strdup(command.c_str());
+ for (char *p = strtok(s, " \t\r\n"); p; p = strtok(NULL, " \t\r\n"))
+ args.push_back(p);
+ free(s);
+ call(design, args);
+}
+
+void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
+{
+ if (args.size() == 0 || args[0][0] == '#')
+ return;
+ if (pass_register.count(args[0]) == 0)
+ log_cmd_error("No such command: %s\n", args[0].c_str());
+
+ size_t orig_sel_stack_pos = design->selection_stack.size();
+ pass_register[args[0]]->execute(args, design);
+ while (design->selection_stack.size() > orig_sel_stack_pos)
+ design->selection_stack.pop_back();
+}
+
+Frontend::Frontend(std::string name) : Pass("read_"+name), frontend_name(name)
+{
+ assert(frontend_register.count(name) == 0);
+ frontend_register[name] = this;
+}
+
+Frontend::~Frontend()
+{
+ frontend_register.erase(frontend_name);
+}
+
+void Frontend::execute(std::vector<std::string> args, RTLIL::Design *design)
+{
+ assert(next_args.empty());
+ do {
+ FILE *f = NULL;
+ next_args.clear();
+ execute(f, std::string(), args, design);
+ args = next_args;
+ fclose(f);
+ } while (!args.empty());
+}
+
+void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
+{
+ bool called_with_fp = f != NULL;
+
+ next_args.clear();
+ for (; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+
+ if (arg.substr(0, 1) == "-")
+ cmd_error(args, argidx, "Unkown 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 (f == NULL)
+ log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
+
+ 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());
+ args.erase(args.begin()+argidx+1, args.end());
+ }
+ break;
+ }
+ if (f == NULL)
+ cmd_error(args, argidx, "No filename given.");
+
+ if (called_with_fp)
+ args.push_back(filename);
+ args[0] = pass_name;
+ cmd_log_args(args);
+}
+
+void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command)
+{
+ std::vector<std::string> args;
+ char *s = strdup(command.c_str());
+ for (char *p = strtok(s, " \t\r\n"); p; p = strtok(NULL, " \t\r\n"))
+ args.push_back(p);
+ free(s);
+ frontend_call(design, f, filename, args);
+}
+
+void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args)
+{
+ if (args.size() == 0)
+ return;
+ if (frontend_register.count(args[0]) == 0)
+ log_cmd_error("No such frontend: %s\n", args[0].c_str());
+
+ if (f != NULL) {
+ frontend_register[args[0]]->execute(f, filename, args, design);
+ } else if (filename == "-") {
+ frontend_register[args[0]]->execute(stdin, "<stdin>", args, design);
+ } else {
+ if (!filename.empty())
+ args.push_back(filename);
+ frontend_register[args[0]]->execute(args, design);
+ }
+}
+
+Backend::Backend(std::string name) : Pass("write_"+name), backend_name(name)
+{
+ assert(backend_register.count(name) == 0);
+ backend_register[name] = this;
+}
+
+Backend::~Backend()
+{
+ backend_register.erase(backend_name);
+}
+
+void Backend::execute(std::vector<std::string> args, RTLIL::Design *design)
+{
+ FILE *f = NULL;
+ execute(f, std::string(), args, design);
+ if (f != stdout)
+ fclose(f);
+}
+
+void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
+{
+ bool called_with_fp = f != NULL;
+
+ for (; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+
+ if (arg.substr(0, 1) == "-" && arg != "-")
+ cmd_error(args, argidx, "Unkown 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;
+ continue;
+ }
+
+ filename = arg;
+ f = fopen(filename.c_str(), "w");
+ if (f == NULL)
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+ }
+
+ if (called_with_fp)
+ args.push_back(filename);
+ args[0] = pass_name;
+ cmd_log_args(args);
+
+ if (f == NULL) {
+ filename = "<stdout>";
+ f = stdout;
+ }
+}
+
+void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command)
+{
+ std::vector<std::string> args;
+ char *s = strdup(command.c_str());
+ for (char *p = strtok(s, " \t\r\n"); p; p = strtok(NULL, " \t\r\n"))
+ args.push_back(p);
+ free(s);
+ backend_call(design, f, filename, args);
+}
+
+void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args)
+{
+ if (args.size() == 0)
+ return;
+ if (backend_register.count(args[0]) == 0)
+ log_cmd_error("No such backend: %s\n", args[0].c_str());
+
+ size_t orig_sel_stack_pos = design->selection_stack.size();
+
+ if (f != NULL) {
+ backend_register[args[0]]->execute(f, filename, args, design);
+ } else if (filename == "-") {
+ backend_register[args[0]]->execute(stdout, "<stdout>", args, design);
+ } else {
+ if (!filename.empty())
+ args.push_back(filename);
+ backend_register[args[0]]->execute(args, design);
+ }
+
+ while (design->selection_stack.size() > orig_sel_stack_pos)
+ design->selection_stack.pop_back();
+}
+
diff --git a/kernel/register.h b/kernel/register.h
new file mode 100644
index 00000000..713d468e
--- /dev/null
+++ b/kernel/register.h
@@ -0,0 +1,80 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef REGISTER_H
+#define REGISTER_H
+
+#include "kernel/rtlil.h"
+#include <stdio.h>
+#include <string>
+#include <vector>
+#include <map>
+
+struct Pass
+{
+ std::string pass_name;
+ Pass(std::string name);
+ virtual ~Pass();
+ virtual void help();
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0;
+
+ 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);
+
+ static void call(RTLIL::Design *design, std::string command);
+ static void call(RTLIL::Design *design, std::vector<std::string> args);
+};
+
+struct Frontend : Pass
+{
+ std::string frontend_name;
+ Frontend(std::string name);
+ 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;
+
+ static std::vector<std::string> next_args;
+ void extra_args(FILE *&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);
+};
+
+struct Backend : Pass
+{
+ std::string backend_name;
+ Backend(std::string name);
+ 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;
+
+ void extra_args(FILE *&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);
+};
+
+namespace REGISTER_INTERN {
+ extern std::map<std::string, Pass*> pass_register;
+ extern std::map<std::string, Frontend*> frontend_register;
+ extern std::map<std::string, Backend*> backend_register;
+}
+
+#endif
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
new file mode 100644
index 00000000..c97e2e45
--- /dev/null
+++ b/kernel/rtlil.cc
@@ -0,0 +1,1081 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/rtlil.h"
+#include <assert.h>
+#include <algorithm>
+
+int RTLIL::autoidx = 1;
+
+RTLIL::Const::Const(std::string str) : str(str)
+{
+ for (size_t i = 0; i < str.size(); i++) {
+ unsigned char ch = str[i];
+ for (int j = 0; j < 8; j++) {
+ bits.push_back((ch & 1) != 0 ? RTLIL::S1 : RTLIL::S0);
+ ch = ch >> 1;
+ }
+ }
+}
+
+RTLIL::Const::Const(int val, int width)
+{
+ for (int i = 0; i < width; i++) {
+ bits.push_back((val & 1) != 0 ? RTLIL::S1 : RTLIL::S0);
+ val = val >> 1;
+ }
+}
+
+RTLIL::Const::Const(RTLIL::State bit, int width)
+{
+ for (int i = 0; i < width; i++)
+ bits.push_back(bit);
+}
+
+bool RTLIL::Const::operator <(const RTLIL::Const &other) const
+{
+ if (bits.size() != other.bits.size())
+ return bits.size() < other.bits.size();
+ for (size_t i = 0; i < bits.size(); i++)
+ if (bits[i] != other.bits[i])
+ return bits[i] < other.bits[i];
+ return false;
+}
+
+bool RTLIL::Const::operator ==(const RTLIL::Const &other) const
+{
+ return bits == other.bits;
+}
+
+bool RTLIL::Const::operator !=(const RTLIL::Const &other) const
+{
+ return bits != other.bits;
+}
+
+bool RTLIL::Const::as_bool() const
+{
+ for (size_t i = 0; i < bits.size(); i++)
+ if (bits[i] == RTLIL::S1)
+ return true;
+ return false;
+}
+
+int RTLIL::Const::as_int() const
+{
+ int ret = 0;
+ for (size_t i = 0; i < bits.size() && i < 32; i++)
+ if (bits[i] == RTLIL::S1)
+ ret |= 1 << i;
+ return ret;
+}
+
+std::string RTLIL::Const::as_string() const
+{
+ std::string ret;
+ for (size_t i = bits.size(); i > 0; i--)
+ switch (bits[i-1]) {
+ case S0: ret += "0"; break;
+ case S1: ret += "1"; break;
+ case Sx: ret += "x"; break;
+ case Sz: ret += "z"; break;
+ case Sa: ret += "-"; break;
+ case Sm: ret += "m"; break;
+ }
+ return ret;
+}
+
+bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name)
+{
+ if (full_selection)
+ return true;
+ if (selected_modules.count(mod_name) > 0)
+ return true;
+ if (selected_members.count(mod_name) > 0)
+ return true;
+ return false;
+}
+
+bool RTLIL::Selection::selected_whole_module(RTLIL::IdString mod_name)
+{
+ if (full_selection)
+ return true;
+ if (selected_modules.count(mod_name) > 0)
+ return true;
+ return false;
+}
+
+bool RTLIL::Selection::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name)
+{
+ if (full_selection)
+ return true;
+ if (selected_modules.count(mod_name) > 0)
+ return true;
+ if (selected_members.count(mod_name) > 0)
+ if (selected_members[mod_name].count(memb_name) > 0)
+ return true;
+ return false;
+}
+
+void RTLIL::Selection::optimize(RTLIL::Design *design)
+{
+ if (full_selection) {
+ selected_modules.clear();
+ selected_members.clear();
+ return;
+ }
+
+ std::vector<RTLIL::IdString> del_list, add_list;
+
+ del_list.clear();
+ for (auto mod_name : selected_modules) {
+ if (design->modules.count(mod_name) == 0)
+ del_list.push_back(mod_name);
+ selected_members.erase(mod_name);
+ }
+ for (auto mod_name : del_list)
+ selected_modules.erase(mod_name);
+
+ del_list.clear();
+ for (auto &it : selected_members)
+ if (design->modules.count(it.first) == 0)
+ del_list.push_back(it.first);
+ for (auto mod_name : del_list)
+ selected_members.erase(mod_name);
+
+ for (auto &it : selected_members) {
+ del_list.clear();
+ for (auto memb_name : it.second)
+ 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);
+ }
+
+ del_list.clear();
+ add_list.clear();
+ 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())
+ add_list.push_back(it.first);
+ for (auto mod_name : del_list)
+ selected_members.erase(mod_name);
+ for (auto mod_name : add_list) {
+ selected_members.erase(mod_name);
+ selected_modules.insert(mod_name);
+ }
+
+ if (selected_modules.size() == design->modules.size()) {
+ full_selection = true;
+ selected_modules.clear();
+ selected_members.clear();
+ }
+}
+
+RTLIL::Design::~Design()
+{
+ for (auto it = modules.begin(); it != modules.end(); it++)
+ delete it->second;
+}
+
+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] == '$'));
+ it.second->check();
+ }
+#endif
+}
+
+void RTLIL::Design::optimize()
+{
+ for (auto &it : modules)
+ it.second->optimize();
+ for (auto &it : selection_stack)
+ it.optimize(this);
+ for (auto &it : selection_vars)
+ it.second.optimize(this);
+}
+
+bool RTLIL::Design::selected_module(RTLIL::IdString mod_name)
+{
+ if (!selected_active_module.empty() && mod_name != selected_active_module)
+ return false;
+ if (selection_stack.size() == 0)
+ return true;
+ return selection_stack.back().selected_module(mod_name);
+}
+
+bool RTLIL::Design::selected_whole_module(RTLIL::IdString mod_name)
+{
+ if (!selected_active_module.empty() && mod_name != selected_active_module)
+ return false;
+ if (selection_stack.size() == 0)
+ return true;
+ return selection_stack.back().selected_whole_module(mod_name);
+}
+
+bool RTLIL::Design::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name)
+{
+ if (!selected_active_module.empty() && mod_name != selected_active_module)
+ return false;
+ if (selection_stack.size() == 0)
+ return true;
+ return selection_stack.back().selected_member(mod_name, memb_name);
+}
+
+RTLIL::Module::~Module()
+{
+ 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++)
+ delete it->second;
+ for (auto it = processes.begin(); it != processes.end(); it++)
+ delete it->second;
+}
+
+RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, std::map<RTLIL::IdString, RTLIL::Const>)
+{
+ assert(!"Called derive() from module base class.");
+ abort();
+}
+
+void RTLIL::Module::update_auto_wires(std::map<RTLIL::IdString, int>)
+{
+ assert(!"Called update_auto_wires() from module base class.");
+}
+
+size_t RTLIL::Module::count_id(RTLIL::IdString id)
+{
+ return wires.count(id) + memories.count(id) + cells.count(id) + processes.count(id);
+}
+
+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] == '$'));
+ }
+ }
+
+ 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] == '$'));
+ }
+ }
+
+ 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] == '$'));
+ 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] == '$'));
+ }
+ }
+
+ for (auto &it : processes) {
+ assert(it.first == it.second->name);
+ assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
+ // FIXME: More checks here..
+ }
+
+ for (auto &it : connections) {
+ assert(it.first.width == it.second.width);
+ it.first.check();
+ it.second.check();
+ }
+
+ for (auto &it : attributes) {
+ assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
+ }
+#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::add(RTLIL::Wire *wire) {
+ assert(!wire->name.empty());
+ assert(count_id(wire->name) == 0);
+ wires[wire->name] = wire;
+}
+
+void RTLIL::Module::add(RTLIL::Cell *cell) {
+ assert(!cell->name.empty());
+ assert(count_id(cell->name) == 0);
+ cells[cell->name] = cell;
+}
+
+RTLIL::Wire::Wire()
+{
+ width = 1;
+ start_offset = 0;
+ port_id = 0;
+ port_input = false;
+ port_output = false;
+ auto_width = false;
+}
+
+RTLIL::Memory::Memory()
+{
+ width = 1;
+ size = 0;
+}
+
+void RTLIL::Cell::optimize()
+{
+ for (auto &it : connections)
+ it.second.optimize();
+}
+
+RTLIL::SigChunk::SigChunk()
+{
+ wire = NULL;
+ width = 0;
+ offset = 0;
+}
+
+RTLIL::SigChunk::SigChunk(const RTLIL::Const &data)
+{
+ wire = NULL;
+ this->data = data;
+ width = data.bits.size();
+ offset = 0;
+}
+
+RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire, int width, int offset)
+{
+ this->wire = wire;
+ this->width = width >= 0 ? width : wire->width;
+ this->offset = offset;
+}
+
+RTLIL::SigChunk::SigChunk(const std::string &str)
+{
+ wire = NULL;
+ data = RTLIL::Const(str);
+ width = data.bits.size();
+ offset = 0;
+}
+
+RTLIL::SigChunk::SigChunk(int val, int width)
+{
+ wire = NULL;
+ data = RTLIL::Const(val, width);
+ this->width = data.bits.size();
+ offset = 0;
+}
+
+RTLIL::SigChunk::SigChunk(RTLIL::State bit, int width)
+{
+ wire = NULL;
+ data = RTLIL::Const(bit, width);
+ this->width = data.bits.size();
+ offset = 0;
+}
+
+RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const
+{
+ RTLIL::SigChunk ret;
+ if (wire) {
+ ret.wire = wire;
+ ret.offset = this->offset + offset;
+ ret.width = length;
+ } else {
+ for (int i = 0; i < length; i++)
+ ret.data.bits.push_back(data.bits[offset+i]);
+ ret.width = length;
+ }
+ return ret;
+}
+
+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;
+
+ if (offset != other.offset)
+ return offset < other.offset;
+
+ if (width != other.width)
+ return width < other.width;
+
+ if (data.bits != other.data.bits)
+ return data.bits < other.data.bits;
+
+ return false;
+}
+
+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;
+}
+
+bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const
+{
+ if (*this == other)
+ return false;
+ return true;
+}
+
+RTLIL::SigSpec::SigSpec()
+{
+ width = 0;
+}
+
+RTLIL::SigSpec::SigSpec(const RTLIL::Const &data)
+{
+ chunks.push_back(RTLIL::SigChunk(data));
+ width = chunks.back().width;
+ check();
+}
+
+RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk)
+{
+ chunks.push_back(chunk);
+ width = chunks.back().width;
+ check();
+}
+
+RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int width, int offset)
+{
+ chunks.push_back(RTLIL::SigChunk(wire, width, offset));
+ this->width = chunks.back().width;
+ check();
+}
+
+RTLIL::SigSpec::SigSpec(const std::string &str)
+{
+ chunks.push_back(RTLIL::SigChunk(str));
+ width = chunks.back().width;
+ check();
+}
+
+RTLIL::SigSpec::SigSpec(int val, int width)
+{
+ chunks.push_back(RTLIL::SigChunk(val, width));
+ this->width = chunks.back().width;
+ check();
+}
+
+RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width)
+{
+ chunks.push_back(RTLIL::SigChunk(bit, width));
+ this->width = chunks.back().width;
+ check();
+}
+
+void RTLIL::SigSpec::expand()
+{
+ std::vector<RTLIL::SigChunk> new_chunks;
+ for (size_t i = 0; i < chunks.size(); i++) {
+ assert(chunks[i].data.str.empty());
+ for (int j = 0; j < chunks[i].width; j++)
+ new_chunks.push_back(chunks[i].extract(j, 1));
+ }
+ chunks.swap(new_chunks);
+ check();
+}
+
+void RTLIL::SigSpec::optimize()
+{
+ for (size_t i = 0; i < chunks.size(); i++) {
+ if (chunks[i].wire && chunks[i].wire->auto_width)
+ continue;
+ if (chunks[i].width == 0)
+ chunks.erase(chunks.begin()+i--);
+ }
+ for (size_t i = 1; i < chunks.size(); i++) {
+ RTLIL::SigChunk &ch1 = chunks[i-1];
+ RTLIL::SigChunk &ch2 = chunks[i];
+ if (ch1.wire && ch1.wire->auto_width)
+ continue;
+ if (ch2.wire && ch2.wire->auto_width)
+ continue;
+ if (ch1.wire == ch2.wire) {
+ if (ch1.wire != NULL && ch1.offset+ch1.width == ch2.offset) {
+ ch1.width += ch2.width;
+ goto merged_with_next_chunk;
+ }
+ if (ch1.wire == NULL && ch1.data.str.empty() == ch2.data.str.empty()) {
+ ch1.data.str = ch2.data.str + ch1.data.str;
+ ch1.data.bits.insert(ch1.data.bits.end(), ch2.data.bits.begin(), ch2.data.bits.end());
+ ch1.width += ch2.width;
+ goto merged_with_next_chunk;
+ }
+ }
+ if (0) {
+ merged_with_next_chunk:
+ chunks.erase(chunks.begin()+i);
+ i--;
+ }
+ }
+ check();
+}
+
+static bool compare_sigchunks(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b)
+{
+ 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;
+}
+
+void RTLIL::SigSpec::sort_and_unify()
+{
+ expand();
+ std::sort(chunks.begin(), chunks.end(), compare_sigchunks);
+ for (size_t i = 1; i < chunks.size(); i++) {
+ RTLIL::SigChunk &ch1 = chunks[i-1];
+ RTLIL::SigChunk &ch2 = chunks[i];
+ if (!compare_sigchunks(ch1, ch2) && !compare_sigchunks(ch2, ch1)) {
+ chunks.erase(chunks.begin()+i);
+ width -= chunks[i].width;
+ i--;
+ }
+ }
+ optimize();
+}
+
+void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with)
+{
+ replace(pattern, with, this);
+}
+
+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;
+ }
+ check();
+}
+
+void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern)
+{
+ remove2(pattern, NULL);
+}
+
+void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const
+{
+ RTLIL::SigSpec tmp = *this;
+ tmp.remove2(pattern, 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;
+ }
+ check();
+}
+
+RTLIL::SigSpec RTLIL::SigSpec::extract(RTLIL::SigSpec pattern, RTLIL::SigSpec *other) const
+{
+ int pos = 0;
+ RTLIL::SigSpec ret;
+ pattern.sort_and_unify();
+ assert(other == NULL || width == other->width);
+ for (size_t i = 0; i < chunks.size(); i++) {
+ const RTLIL::SigChunk &ch1 = chunks[i];
+ if (chunks[i].wire != NULL)
+ for (size_t j = 0; j < pattern.chunks.size(); j++) {
+ 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)
+ ret.append(other->extract(pos+lower-ch1.offset, upper-lower));
+ else
+ ret.append(extract(pos+lower-ch1.offset, upper-lower));
+ }
+ }
+ }
+ pos += chunks[i].width;
+ }
+ ret.check();
+ return ret;
+}
+
+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;
+ 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--));
+ }
+ 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;
+ }
+ 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;
+}
+
+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;
+ }
+ check();
+}
+
+bool RTLIL::SigSpec::combine(RTLIL::SigSpec signal, RTLIL::State freeState, bool override)
+{
+ bool no_collisions = true;
+
+ assert(width == signal.width);
+ expand();
+ signal.expand();
+
+ 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];
+ else
+ chunks[i] = RTLIL::SigChunk(RTLIL::State::Sx, 1);
+ no_collisions = false;
+ }
+ if (self_free && !other_free)
+ chunks[i] = signal.chunks[i];
+ }
+
+ optimize();
+ return no_collisions;
+}
+
+void RTLIL::SigSpec::extend(int width, bool is_signed)
+{
+ if (this->width > width)
+ remove(width, this->width - width);
+
+ if (this->width < width) {
+ RTLIL::SigSpec padding = this->width > 0 ? extract(this->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)
+ append(padding);
+ }
+
+ optimize();
+}
+
+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);
+ assert(chunk.data.str.size() == 0 || chunk.data.str.size()*8 == chunk.data.bits.size());
+ } else {
+ assert(chunk.offset >= 0);
+ assert(chunk.width >= 0);
+ assert(chunk.offset + chunk.width <= chunk.wire->width);
+ assert(chunk.data.bits.size() == 0);
+ assert(chunk.data.str.size() == 0);
+ }
+ w += chunk.width;
+ }
+ assert(w == width);
+}
+
+bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const
+{
+ if (width != other.width)
+ return width < other.width;
+
+ RTLIL::SigSpec a = *this, b = other;
+ a.optimize();
+ b.optimize();
+
+ if (a.chunks.size() != b.chunks.size())
+ return a.chunks.size() < b.chunks.size();
+
+ for (size_t i = 0; i < a.chunks.size(); i++)
+ if (a.chunks[i] != b.chunks[i])
+ return a.chunks[i] < b.chunks[i];
+
+ return false;
+}
+
+bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const
+{
+ if (width != other.width)
+ return false;
+
+ RTLIL::SigSpec a = *this, b = other;
+ a.optimize();
+ b.optimize();
+
+ if (a.chunks.size() != b.chunks.size())
+ return false;
+
+ for (size_t i = 0; i < a.chunks.size(); i++)
+ if (a.chunks[i] != b.chunks[i])
+ return false;
+
+ return true;
+}
+
+bool RTLIL::SigSpec::operator !=(const RTLIL::SigSpec &other) const
+{
+ if (*this == other)
+ return false;
+ return true;
+}
+
+bool RTLIL::SigSpec::is_fully_const() const
+{
+ for (auto it = chunks.begin(); it != chunks.end(); it++)
+ if (it->width > 0 && it->wire != NULL)
+ return false;
+ return true;
+}
+
+bool RTLIL::SigSpec::is_fully_def() const
+{
+ 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)
+ return false;
+ }
+ return true;
+}
+
+bool RTLIL::SigSpec::is_fully_undef() const
+{
+ 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)
+ return false;
+ }
+ return true;
+}
+
+bool RTLIL::SigSpec::has_marked_bits() const
+{
+ 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)
+ return true;
+ }
+ return false;
+}
+
+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();
+ return false;
+}
+
+int RTLIL::SigSpec::as_int() const
+{
+ assert(is_fully_const());
+ SigSpec sig = *this;
+ sig.optimize();
+ if (sig.width)
+ return sig.chunks[0].data.as_int();
+ return 0;
+}
+
+std::string RTLIL::SigSpec::as_string() const
+{
+ std::string str;
+ 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();
+ }
+ 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;
+ return RTLIL::Const();
+}
+
+bool RTLIL::SigSpec::match(std::string pattern) const
+{
+ std::string str = as_string();
+ assert(pattern.size() == str.size());
+
+ for (size_t i = 0; i < pattern.size(); i++) {
+ if (pattern[i] == ' ')
+ continue;
+ if (pattern[i] == '*') {
+ if (str[i] != 'z' && str[i] != 'x')
+ return false;
+ continue;
+ }
+ if (pattern[i] != str[i])
+ return false;
+ }
+
+ return true;
+}
+
+RTLIL::CaseRule::~CaseRule()
+{
+ for (auto it = switches.begin(); it != switches.end(); it++)
+ 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::SwitchRule::~SwitchRule()
+{
+ for (auto it = cases.begin(); it != cases.end(); it++)
+ delete *it;
+}
+
+void RTLIL::SwitchRule::optimize()
+{
+ signal.optimize();
+ for (auto it : cases)
+ it->optimize();
+}
+
+void RTLIL::SyncRule::optimize()
+{
+ signal.optimize();
+ for (auto &it : actions) {
+ it.first.optimize();
+ it.second.optimize();
+ }
+}
+
+RTLIL::Process::~Process()
+{
+ for (auto it = syncs.begin(); it != syncs.end(); it++)
+ delete *it;
+}
+
+void RTLIL::Process::optimize()
+{
+ root_case.optimize();
+ for (auto it : syncs)
+ it->optimize();
+}
+
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
new file mode 100644
index 00000000..1f45d120
--- /dev/null
+++ b/kernel/rtlil.h
@@ -0,0 +1,341 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef RTLIL_H
+#define RTLIL_H
+
+#include <map>
+#include <set>
+#include <vector>
+#include <string>
+#include <assert.h>
+
+std::string stringf(const char *fmt, ...);
+
+namespace RTLIL
+{
+ enum 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)
+ };
+ enum SyncType {
+ ST0 = 0, // level sensitive: 0
+ ST1 = 1, // level sensitive: 1
+ STp = 2, // edge sensitive: posedge
+ STn = 3, // edge sensitive: negedge
+ STe = 4, // edge sensitive: both edges
+ STa = 5 // always active
+ };
+
+ extern int autoidx;
+
+ struct Const;
+ struct Selection;
+ struct Design;
+ struct Module;
+ struct Wire;
+ struct Memory;
+ struct Cell;
+ struct SigChunk;
+ struct SigSpec;
+ struct CaseRule;
+ struct SwitchRule;
+ struct SyncRule;
+ struct Process;
+
+ 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();
+ }
+ IdString(const char *s) : std::string(s) {
+ check();
+ }
+ IdString &operator=(const std::string &str) {
+ std::string::operator=(str);
+ check();
+ return *this;
+ }
+ IdString &operator=(const char *s) {
+ std::string::operator=(s);
+ check();
+ return *this;
+ }
+ bool operator<(const IdString &rhs) {
+ check(), rhs.check();
+ return std::string(*this) < std::string(rhs);
+ }
+ void check() const {
+ assert(empty() || (size() >= 2 && (at(0) == '$' || at(0) == '\\')));
+ }
+ };
+#endif
+
+ static IdString escape_id(std::string str) __attribute__((unused));
+ static IdString 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) {
+ if (str.size() > 0 && str[0] == '\\')
+ return str.substr(1);
+ return 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;
+ }
+
+#define NEW_ID \
+ RTLIL::new_id(__FILE__, __LINE__, __FUNCTION__)
+
+ // 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);
+ RTLIL::Const const_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_xor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_xnor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+
+ RTLIL::Const const_reduce_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_reduce_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_reduce_xor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_reduce_xnor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_reduce_bool (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+
+ RTLIL::Const const_logic_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_logic_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_logic_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+
+ RTLIL::Const const_shl (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ 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_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);
+ RTLIL::Const const_eq (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_ne (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_ge (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_gt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+
+ RTLIL::Const const_add (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_sub (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_mul (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_div (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_mod (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ 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_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+};
+
+struct RTLIL::Const {
+ std::string str;
+ std::vector<RTLIL::State> bits;
+ Const(std::string str = std::string());
+ Const(int val, int width = 32);
+ Const(RTLIL::State bit, int width = 1);
+ Const(std::vector<RTLIL::State> bits) : bits(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;
+ std::string as_string() const;
+};
+
+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);
+ bool selected_whole_module(RTLIL::IdString mod_name);
+ bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name);
+ void optimize(RTLIL::Design *design);
+};
+
+struct RTLIL::Design {
+ 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();
+ void check();
+ void optimize();
+ bool selected_module(RTLIL::IdString mod_name);
+ bool selected_whole_module(RTLIL::IdString mod_name);
+ bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name);
+ template<typename T1> bool selected(T1 *module) {
+ return selected_module(module->name);
+ }
+ template<typename T1, typename T2> bool selected(T1 *module, T2 *member) {
+ return selected_member(module->name, member->name);
+ }
+};
+
+struct RTLIL::Module {
+ RTLIL::IdString name;
+ 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;
+ std::map<RTLIL::IdString, RTLIL::Const> attributes;
+ virtual ~Module();
+ virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
+ virtual void update_auto_wires(std::map<RTLIL::IdString, int> auto_sizes);
+ virtual size_t count_id(RTLIL::IdString id);
+ virtual void check();
+ virtual void optimize();
+ void add(RTLIL::Wire *wire);
+ void add(RTLIL::Cell *cell);
+};
+
+struct RTLIL::Wire {
+ RTLIL::IdString name;
+ int width, start_offset, port_id;
+ bool port_input, port_output, auto_width;
+ std::map<RTLIL::IdString, RTLIL::Const> attributes;
+ Wire();
+};
+
+struct RTLIL::Memory {
+ RTLIL::IdString name;
+ int width, start_offset, size;
+ std::map<RTLIL::IdString, RTLIL::Const> attributes;
+ Memory();
+};
+
+struct RTLIL::Cell {
+ RTLIL::IdString name;
+ RTLIL::IdString type;
+ std::map<RTLIL::IdString, RTLIL::SigSpec> connections;
+ std::map<RTLIL::IdString, RTLIL::Const> attributes;
+ std::map<RTLIL::IdString, RTLIL::Const> parameters;
+ void optimize();
+};
+
+struct RTLIL::SigChunk {
+ RTLIL::Wire *wire;
+ RTLIL::Const 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 std::string &str);
+ SigChunk(int val, int width = 32);
+ SigChunk(RTLIL::State bit, int width = 1);
+ RTLIL::SigChunk extract(int offset, int length) const;
+ bool operator <(const RTLIL::SigChunk &other) const;
+ bool operator ==(const RTLIL::SigChunk &other) const;
+ bool operator !=(const RTLIL::SigChunk &other) const;
+};
+
+struct RTLIL::SigSpec {
+ std::vector<RTLIL::SigChunk> chunks; // LSB at index 0
+ int width;
+ SigSpec();
+ SigSpec(const RTLIL::Const &data);
+ SigSpec(const RTLIL::SigChunk &chunk);
+ SigSpec(RTLIL::Wire *wire, int width = -1, int offset = 0);
+ SigSpec(const std::string &str);
+ SigSpec(int val, int width = 32);
+ SigSpec(RTLIL::State bit, int width = 1);
+ void expand();
+ void optimize();
+ 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 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();
+ void remove(int offset, int length);
+ RTLIL::SigSpec extract(int offset, int length) const;
+ void append(const RTLIL::SigSpec &signal);
+ bool combine(RTLIL::SigSpec signal, RTLIL::State freeState = RTLIL::State::Sz, bool override = false);
+ void extend(int width, bool is_signed = false);
+ void check() const;
+ bool operator <(const RTLIL::SigSpec &other) const;
+ bool operator ==(const RTLIL::SigSpec &other) const;
+ bool operator !=(const RTLIL::SigSpec &other) 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;
+ std::string as_string() const;
+ RTLIL::Const as_const() const;
+ bool match(std::string pattern) const;
+};
+
+struct RTLIL::CaseRule {
+ std::vector<RTLIL::SigSpec> compare;
+ std::vector<RTLIL::SigSig> actions;
+ std::vector<RTLIL::SwitchRule*> switches;
+ ~CaseRule();
+ void optimize();
+};
+
+struct RTLIL::SwitchRule {
+ RTLIL::SigSpec signal;
+ std::map<RTLIL::IdString, RTLIL::Const> attributes;
+ std::vector<RTLIL::CaseRule*> cases;
+ ~SwitchRule();
+ void optimize();
+};
+
+struct RTLIL::SyncRule {
+ RTLIL::SyncType type;
+ RTLIL::SigSpec signal;
+ std::vector<RTLIL::SigSig> actions;
+ void optimize();
+};
+
+struct RTLIL::Process {
+ RTLIL::IdString name;
+ std::map<RTLIL::IdString, RTLIL::Const> attributes;
+ RTLIL::CaseRule root_case;
+ std::vector<RTLIL::SyncRule*> syncs;
+ ~Process();
+ void optimize();
+};
+
+#endif
diff --git a/kernel/select.cc b/kernel/select.cc
new file mode 100644
index 00000000..8a91f1b1
--- /dev/null
+++ b/kernel/select.cc
@@ -0,0 +1,476 @@
+/*
+ * 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 <string.h>
+#include <fnmatch.h>
+
+static std::vector<RTLIL::Selection> work_stack;
+
+static bool match_ids(RTLIL::IdString id, std::string pattern)
+{
+ if (!fnmatch(pattern.c_str(), id.c_str(), FNM_NOESCAPE))
+ return true;
+ if (id.size() > 0 && id[0] == '\\' && !fnmatch(pattern.c_str(), id.substr(1).c_str(), FNM_NOESCAPE))
+ return true;
+ return false;
+}
+
+static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs)
+{
+ if (lhs.full_selection) {
+ lhs.full_selection = false;
+ lhs.selected_modules.clear();
+ lhs.selected_members.clear();
+ return;
+ }
+
+ if (lhs.selected_modules.size() == 0 && lhs.selected_members.size() == 0) {
+ lhs.full_selection = true;
+ return;
+ }
+
+ RTLIL::Selection new_sel(false);
+
+ for (auto &mod_it : design->modules)
+ {
+ if (lhs.selected_whole_module(mod_it.first))
+ continue;
+ if (!lhs.selected_module(mod_it.first)) {
+ new_sel.selected_modules.insert(mod_it.first);
+ continue;
+ }
+
+ RTLIL::Module *mod = mod_it.second;
+ 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)
+ if (!lhs.selected_member(mod_it.first, it.first))
+ new_sel.selected_members[mod->name].insert(it.first);
+ for (auto &it : mod->processes)
+ if (!lhs.selected_member(mod_it.first, it.first))
+ new_sel.selected_members[mod->name].insert(it.first);
+ }
+
+ lhs.selected_modules.swap(new_sel.selected_modules);
+ lhs.selected_members.swap(new_sel.selected_members);
+}
+
+static void select_op_union(RTLIL::Design*, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
+{
+ if (rhs.full_selection) {
+ lhs.full_selection = true;
+ lhs.selected_modules.clear();
+ lhs.selected_members.clear();
+ return;
+ }
+
+ if (lhs.full_selection)
+ return;
+
+ for (auto &it : rhs.selected_members)
+ for (auto &it2 : it.second)
+ lhs.selected_members[it.first].insert(it2);
+
+ for (auto &it : rhs.selected_modules) {
+ lhs.selected_modules.insert(it);
+ lhs.selected_members.erase(it);
+ }
+}
+
+static void select_op_diff(RTLIL::Design *design, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
+{
+ if (rhs.full_selection) {
+ lhs.full_selection = false;
+ lhs.selected_modules.clear();
+ lhs.selected_members.clear();
+ return;
+ }
+
+ if (lhs.full_selection) {
+ if (!rhs.full_selection && rhs.selected_modules.size() == 0 && rhs.selected_members.size() == 0)
+ return;
+ lhs.full_selection = false;
+ for (auto &it : design->modules)
+ lhs.selected_modules.insert(it.first);
+ }
+
+ for (auto &it : rhs.selected_modules) {
+ lhs.selected_modules.erase(it);
+ lhs.selected_members.erase(it);
+ }
+
+ for (auto &it : rhs.selected_members)
+ {
+ if (design->modules.count(it.first) == 0)
+ continue;
+
+ RTLIL::Module *mod = design->modules[it.first];
+
+ if (lhs.selected_modules.count(mod->name) > 0)
+ {
+ 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)
+ lhs.selected_members[mod->name].insert(it.first);
+ for (auto &it : mod->processes)
+ lhs.selected_members[mod->name].insert(it.first);
+ lhs.selected_modules.erase(mod->name);
+ }
+
+ if (lhs.selected_members.count(mod->name) == 0)
+ continue;
+
+ for (auto &it2 : it.second)
+ lhs.selected_members[mod->name].erase(it2);
+ }
+}
+
+static void select_op_intersect(RTLIL::Design *design, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
+{
+ if (rhs.full_selection)
+ return;
+
+ if (lhs.full_selection) {
+ lhs.full_selection = false;
+ for (auto &it : design->modules)
+ lhs.selected_modules.insert(it.first);
+ }
+
+ std::vector<RTLIL::IdString> del_list;
+
+ for (auto &it : lhs.selected_modules)
+ if (rhs.selected_modules.count(it) == 0) {
+ if (rhs.selected_members.count(it) > 0)
+ for (auto &it2 : rhs.selected_members.at(it))
+ lhs.selected_members[it].insert(it2);
+ del_list.push_back(it);
+ }
+ for (auto &it : del_list)
+ lhs.selected_modules.erase(it);
+
+ del_list.clear();
+ for (auto &it : lhs.selected_members) {
+ if (rhs.selected_modules.count(it.first) > 0)
+ continue;
+ if (rhs.selected_members.count(it.first) == 0) {
+ del_list.push_back(it.first);
+ continue;
+ }
+ std::vector<RTLIL::IdString> del_list2;
+ for (auto &it2 : it.second)
+ if (rhs.selected_members.at(it.first).count(it2) == 0)
+ del_list2.push_back(it2);
+ for (auto &it2 : del_list2)
+ it.second.erase(it2);
+ if (it.second.size() == 0)
+ del_list.push_back(it.first);
+ }
+ for (auto &it : del_list)
+ lhs.selected_members.erase(it);
+}
+
+static void select_filter_active_mod(RTLIL::Design *design, RTLIL::Selection &sel)
+{
+ if (design->selected_active_module.empty())
+ return;
+
+ if (sel.full_selection) {
+ sel.full_selection = false;
+ sel.selected_modules.clear();
+ sel.selected_members.clear();
+ sel.selected_modules.insert(design->selected_active_module);
+ return;
+ }
+
+ std::vector<std::string> del_list;
+ for (auto mod_name : sel.selected_modules)
+ if (mod_name != design->selected_active_module)
+ del_list.push_back(mod_name);
+ for (auto &it : sel.selected_members)
+ if (it.first != design->selected_active_module)
+ del_list.push_back(it.first);
+ for (auto mod_name : del_list) {
+ sel.selected_modules.erase(mod_name);
+ sel.selected_members.erase(mod_name);
+ }
+}
+
+static void select_stmt(RTLIL::Design *design, std::string arg)
+{
+ std::string arg_mod, arg_memb;
+
+ if (arg.size() == 0)
+ return;
+
+ if (arg[0] == '#') {
+ if (arg == "#") {
+ if (design->selection_stack.size() > 0)
+ work_stack.push_back(design->selection_stack.back());
+ } else
+ if (arg == "#n") {
+ if (work_stack.size() < 1)
+ log_cmd_error("Must have at least one element on stack for operator #n.\n");
+ select_op_neg(design, work_stack[work_stack.size()-1]);
+ } else
+ if (arg == "#u") {
+ if (work_stack.size() < 2)
+ log_cmd_error("Must have at least two elements on stack for operator #u.\n");
+ select_op_union(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 stack for operator #d.\n");
+ select_op_diff(design, 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 stack for operator #i.\n");
+ select_op_intersect(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
+ work_stack.pop_back();
+ } else
+ log_cmd_error("Unknown selection operator '%s'.\n", arg.c_str());
+ select_filter_active_mod(design, work_stack.back());
+ return;
+ }
+
+ if (!design->selected_active_module.empty()) {
+ arg_mod = design->selected_active_module;
+ arg_memb = arg;
+ } else {
+ size_t pos = arg.find('/');
+ if (pos == std::string::npos) {
+ arg_mod = arg;
+ } else {
+ arg_mod = arg.substr(0, pos);
+ arg_memb = arg.substr(pos+1);
+ }
+ }
+
+ work_stack.push_back(RTLIL::Selection());
+ RTLIL::Selection &sel = work_stack.back();
+
+ if (arg == "*" && arg_mod == "*") {
+ select_filter_active_mod(design, work_stack.back());
+ return;
+ }
+
+ sel.full_selection = false;
+ for (auto &mod_it : design->modules)
+ {
+ if (!match_ids(mod_it.first, arg_mod))
+ continue;
+
+ if (arg_memb == "") {
+ sel.selected_modules.insert(mod_it.first);
+ continue;
+ }
+
+ RTLIL::Module *mod = mod_it.second;
+ if (arg_memb.substr(0, 2) == "w:") {
+ 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) == "m:") {
+ for (auto &it : mod->memories)
+ if (match_ids(it.first, arg_memb.substr(2)))
+ sel.selected_members[mod->name].insert(it.first);
+ } else
+ if (arg_memb.substr(0, 2) == "c:") {
+ 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)
+ if (match_ids(it.second->type, arg_memb.substr(2)))
+ sel.selected_members[mod->name].insert(it.first);
+ } else
+ if (arg_memb.substr(0, 2) == "p:") {
+ for (auto &it : mod->processes)
+ if (match_ids(it.first, 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)
+ 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)
+ if (match_ids(it.first, arg_memb))
+ sel.selected_members[mod->name].insert(it.first);
+ for (auto &it : mod->processes)
+ if (match_ids(it.first, arg_memb))
+ sel.selected_members[mod->name].insert(it.first);
+ }
+ }
+
+ select_filter_active_mod(design, work_stack.back());
+}
+
+struct SelectPass : public Pass {
+ SelectPass() : Pass("select") { }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ bool add_mode = false;
+ bool del_mode = false;
+ bool clear_mode = false;
+ bool list_mode = false;
+ bool got_module = false;
+
+ work_stack.clear();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+ if (arg == "-add") {
+ add_mode = true;
+ continue;
+ }
+ if (arg == "-del") {
+ del_mode = true;
+ continue;
+ }
+ if (arg == "-clear") {
+ clear_mode = true;
+ continue;
+ }
+ if (arg == "-list") {
+ list_mode = true;
+ continue;
+ }
+ if (arg == "-module" && argidx+1 < args.size()) {
+ RTLIL::IdString mod_name = RTLIL::escape_id(args[++argidx]);
+ if (design->modules.count(mod_name) == 0)
+ log_cmd_error("No such module: %s\n", mod_name.c_str());
+ design->selected_active_module = mod_name;
+ got_module = true;
+ continue;
+ }
+ if (arg.size() > 0 && arg[0] == '-')
+ log_cmd_error("Unkown option %s.\n", arg.c_str());
+ select_stmt(design, arg);
+ }
+
+ if (clear_mode && args.size() != 2)
+ log_cmd_error("Option -clear can not be combined with other options.\n");
+
+ if (add_mode && del_mode)
+ log_cmd_error("Options -add and -del can not be combined.\n");
+
+ if (list_mode && (add_mode || del_mode))
+ log_cmd_error("Option -list can not be combined with -add or -del.\n");
+
+ if (work_stack.size() == 0 && got_module) {
+ RTLIL::Selection sel;
+ select_filter_active_mod(design, sel);
+ work_stack.push_back(sel);
+ }
+
+ while (work_stack.size() > 1) {
+ select_op_union(design, work_stack.front(), work_stack.back());
+ work_stack.pop_back();
+ }
+
+ assert(design->selection_stack.size() > 0);
+
+ if (clear_mode)
+ {
+ design->selection_stack.back() = RTLIL::Selection(true);
+ design->selected_active_module = std::string();
+ return;
+ }
+
+ if (list_mode)
+ {
+ RTLIL::Selection *sel = &design->selection_stack.back();
+ if (work_stack.size() > 0)
+ sel = &work_stack.back();
+ sel->optimize(design);
+ for (auto mod_it : design->modules)
+ {
+ if (design->selected_whole_module(mod_it.first))
+ log("%s\n", mod_it.first.c_str());
+ if (design->selected_module(mod_it.first)) {
+ for (auto &it : mod_it.second->wires)
+ if (design->selected_member(mod_it.first, it.first))
+ log("%s/%s\n", mod_it.first.c_str(), it.first.c_str());
+ for (auto &it : mod_it.second->memories)
+ if (design->selected_member(mod_it.first, it.first))
+ log("%s/%s\n", mod_it.first.c_str(), it.first.c_str());
+ for (auto &it : mod_it.second->cells)
+ if (design->selected_member(mod_it.first, it.first))
+ log("%s/%s\n", mod_it.first.c_str(), it.first.c_str());
+ for (auto &it : mod_it.second->processes)
+ if (design->selected_member(mod_it.first, it.first))
+ log("%s/%s\n", mod_it.first.c_str(), it.first.c_str());
+ }
+ }
+ return;
+ }
+
+ if (add_mode)
+ {
+ if (work_stack.size() == 0)
+ log_cmd_error("Nothing to add to selection.\n");
+ select_op_union(design, design->selection_stack.back(), work_stack.back());
+ design->selection_stack.back().optimize(design);
+ return;
+ }
+
+ if (del_mode)
+ {
+ if (work_stack.size() == 0)
+ log_cmd_error("Nothing to delete from selection.\n");
+ select_op_diff(design, design->selection_stack.back(), work_stack.back());
+ design->selection_stack.back().optimize(design);
+ return;
+ }
+
+ if (work_stack.size() == 0) {
+ RTLIL::Selection &sel = design->selection_stack.back();
+ if (sel.full_selection)
+ log("*\n");
+ for (auto &it : sel.selected_modules)
+ log("%s\n", it.c_str());
+ for (auto &it : sel.selected_members)
+ for (auto &it2 : it.second)
+ log("%s/%s\n", it.first.c_str(), it2.c_str());
+ return;
+ }
+
+ design->selection_stack.back() = work_stack.back();
+ design->selection_stack.back().optimize(design);
+ }
+} SelectPass;
+
diff --git a/kernel/sha1.cpp b/kernel/sha1.cpp
new file mode 100644
index 00000000..fb7bfed6
--- /dev/null
+++ b/kernel/sha1.cpp
@@ -0,0 +1,185 @@
+/*
+ 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);
+ }
+