initial import
authorClifford Wolf <clifford@clifford.at>
Sat, 5 Jan 2013 10:13:26 +0000 (11:13 +0100)
committerClifford Wolf <clifford@clifford.at>
Sat, 5 Jan 2013 10:13:26 +0000 (11:13 +0100)
481 files changed:
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
backends/autotest/Makefile.inc [new file with mode: 0644]
backends/autotest/autotest.cc [new file with mode: 0644]
backends/ilang/Makefile.inc [new file with mode: 0644]
backends/ilang/ilang_backend.cc [new file with mode: 0644]
backends/ilang/ilang_backend.h [new file with mode: 0644]
backends/verilog/Makefile.inc [new file with mode: 0644]
backends/verilog/verilog_backend.cc [new file with mode: 0644]
backends/verilog/verilog_backend.h [new file with mode: 0644]
bigint/.gitignore [new file with mode: 0644]
bigint/BigInteger.cc [new file with mode: 0644]
bigint/BigInteger.hh [new file with mode: 0644]
bigint/BigIntegerAlgorithms.cc [new file with mode: 0644]
bigint/BigIntegerAlgorithms.hh [new file with mode: 0644]
bigint/BigIntegerLibrary.hh [new file with mode: 0644]
bigint/BigIntegerUtils.cc [new file with mode: 0644]
bigint/BigIntegerUtils.hh [new file with mode: 0644]
bigint/BigUnsigned.cc [new file with mode: 0644]
bigint/BigUnsigned.hh [new file with mode: 0644]
bigint/BigUnsignedInABase.cc [new file with mode: 0644]
bigint/BigUnsignedInABase.hh [new file with mode: 0644]
bigint/ChangeLog [new file with mode: 0644]
bigint/Makefile [new file with mode: 0644]
bigint/NumberlikeArray.hh [new file with mode: 0644]
bigint/README [new file with mode: 0644]
bigint/run-testsuite [new file with mode: 0755]
bigint/sample.cc [new file with mode: 0644]
bigint/testsuite.cc [new file with mode: 0644]
frontends/ast/Makefile.inc [new file with mode: 0644]
frontends/ast/ast.cc [new file with mode: 0644]
frontends/ast/ast.h [new file with mode: 0644]
frontends/ast/genrtlil.cc [new file with mode: 0644]
frontends/ast/simplify.cc [new file with mode: 0644]
frontends/ilang/Makefile.inc [new file with mode: 0644]
frontends/ilang/ilang_frontend.cc [new file with mode: 0644]
frontends/ilang/ilang_frontend.h [new file with mode: 0644]
frontends/ilang/lexer.l [new file with mode: 0644]
frontends/ilang/parser.y [new file with mode: 0644]
frontends/verilog/Makefile.inc [new file with mode: 0644]
frontends/verilog/const2ast.cc [new file with mode: 0644]
frontends/verilog/lexer.l [new file with mode: 0644]
frontends/verilog/parser.y [new file with mode: 0644]
frontends/verilog/preproc.cc [new file with mode: 0644]
frontends/verilog/verilog_frontend.cc [new file with mode: 0644]
frontends/verilog/verilog_frontend.h [new file with mode: 0644]
kernel/bitpattern.h [new file with mode: 0644]
kernel/calc.cc [new file with mode: 0644]
kernel/celltypes.h [new file with mode: 0644]
kernel/consteval.h [new file with mode: 0644]
kernel/driver.cc [new file with mode: 0644]
kernel/log.cc [new file with mode: 0644]
kernel/log.h [new file with mode: 0644]
kernel/register.cc [new file with mode: 0644]
kernel/register.h [new file with mode: 0644]
kernel/rtlil.cc [new file with mode: 0644]
kernel/rtlil.h [new file with mode: 0644]
kernel/select.cc [new file with mode: 0644]
kernel/sha1.cpp [new file with mode: 0644]
kernel/sha1.h [new file with mode: 0644]
kernel/show.cc [new file with mode: 0644]
kernel/sigtools.h [new file with mode: 0644]
passes/abc/Makefile.inc [new file with mode: 0644]
passes/abc/abc.cc [new file with mode: 0644]
passes/abc/vlparse.cc [new file with mode: 0644]
passes/abc/vlparse.h [new file with mode: 0644]
passes/dfflibmap/Makefile.inc [new file with mode: 0644]
passes/dfflibmap/dfflibmap.cc [new file with mode: 0644]
passes/dfflibmap/filterlib.cc [new file with mode: 0644]
passes/dfflibmap/libparse.cc [new file with mode: 0644]
passes/dfflibmap/libparse.h [new file with mode: 0644]
passes/fsm/Makefile.inc [new file with mode: 0644]
passes/fsm/fsm.cc [new file with mode: 0644]
passes/fsm/fsm_detect.cc [new file with mode: 0644]
passes/fsm/fsm_expand.cc [new file with mode: 0644]
passes/fsm/fsm_export.cc [new file with mode: 0644]
passes/fsm/fsm_extract.cc [new file with mode: 0644]
passes/fsm/fsm_info.cc [new file with mode: 0644]
passes/fsm/fsm_map.cc [new file with mode: 0644]
passes/fsm/fsm_opt.cc [new file with mode: 0644]
passes/fsm/fsm_recode.cc [new file with mode: 0644]
passes/fsm/fsmdata.h [new file with mode: 0644]
passes/hierarchy/Makefile.inc [new file with mode: 0644]
passes/hierarchy/hierarchy.cc [new file with mode: 0644]
passes/memory/Makefile.inc [new file with mode: 0644]
passes/memory/memory.cc [new file with mode: 0644]
passes/memory/memory_collect.cc [new file with mode: 0644]
passes/memory/memory_dff.cc [new file with mode: 0644]
passes/memory/memory_map.cc [new file with mode: 0644]
passes/opt/Makefile.inc [new file with mode: 0644]
passes/opt/opt.cc [new file with mode: 0644]
passes/opt/opt_const.cc [new file with mode: 0644]
passes/opt/opt_muxtree.cc [new file with mode: 0644]
passes/opt/opt_reduce.cc [new file with mode: 0644]
passes/opt/opt_rmdff.cc [new file with mode: 0644]
passes/opt/opt_rmunused.cc [new file with mode: 0644]
passes/opt/opt_share.cc [new file with mode: 0644]
passes/opt/opt_status.h [new file with mode: 0644]
passes/proc/Makefile.inc [new file with mode: 0644]
passes/proc/proc.cc [new file with mode: 0644]
passes/proc/proc_arst.cc [new file with mode: 0644]
passes/proc/proc_clean.cc [new file with mode: 0644]
passes/proc/proc_dff.cc [new file with mode: 0644]
passes/proc/proc_mux.cc [new file with mode: 0644]
passes/proc/proc_rmdead.cc [new file with mode: 0644]
passes/submod/Makefile.inc [new file with mode: 0644]
passes/submod/submod.cc [new file with mode: 0644]
passes/techmap/Makefile.inc [new file with mode: 0644]
passes/techmap/techmap.cc [new file with mode: 0644]
techlibs/Makefile.inc [new file with mode: 0644]
techlibs/blackbox.sed [new file with mode: 0644]
techlibs/simlib.v [new file with mode: 0644]
techlibs/stdcells.v [new file with mode: 0644]
techlibs/stdcells_sim.v [new file with mode: 0644]
tests/asicworld/README [new file with mode: 0644]
tests/asicworld/code_hdl_models_GrayCounter.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_arbiter.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_arbiter_tb.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_cam.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_clk_div.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_clk_div_45.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_d_ff_gates.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_d_latch_gates.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_decoder_2to4_gates.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_decoder_using_assign.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_decoder_using_case.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_dff_async_reset.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_dff_sync_reset.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_dlatch_reset.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_encoder_4to2_gates.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_encoder_using_case.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_encoder_using_if.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_full_adder_gates.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_full_subtracter_gates.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_gray_counter.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_half_adder_gates.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_lfsr.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_lfsr_updown.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_misc1.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_mux21_switch.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_mux_2to1_gates.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_mux_using_assign.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_mux_using_case.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_mux_using_if.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_nand_switch.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_one_hot_cnt.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_parallel_crc.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_parity_using_assign.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_parity_using_bitwise.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_parity_using_function.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_pri_encoder_using_assign.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_ram_sp_ar_sw.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_ram_sp_sr_sw.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_rom_using_case.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_serial_crc.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_t_gate_switch.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_tff_async_reset.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_tff_sync_reset.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_uart.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_up_counter.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_up_counter_load.v [new file with mode: 0644]
tests/asicworld/code_hdl_models_up_down_counter.v [new file with mode: 0644]
tests/asicworld/code_specman_switch_fabric.v [new file with mode: 0644]
tests/asicworld/code_tidbits_asyn_reset.v [new file with mode: 0644]
tests/asicworld/code_tidbits_blocking.v [new file with mode: 0644]
tests/asicworld/code_tidbits_fsm_using_always.v [new file with mode: 0644]
tests/asicworld/code_tidbits_fsm_using_function.v [new file with mode: 0644]
tests/asicworld/code_tidbits_fsm_using_single_always.v [new file with mode: 0644]
tests/asicworld/code_tidbits_nonblocking.v [new file with mode: 0644]
tests/asicworld/code_tidbits_reg_combo_example.v [new file with mode: 0644]
tests/asicworld/code_tidbits_reg_seq_example.v [new file with mode: 0644]
tests/asicworld/code_tidbits_syn_reset.v [new file with mode: 0644]
tests/asicworld/code_tidbits_wire_example.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_addbit.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_always_example.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_bus_con.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_comment.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_counter.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_counter_tb.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_d_ff.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_decoder.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_decoder_always.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_escape_id.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_explicit.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_first_counter.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_first_counter_tb.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_flip_flop.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_fsm_full.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_fsm_full_tb.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_good_code.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_if_else.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_multiply.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_mux_21.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_n_out_primitive.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_parallel_if.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_parity.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_simple_function.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_simple_if.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_task_global.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_tri_buf.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_v2k_reg.v [new file with mode: 0644]
tests/asicworld/code_verilog_tutorial_which_clock.v [new file with mode: 0644]
tests/asicworld/run-test.sh [new file with mode: 0755]
tests/hana/README [new file with mode: 0644]
tests/hana/hana_vlib.v [new file with mode: 0644]
tests/hana/run-test.sh [new file with mode: 0755]
tests/hana/test_intermout_always_comb_1_test.v [new file with mode: 0644]
tests/hana/test_intermout_always_comb_3_test.v [new file with mode: 0644]
tests/hana/test_intermout_always_comb_4_test.v [new file with mode: 0644]
tests/hana/test_intermout_always_comb_5_test.v [new file with mode: 0644]
tests/hana/test_intermout_always_ff_3_test.v [new file with mode: 0644]
tests/hana/test_intermout_always_ff_4_test.v [new file with mode: 0644]
tests/hana/test_intermout_always_ff_5_test.v [new file with mode: 0644]
tests/hana/test_intermout_always_ff_6_test.v [new file with mode: 0644]
tests/hana/test_intermout_always_ff_8_test.v [new file with mode: 0644]
tests/hana/test_intermout_always_ff_9_test.v [new file with mode: 0644]
tests/hana/test_intermout_always_latch_1_test.v [new file with mode: 0644]
tests/hana/test_intermout_bufrm_1_test.v [new file with mode: 0644]
tests/hana/test_intermout_bufrm_2_test.v [new file with mode: 0644]
tests/hana/test_intermout_bufrm_6_test.v [new file with mode: 0644]
tests/hana/test_intermout_bufrm_7_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_add_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_binlogic_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_bitwiseneg_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_buffer_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_condexpr_mux_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_condexpr_tribuf_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_const_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_constshift_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_div_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_logicneg_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_mod_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_mul_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_redand_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_redop_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_sub_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_unaryminus_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_unaryplus_test.v [new file with mode: 0644]
tests/hana/test_intermout_exprs_varshift_test.v [new file with mode: 0644]
tests/hana/test_parse2synthtrans_behavopt_1_test.v [new file with mode: 0644]
tests/hana/test_parse2synthtrans_case_1_test.v [new file with mode: 0644]
tests/hana/test_parse2synthtrans_contassign_1_test.v [new file with mode: 0644]
tests/hana/test_parse2synthtrans_module_basic0_test.v [new file with mode: 0644]
tests/hana/test_parse2synthtrans_operators_1_test.v [new file with mode: 0644]
tests/hana/test_parse2synthtrans_param_1_test.v [new file with mode: 0644]
tests/hana/test_parse2synthtrans_port_scalar_1_test.v [new file with mode: 0644]
tests/hana/test_parse2synthtrans_port_vector_1_test.v [new file with mode: 0644]
tests/hana/test_parse2synthtrans_v2k_comb_logic_sens_list_test.v [new file with mode: 0644]
tests/hana/test_parser_constructs_module_basic1_test.v [new file with mode: 0644]
tests/hana/test_parser_constructs_param_basic0_test.v [new file with mode: 0644]
tests/hana/test_parser_constructs_port_basic0_test.v [new file with mode: 0644]
tests/hana/test_parser_directives_define_simpledef_test.v [new file with mode: 0644]
tests/hana/test_parser_misc_operators_test.v [new file with mode: 0644]
tests/hana/test_parser_v2k_comb_port_data_type_test.v [new file with mode: 0644]
tests/hana/test_parser_v2k_comma_sep_sens_list_test.v [new file with mode: 0644]
tests/hana/test_simulation_always_15_test.v [new file with mode: 0644]
tests/hana/test_simulation_always_17_test.v [new file with mode: 0644]
tests/hana/test_simulation_always_18_test.v [new file with mode: 0644]
tests/hana/test_simulation_always_19_test.v [new file with mode: 0644]
tests/hana/test_simulation_always_1_test.v [new file with mode: 0644]
tests/hana/test_simulation_always_20_test.v [new file with mode: 0644]
tests/hana/test_simulation_always_21_test.v [new file with mode: 0644]
tests/hana/test_simulation_always_22_test.v [new file with mode: 0644]
tests/hana/test_simulation_always_23_test.v [new file with mode: 0644]
tests/hana/test_simulation_always_27_test.v [new file with mode: 0644]
tests/hana/test_simulation_always_29_test.v [new file with mode: 0644]
tests/hana/test_simulation_always_31_tt.v [new file with mode: 0644]
tests/hana/test_simulation_and_1_test.v [new file with mode: 0644]
tests/hana/test_simulation_and_2_test.v [new file with mode: 0644]
tests/hana/test_simulation_and_3_test.v [new file with mode: 0644]
tests/hana/test_simulation_and_4_test.v [new file with mode: 0644]
tests/hana/test_simulation_and_5_test.v [new file with mode: 0644]
tests/hana/test_simulation_and_6_test.v [new file with mode: 0644]
tests/hana/test_simulation_and_7_test.v [new file with mode: 0644]
tests/hana/test_simulation_buffer_1_test.v [new file with mode: 0644]
tests/hana/test_simulation_buffer_2_test.v [new file with mode: 0644]
tests/hana/test_simulation_buffer_3_test.v [new file with mode: 0644]
tests/hana/test_simulation_decoder_2_test.v [new file with mode: 0644]
tests/hana/test_simulation_decoder_3_test.v [new file with mode: 0644]
tests/hana/test_simulation_decoder_4_test.v [new file with mode: 0644]
tests/hana/test_simulation_decoder_5_test.v [new file with mode: 0644]
tests/hana/test_simulation_decoder_6_test.v [new file with mode: 0644]
tests/hana/test_simulation_decoder_7_test.v [new file with mode: 0644]
tests/hana/test_simulation_decoder_8_test.v [new file with mode: 0644]
tests/hana/test_simulation_inc_16_test.v [new file with mode: 0644]
tests/hana/test_simulation_inc_1_test.v [new file with mode: 0644]
tests/hana/test_simulation_inc_2_test.v [new file with mode: 0644]
tests/hana/test_simulation_inc_32_test.v [new file with mode: 0644]
tests/hana/test_simulation_inc_4_test.v [new file with mode: 0644]
tests/hana/test_simulation_inc_8_test.v [new file with mode: 0644]
tests/hana/test_simulation_mod_1_xx.v [new file with mode: 0644]
tests/hana/test_simulation_mux_16_test.v [new file with mode: 0644]
tests/hana/test_simulation_mux_2_test.v [new file with mode: 0644]
tests/hana/test_simulation_mux_32_test.v [new file with mode: 0644]
tests/hana/test_simulation_mux_4_test.v [new file with mode: 0644]
tests/hana/test_simulation_mux_64_test.v [new file with mode: 0644]
tests/hana/test_simulation_mux_8_test.v [new file with mode: 0644]
tests/hana/test_simulation_nand_1_test.v [new file with mode: 0644]
tests/hana/test_simulation_nand_3_test.v [new file with mode: 0644]
tests/hana/test_simulation_nand_4_test.v [new file with mode: 0644]
tests/hana/test_simulation_nand_5_test.v [new file with mode: 0644]
tests/hana/test_simulation_nand_6_test.v [new file with mode: 0644]
tests/hana/test_simulation_nor_1_test.v [new file with mode: 0644]
tests/hana/test_simulation_nor_2_test.v [new file with mode: 0644]
tests/hana/test_simulation_nor_3_test.v [new file with mode: 0644]
tests/hana/test_simulation_nor_4_test.v [new file with mode: 0644]
tests/hana/test_simulation_opt_constprop_contassign_1_test.v [new file with mode: 0644]
tests/hana/test_simulation_or_1_test.v [new file with mode: 0644]
tests/hana/test_simulation_or_2_test.v [new file with mode: 0644]
tests/hana/test_simulation_or_3_test.v [new file with mode: 0644]
tests/hana/test_simulation_or_4_test.v [new file with mode: 0644]
tests/hana/test_simulation_or_5_test.v [new file with mode: 0644]
tests/hana/test_simulation_or_6_test.v [new file with mode: 0644]
tests/hana/test_simulation_seq_ff_1_test.v [new file with mode: 0644]
tests/hana/test_simulation_seq_ff_2_test.v [new file with mode: 0644]
tests/hana/test_simulation_shifter_left_16_test.v [new file with mode: 0644]
tests/hana/test_simulation_shifter_left_32_test.v [new file with mode: 0644]
tests/hana/test_simulation_shifter_left_4_test.v [new file with mode: 0644]
tests/hana/test_simulation_shifter_left_64_test.v [new file with mode: 0644]
tests/hana/test_simulation_shifter_left_8_test.v [new file with mode: 0644]
tests/hana/test_simulation_shifter_right_16_test.v [new file with mode: 0644]
tests/hana/test_simulation_shifter_right_32_test.v [new file with mode: 0644]
tests/hana/test_simulation_shifter_right_4_test.v [new file with mode: 0644]
tests/hana/test_simulation_shifter_right_64_test.v [new file with mode: 0644]
tests/hana/test_simulation_shifter_right_8_test.v [new file with mode: 0644]
tests/hana/test_simulation_sop_basic_10_test.v [new file with mode: 0644]
tests/hana/test_simulation_sop_basic_11_test.v [new file with mode: 0644]
tests/hana/test_simulation_sop_basic_12_test.v [new file with mode: 0644]
tests/hana/test_simulation_sop_basic_18_test.v [new file with mode: 0644]
tests/hana/test_simulation_sop_basic_3_test.v [new file with mode: 0644]
tests/hana/test_simulation_sop_basic_7_test.v [new file with mode: 0644]
tests/hana/test_simulation_sop_basic_8_test.v [new file with mode: 0644]
tests/hana/test_simulation_sop_basic_9_test.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_and_19_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_and_5_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_buf_test.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_inv_test.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_mux_0_test.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_mux_128_test.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_mux_8_test.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_nand_19_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_nand_2_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_nand_5_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_nor_19_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_nor_2_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_nor_5_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_or_19_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_or_5_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_xnor_2_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_xnor_5_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_xor_19_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_xor_2_tech.v [new file with mode: 0644]
tests/hana/test_simulation_techmap_xor_5_tech.v [new file with mode: 0644]
tests/hana/test_simulation_tribuf_2_test.v [new file with mode: 0644]
tests/hana/test_simulation_xnor_1_test.v [new file with mode: 0644]
tests/hana/test_simulation_xnor_2_test.v [new file with mode: 0644]
tests/hana/test_simulation_xnor_3_test.v [new file with mode: 0644]
tests/hana/test_simulation_xnor_4_test.v [new file with mode: 0644]
tests/hana/test_simulation_xor_1_test.v [new file with mode: 0644]
tests/hana/test_simulation_xor_2_test.v [new file with mode: 0644]
tests/hana/test_simulation_xor_3_test.v [new file with mode: 0644]
tests/hana/test_simulation_xor_4_test.v [new file with mode: 0644]
tests/i2c_bench/i2c_master_bit_ctrl.v [new file with mode: 0644]
tests/i2c_bench/i2c_master_byte_ctrl.v [new file with mode: 0644]
tests/i2c_bench/i2c_master_defines.v [new file with mode: 0644]
tests/i2c_bench/i2c_master_top.v [new file with mode: 0644]
tests/i2c_bench/i2c_slave_model.v [new file with mode: 0644]
tests/i2c_bench/run-test.sh [new file with mode: 0755]
tests/i2c_bench/spi_slave_model.v [new file with mode: 0644]
tests/i2c_bench/timescale.v [new file with mode: 0644]
tests/i2c_bench/tst_bench_top.v [new file with mode: 0644]
tests/i2c_bench/wb_master_model.v [new file with mode: 0644]
tests/iwls2005/README [new file with mode: 0644]
tests/iwls2005/aes_core/aes_cipher_top.v [new file with mode: 0644]
tests/iwls2005/aes_core/aes_inv_cipher_top.v [new file with mode: 0644]
tests/iwls2005/aes_core/aes_inv_sbox.v [new file with mode: 0644]
tests/iwls2005/aes_core/aes_key_expand_128.v [new file with mode: 0644]
tests/iwls2005/aes_core/aes_rcon.v [new file with mode: 0644]
tests/iwls2005/aes_core/aes_sbox.v [new file with mode: 0644]
tests/iwls2005/aes_core/timescale.v [new file with mode: 0644]
tests/iwls2005/fpu/except.v [new file with mode: 0644]
tests/iwls2005/fpu/fpu.v [new file with mode: 0644]
tests/iwls2005/fpu/post_norm.v [new file with mode: 0644]
tests/iwls2005/fpu/pre_norm.v [new file with mode: 0644]
tests/iwls2005/fpu/pre_norm_fmul.v [new file with mode: 0644]
tests/iwls2005/fpu/primitives.v [new file with mode: 0644]
tests/iwls2005/i2c/i2c_master_bit_ctrl.v [new file with mode: 0644]
tests/iwls2005/i2c/i2c_master_byte_ctrl.v [new file with mode: 0644]
tests/iwls2005/i2c/i2c_master_defines.v [new file with mode: 0644]
tests/iwls2005/i2c/i2c_master_top.v [new file with mode: 0644]
tests/iwls2005/i2c/timescale.v [new file with mode: 0644]
tests/iwls2005/run-fm.sh [new file with mode: 0755]
tests/iwls2005/run-synth.sh [new file with mode: 0755]
tests/iwls2005/run-synth.ys [new file with mode: 0644]
tests/iwls2005/sasc/sasc_brg.v [new file with mode: 0644]
tests/iwls2005/sasc/sasc_fifo4.v [new file with mode: 0644]
tests/iwls2005/sasc/sasc_top.v [new file with mode: 0644]
tests/iwls2005/sasc/timescale.v [new file with mode: 0644]
tests/iwls2005/simple_spi/fifo4.v [new file with mode: 0644]
tests/iwls2005/simple_spi/simple_spi_top.v [new file with mode: 0644]
tests/iwls2005/spi/spi_clgen.v [new file with mode: 0644]
tests/iwls2005/spi/spi_defines.v [new file with mode: 0644]
tests/iwls2005/spi/spi_shift.v [new file with mode: 0644]
tests/iwls2005/spi/spi_top.v [new file with mode: 0644]
tests/iwls2005/spi/timescale.v [new file with mode: 0644]
tests/iwls2005/ss_pcm/pcm_slv_top.v [new file with mode: 0644]
tests/iwls2005/ss_pcm/timescale.v [new file with mode: 0644]
tests/iwls2005/systemcaes/aes.v [new file with mode: 0644]
tests/iwls2005/systemcaes/byte_mixcolum.v [new file with mode: 0644]
tests/iwls2005/systemcaes/keysched.v [new file with mode: 0644]
tests/iwls2005/systemcaes/mixcolum.v [new file with mode: 0644]
tests/iwls2005/systemcaes/sbox.v [new file with mode: 0644]
tests/iwls2005/systemcaes/subbytes.v [new file with mode: 0644]
tests/iwls2005/systemcaes/timescale.v [new file with mode: 0644]
tests/iwls2005/systemcaes/word_mixcolum.v [new file with mode: 0644]
tests/iwls2005/usb_phy/timescale.v [new file with mode: 0644]
tests/iwls2005/usb_phy/usb_phy.v [new file with mode: 0644]
tests/iwls2005/usb_phy/usb_rx_phy.v [new file with mode: 0644]
tests/iwls2005/usb_phy/usb_tx_phy.v [new file with mode: 0644]
tests/no-icarus/README [new file with mode: 0644]
tests/no-icarus/autowire.v [new file with mode: 0644]
tests/no-icarus/var_range.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_alu.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_and_gate.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_clock_gate.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_clock_module.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_clock_mux.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_dbg.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_dbg_hwbrk.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_dbg_uart.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_execution_unit.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_frontend.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_mem_backbone.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_multiplier.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_register_file.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_scan_mux.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_sfr.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_sync_cell.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_sync_reset.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_wakeup_cell.v [new file with mode: 0644]
tests/openmsp430/rtl/omsp_watchdog.v [new file with mode: 0644]
tests/openmsp430/rtl/openMSP430.v [new file with mode: 0644]
tests/openmsp430/rtl/openMSP430_defines.v [new file with mode: 0644]
tests/openmsp430/rtl/openMSP430_undefines.v [new file with mode: 0644]
tests/openmsp430/run-fm.do [new file with mode: 0644]
tests/openmsp430/run-fm.sh [new file with mode: 0644]
tests/openmsp430/run-synth.sh [new file with mode: 0644]
tests/openmsp430/run-synth.ys [new file with mode: 0644]
tests/openmsp430/sim_mul.v [new file with mode: 0644]
tests/or1200/config.patch [new file with mode: 0644]
tests/or1200/run-checkout.sh [new file with mode: 0644]
tests/or1200/run-fm-mods.sh [new file with mode: 0644]
tests/or1200/run-fm.do [new file with mode: 0644]
tests/or1200/run-fm.sh [new file with mode: 0644]
tests/or1200/run-synth.sh [new file with mode: 0644]
tests/or1200/run-synth.ys [new file with mode: 0644]
tests/or1200/run-vg.sh [new file with mode: 0644]
tests/simple/aes_kexp128.v [new file with mode: 0644]
tests/simple/dff_different_styles.v [new file with mode: 0644]
tests/simple/fiedler-cooley.v [new file with mode: 0644]
tests/simple/fsm.v [new file with mode: 0644]
tests/simple/generate.v [new file with mode: 0644]
tests/simple/i2c_master_tests.v [new file with mode: 0644]
tests/simple/loops.v [new file with mode: 0644]
tests/simple/mem2reg.v [new file with mode: 0644]
tests/simple/memory.v [new file with mode: 0644]
tests/simple/muxtree.v [new file with mode: 0644]
tests/simple/omsp_dbg_uart.v [new file with mode: 0644]
tests/simple/operators.v [new file with mode: 0644]
tests/simple/paramods.v [new file with mode: 0644]
tests/simple/process.v [new file with mode: 0644]
tests/simple/run-test.sh [new file with mode: 0755]
tests/simple/subbytes.v [new file with mode: 0644]
tests/simple/task_func.v [new file with mode: 0644]
tests/simple/usb_phy_tetsts.v [new file with mode: 0644]
tests/simple/values.v [new file with mode: 0644]
tests/tools/autotest.sh [new file with mode: 0755]
tests/tools/cmp_tbdata.c [new file with mode: 0644]
tests/tools/profiler.pl [new file with mode: 0755]
tests/tools/rtlview.sh [new file with mode: 0755]
tests/tools/vcdcd.pl [new file with mode: 0755]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..49533d0
--- /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 (file)
index 0000000..0a51926
--- /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 (file)
index 0000000..9308dcd
--- /dev/null
@@ -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 (file)
index 0000000..36d5650
--- /dev/null
@@ -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 (file)
index 0000000..52fc2b8
--- /dev/null
@@ -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 (file)
index 0000000..7e28372
--- /dev/null
@@ -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 (file)
index 0000000..e34c4e6
--- /dev/null
@@ -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 (file)
index 0000000..c2dffef
--- /dev/null
@@ -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 (file)
index 0000000..d799080
--- /dev/null
@@ -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 (file)
index 0000000..c40830e
--- /dev/null
@@ -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 (file)
index 0000000..4467edc
--- /dev/null
@@ -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 (file)
index 0000000..3b23aa1
--- /dev/null
@@ -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 (file)
index 0000000..cf6e910
--- /dev/null
@@ -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 (file)
index 0000000..7edebda
--- /dev/null
@@ -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 (file)
index 0000000..b1dd943
--- /dev/null
@@ -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 (file)
index 0000000..2a0ebee
--- /dev/null
@@ -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 (file)
index 0000000..44073af
--- /dev/null
@@ -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 (file)
index 0000000..c815b5d
--- /dev/null
@@ -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 (file)
index 0000000..d7f9889
--- /dev/null
@@ -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 (file)
index 0000000..9228753
--- /dev/null
@@ -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 (file)
index 0000000..999faaf
--- /dev/null
@@ -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 (file)
index 0000000..0ea89c6
--- /dev/null
@@ -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 (file)
index 0000000..ac6927c
--- /dev/null
@@ -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 (file)
index 0000000..3018e98
--- /dev/null
@@ -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 (file)
index 0000000..53c8e5b
--- /dev/null
@@ -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 (file)
index 0000000..e184238
--- /dev/null
@@ -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 (executable)
index 0000000..ff73729
--- /dev/null
@@ -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 (file)
index 0000000..62b41df
--- /dev/null
@@ -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 (file)
index 0000000..7cb9768
--- /dev/null
@@ -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 (file)
index 0000000..993ead9
--- /dev/null
@@ -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 (file)
index 0000000..160e9c4
--- /dev/null
@@ -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 (file)
index 0000000..f7c9328
--- /dev/null
@@ -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 (file)
index 0000000..9f1acb6
--- /dev/null
@@ -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 (file)
index 0000000..cb8b104
--- /dev/null
@@ -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 (file)
index 0000000..07ebf08
--- /dev/null
@@ -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 (file)
index 0000000..f3ad3a1
--- /dev/null
@@ -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 (file)
index 0000000..5e768c3
--- /dev/null
@@ -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 (file)
index 0000000..e331c26
--- /dev/null
@@ -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 (file)
index 0000000..61bac83
--- /dev/null
@@ -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 (file)
index 0000000..6693f2d
--- /dev/null
@@ -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 (file)
index 0000000..e5beaea
--- /dev/null
@@ -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 (file)
index 0000000..a269c07
--- /dev/null
@@ -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 (file)
index 0000000..7c12bd5
--- /dev/null
@@ -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 (file)
index 0000000..e6fdc1f
--- /dev/null
@@ -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 (file)
index 0000000..c182337
--- /dev/null
@@ -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 (file)
index 0000000..808edfc
--- /dev/null
@@ -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 (file)
index 0000000..aaefa50
--- /dev/null
@@ -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 (file)
index 0000000..f31fed7
--- /dev/null
@@ -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 (file)
index 0000000..a13cbf3
--- /dev/null
@@ -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 (file)
index 0000000..d48771f
--- /dev/null
@@ -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 (file)
index 0000000..c49bf65
--- /dev/null
@@ -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 (file)
index 0000000..9bf8705
--- /dev/null
@@ -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 (file)
index 0000000..9023854
--- /dev/null
@@ -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 (file)
index 0000000..fb70c80
--- /dev/null
@@ -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 (file)
index 0000000..713d468
--- /dev/null
@@ -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 (file)
index 0000000..c97e2e4
--- /dev/null
@@ -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 (file)
index 0000000..1f45d12
--- /dev/null
@@ -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 (file)
index 0000000..8a91f1b
--- /dev/null
@@ -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 (file)
index 0000000..fb7bfed
--- /dev/null
@@ -0,0 +1,185 @@
+/*\r
+ Copyright (c) 2011, Micael Hildenborg\r
+ All rights reserved.\r
+\r
+ Redistribution and use in source and binary forms, with or without\r
+ modification, are permitted provided that the following conditions are met:\r
+    * Redistributions of source code must retain the above copyright\r
+      notice, this list of conditions and the following disclaimer.\r
+    * Redistributions in binary form must reproduce the above copyright\r
+      notice, this list of conditions and the following disclaimer in the\r
+      documentation and/or other materials provided with the distribution.\r
+    * Neither the name of Micael Hildenborg nor the\r
+      names of its contributors may be used to endorse or promote products\r
+      derived from this software without specific prior written permission.\r
+\r
+ THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY\r
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+ DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY\r
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+/*\r
+ Contributors:\r
+ Gustav\r
+ Several members in the gamedev.se forum.\r
+ Gregory Petrosyan\r
+ */\r
+\r
+#include "sha1.h"\r
+\r
+namespace sha1\r
+{\r
+    namespace // local\r
+    {\r
+        // Rotate an integer value to left.\r
+        inline unsigned int rol(const unsigned int value,\r
+                const unsigned int steps)\r
+        {\r
+            return ((value << steps) | (value >> (32 - steps)));\r
+        }\r
+\r
+        // Sets the first 16 integers in the buffert to zero.\r
+        // Used for clearing the W buffert.\r
+        inline void clearWBuffert(unsigned int* buffert)\r
+        {\r
+            for (int pos = 16; --pos >= 0;)\r
+            {\r
+                buffert[pos] = 0;\r
+            }\r
+        }\r
+\r
+        void innerHash(unsigned int* result, unsigned int* w)\r
+        {\r
+            unsigned int a = result[0];\r
+            unsigned int b = result[1];\r
+            unsigned int c = result[2];\r
+            unsigned int d = result[3];\r
+            unsigned int e = result[4];\r
+\r
+            int round = 0;\r
+\r
+            #define sha1macro(func,val) \\r
+                       { \\r
+                const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \\r
+                               e = d; \\r
+                               d = c; \\r
+                               c = rol(b, 30); \\r
+                               b = a; \\r
+                               a = t; \\r
+                       }\r
+\r
+            while (round < 16)\r
+            {\r
+                sha1macro((b & c) | (~b & d), 0x5a827999)\r
+                ++round;\r
+            }\r
+            while (round < 20)\r
+            {\r
+                w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);\r
+                sha1macro((b & c) | (~b & d), 0x5a827999)\r
+                ++round;\r
+            }\r
+            while (round < 40)\r
+            {\r
+                w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);\r
+                sha1macro(b ^ c ^ d, 0x6ed9eba1)\r
+                ++round;\r
+            }\r
+            while (round < 60)\r
+            {\r
+                w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);\r
+                sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)\r
+                ++round;\r
+            }\r
+            while (round < 80)\r
+            {\r
+                w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);\r
+                sha1macro(b ^ c ^ d, 0xca62c1d6)\r
+                ++round;\r
+            }\r
+\r
+            #undef sha1macro\r
+\r
+            result[0] += a;\r
+            result[1] += b;\r
+            result[2] += c;\r
+            result[3] += d;\r
+            result[4] += e;\r
+        }\r
+    } // namespace\r
+\r
+    void calc(const void* src, const int bytelength, unsigned char* hash)\r
+    {\r
+        // Init the result array.\r
+        unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };\r
+\r
+        // Cast the void src pointer to be the byte array we can work with.\r
+        const unsigned char* sarray = (const unsigned char*) src;\r
+\r
+        // The reusable round buffer\r
+        unsigned int w[80];\r
+\r
+        // Loop through all complete 64byte blocks.\r
+        const int endOfFullBlocks = bytelength - 64;\r
+        int endCurrentBlock;\r
+        int currentBlock = 0;\r
+\r
+        while (currentBlock <= endOfFullBlocks)\r
+        {\r
+            endCurrentBlock = currentBlock + 64;\r
+\r
+            // Init the round buffer with the 64 byte block data.\r
+            for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)\r
+            {\r
+                // This line will swap endian on big endian and keep endian on little endian.\r
+                w[roundPos++] = (unsigned int) sarray[currentBlock + 3]\r
+                        | (((unsigned int) sarray[currentBlock + 2]) << 8)\r
+                        | (((unsigned int) sarray[currentBlock + 1]) << 16)\r
+                        | (((unsigned int) sarray[currentBlock]) << 24);\r
+            }\r
+            innerHash(result, w);\r
+        }\r
+\r
+        // Handle the last and not full 64 byte block if existing.\r
+        endCurrentBlock = bytelength - currentBlock;\r
+        clearWBuffert(w);\r
+        int lastBlockBytes = 0;\r
+        for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)\r
+        {\r
+            w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);\r
+        }\r
+        w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);\r
+        if (endCurrentBlock >= 56)\r
+        {\r
+            innerHash(result, w);\r
+            clearWBuffert(w);\r
+        }\r
+        w[15] = bytelength << 3;\r
+        innerHash(result, w);\r
+\r
+        // Store hash in result pointer, and make sure we get in in the correct order on both endian models.\r
+        for (int hashByte = 20; --hashByte >= 0;)\r
+        {\r
+            hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;\r
+        }\r
+    }\r
+\r
+    void toHexString(const unsigned char* hash, char* hexstring)\r
+    {\r
+        const char hexDigits[] = { "0123456789abcdef" };\r
+\r
+        for (int hashByte = 20; --hashByte >= 0;)\r
+        {\r
+            hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf];\r
+            hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf];\r
+        }\r
+        hexstring[40] = 0;\r
+    }\r
+} // namespace sha1\r
diff --git a/kernel/sha1.h b/kernel/sha1.h
new file mode 100644 (file)
index 0000000..540c156
--- /dev/null
@@ -0,0 +1,49 @@
+/*\r
+ Copyright (c) 2011, Micael Hildenborg\r
+ All rights reserved.\r
+\r
+ Redistribution and use in source and binary forms, with or without\r
+ modification, are permitted provided that the following conditions are met:\r
+    * Redistributions of source code must retain the above copyright\r
+      notice, this list of conditions and the following disclaimer.\r
+    * Redistributions in binary form must reproduce the above copyright\r
+      notice, this list of conditions and the following disclaimer in the\r
+      documentation and/or other materials provided with the distribution.\r
+    * Neither the name of Micael Hildenborg nor the\r
+      names of its contributors may be used to endorse or promote products\r
+      derived from this software without specific prior written permission.\r
+\r
+ THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY\r
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+ DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY\r
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+#ifndef SHA1_DEFINED\r
+#define SHA1_DEFINED\r
+\r
+namespace sha1\r
+{\r
+\r
+    /**\r
+     @param src points to any kind of data to be hashed.\r
+     @param bytelength the number of bytes to hash from the src pointer.\r
+     @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.\r
+     */\r
+    void calc(const void* src, const int bytelength, unsigned char* hash);\r
+\r
+    /**\r
+     @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function.\r
+     @param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string.\r
+     */\r
+    void toHexString(const unsigned char* hash, char* hexstring);\r
+\r
+} // namespace sha1\r
+\r
+#endif // SHA1_DEFINED\r
diff --git a/kernel/show.cc b/kernel/show.cc
new file mode 100644 (file)
index 0000000..d7da62c
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *  
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/log.h"
+#include <string.h>
+#include <dirent.h>
+
+#undef CLUSTER_CELLS_AND_PORTBOXES
+
+struct ShowWorker
+{
+       CellTypes ct;
+
+       std::vector<std::string> dot_escape_store;
+       std::map<RTLIL::IdString, int> dot_id2num_store;
+       std::map<RTLIL::IdString, int> autonames;
+       int single_idx_count;
+
+       struct net_conn { std::set<std::string> in, out; };
+       std::map<std::string, net_conn> net_conn_map;
+
+       FILE *f;
+       RTLIL::Design *design;
+       RTLIL::Module *module;
+       int page_counter;
+
+       const char *escape(std::string id, bool is_name = false)
+       {
+               if (id.size() == 0)
+                       return "";
+
+               if (id[0] == '$' && is_name) {
+                       if (autonames.count(id) == 0) {
+                               autonames[id] = autonames.size() + 1;
+                               log("Generated short name for internal identifier: _%d_ -> %s\n", autonames[id], id.c_str());
+                       }
+                       id = stringf("_%d_", autonames[id]);
+               }
+
+               if (id[0] == '\\')
+                       id = id.substr(1);
+
+               std::string str;
+               for (char ch : id) {
+                       if (ch == '\\' || ch == '"')
+                               str += "\\";
+                       str += ch;
+               }
+
+               dot_escape_store.push_back(str);
+               return dot_escape_store.back().c_str();
+       }
+
+       int id2num(RTLIL::IdString id)
+       {
+               if (dot_id2num_store.count(id) > 0)
+                       return dot_id2num_store[id];
+               return dot_id2num_store[id] = dot_id2num_store.size() + 1;
+       }
+
+       std::string gen_signode_simple(RTLIL::SigSpec sig, bool range_check = true)
+       {
+               sig.optimize();
+
+               if (sig.chunks.size() == 0) {
+                       fprintf(f, "v%d [ label=\"\" ];\n", single_idx_count);
+                       return stringf("v%d", single_idx_count++);
+               }
+
+               if (sig.chunks.size() == 1) {
+                       RTLIL::SigChunk &c = sig.chunks[0];
+                       if (c.wire != NULL && design->selected_member(module->name, c.wire->name)) {
+                               if (!range_check || c.wire->width == c.width)
+                                               return stringf("n%d", id2num(c.wire->name));
+                       } else {
+                               fprintf(f, "v%d [ label=\"%s\" ];\n", single_idx_count, escape(log_signal(c), true));
+                               return stringf("v%d", single_idx_count++);
+                       }
+               }
+
+               return std::string();
+       }
+
+       std::string gen_portbox(std::string port, RTLIL::SigSpec sig, bool driver, std::string *node = NULL)
+       {
+               std::string code;
+               std::string net = gen_signode_simple(sig);
+               if (net.empty())
+               {
+                       std::string label_string;
+                       sig.optimize();
+                       int pos = sig.width-1;
+                       int idx = single_idx_count++;
+                       for (int i = int(sig.chunks.size())-1; i >= 0; i--) {
+                               RTLIL::SigChunk &c = sig.chunks[i];
+                               net = gen_signode_simple(c, false);
+                               assert(!net.empty());
+                               if (driver) {
+                                       label_string += stringf("<s%d> %d:%d - %d:%d |", i, pos, pos-c.width+1, c.offset+c.width-1, c.offset);
+                                       net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i));
+                               } else {
+                                       label_string += stringf("<s%d> %d:%d - %d:%d |", i, c.offset+c.width-1, c.offset, pos, pos-c.width+1);
+                                       net_conn_map[net].out.insert(stringf("x%d:s%d", idx, i));
+                               }
+                               pos -= c.width;
+                       }
+                       if (label_string[label_string.size()-1] == '|')
+                               label_string = label_string.substr(0, label_string.size()-1);
+                       code += stringf("x%d [ shape=record, style=rounded, label=\"%s\" ];\n", idx, label_string.c_str());
+                       if (!port.empty()) {
+                               if (driver)
+                                       code += stringf("%s:e -> x%d:w [arrowhead=odiamond, arrowtail=odiamond, dir=both];\n", port.c_str(), idx);
+                               else
+                                       code += stringf("x%d:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both];\n", idx, port.c_str());
+                       }
+                       if (node != NULL)
+                               *node = stringf("x%d", idx);
+               }
+               else
+               {
+                       if (!port.empty()) {
+                               if (driver)
+                                       net_conn_map[net].in.insert(port);
+                               else
+                                       net_conn_map[net].out.insert(port);
+                       }
+                       if (node != NULL)
+                               *node = net;
+               }
+               return code;
+       }
+
+       void handle_module()
+       {
+               single_idx_count = 0;
+               dot_escape_store.clear();
+               dot_id2num_store.clear();
+               net_conn_map.clear();
+
+               fprintf(f, "digraph \"%s\" {\n", escape(module->name));
+               fprintf(f, "rankdir=\"LR\";\n");
+               fprintf(f, "remincross=true;\n");
+
+               std::map<std::string, std::string> wires_on_demand;
+               for (auto &it : module->wires) {
+                       if (!design->selected_member(module->name, it.first))
+                               continue;
+                       const char *shape = "diamond";
+                       if (it.second->port_input || it.second->port_output)
+                               shape = "octagon";
+                       if (it.first[0] == '\\')
+                               fprintf(f, "n%d [ shape=%s, label=\"%s\" ];\n",
+                                               id2num(it.first), shape, escape(it.first));
+                       else {
+                               wires_on_demand[stringf("n%d", id2num(it.first))] = it.first;
+                       }
+               }
+
+               for (auto &it : module->cells)
+               {
+                       if (!design->selected_member(module->name, it.first))
+                               continue;
+
+                       std::vector<RTLIL::IdString> in_ports, out_ports;
+
+                       for (auto &conn : it.second->connections) {
+                               if (ct.cell_input(it.second->type, conn.first))
+                                       in_ports.push_back(conn.first);
+                               else
+                                       out_ports.push_back(conn.first);
+                       }
+
+                       std::string label_string = "{{";
+
+                       for (auto &p : in_ports)
+                               label_string += stringf("<p%d> %s|", id2num(p), escape(p));
+                       if (label_string[label_string.size()-1] == '|')
+                               label_string = label_string.substr(0, label_string.size()-1);
+
+                       label_string += stringf("}|%s\\n%s|{", escape(it.first, true), escape(it.second->type));
+
+                       for (auto &p : out_ports)
+                               label_string += stringf("<p%d> %s|", id2num(p), escape(p));
+                       if (label_string[label_string.size()-1] == '|')
+                               label_string = label_string.substr(0, label_string.size()-1);
+
+                       label_string += "}}";
+
+                       std::string code;
+                       for (auto &conn : it.second->connections) {
+                               code += gen_portbox(stringf("c%d:p%d", id2num(it.first), id2num(conn.first)),
+                                               conn.second, !ct.cell_input(it.second->type, conn.first));
+                       }
+
+#ifdef CLUSTER_CELLS_AND_PORTBOXES
+                       if (!code.empty())
+                               fprintf(f, "subgraph cluster_c%d {\nc%d [ shape=record, label=\"%s\" ];\n%s}\n",
+                                               id2num(it.first), id2num(it.first), label_string.c_str(), code.c_str());
+                       else
+#endif
+                               fprintf(f, "c%d [ shape=record, label=\"%s\" ];\n%s",
+                                               id2num(it.first), label_string.c_str(), code.c_str());
+               }
+
+               for (auto &conn : module->connections)
+               {
+                       bool found_lhs_wire = false;
+                       for (auto &c : conn.first.chunks) {
+                               if (c.wire != NULL && design->selected_member(module->name, c.wire->name))
+                                       found_lhs_wire = true;
+                       }
+                       bool found_rhs_wire = false;
+                       for (auto &c : conn.second.chunks) {
+                               if (c.wire != NULL && design->selected_member(module->name, c.wire->name))
+                                       found_rhs_wire = true;
+                       }
+                       if (!found_lhs_wire || !found_rhs_wire)
+                               continue;
+
+                       std::string code, left_node, right_node;
+                       code += gen_portbox("", conn.second, false, &left_node);
+                       code += gen_portbox("", conn.first, true, &right_node);
+                       fprintf(f, "%s", code.c_str());
+
+                       if (left_node[0] == 'x' && right_node[0] == 'x')
+                               fprintf(f, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both];\n", left_node.c_str(), right_node.c_str());
+                       else if (left_node[0] == 'x')
+                               net_conn_map[right_node].in.insert(left_node);
+                       else if (right_node[0] == 'x')
+                               net_conn_map[left_node].out.insert(right_node);
+                       else {
+                               net_conn_map[right_node].in.insert(stringf("x%d:e", single_idx_count));
+                               net_conn_map[left_node].out.insert(stringf("x%d:w", single_idx_count));
+                               fprintf(f, "x%d [shape=box, style=rounded, label=\"BUF\"];\n", single_idx_count++);
+                       }
+               }
+
+               for (auto &it : net_conn_map)
+               {
+                       if (wires_on_demand.count(it.first) > 0) {
+                               if (it.second.in.size() == 1 && it.second.out.size() == 1) {
+                                       fprintf(f, "%s:e -> %s:w;\n", it.second.in.begin()->c_str(), it.second.out.begin()->c_str());
+                                       continue;
+                               }
+                               if (it.second.in.size() == 0 || it.second.out.size() == 0)
+                                       fprintf(f, "%s [ shape=diamond, label=\"%s\" ];\n", it.first.c_str(), escape(wires_on_demand[it.first], true));
+                               else
+                                       fprintf(f, "%s [ shape=point ];\n", it.first.c_str());
+                       }
+                       for (auto &it2 : it.second.in)
+                               fprintf(f, "%s:e -> %s:w;\n", it2.c_str(), it.first.c_str());
+                       for (auto &it2 : it.second.out)
+                               fprintf(f, "%s:e -> %s:w;\n", it.first.c_str(), it2.c_str());
+               }
+
+               fprintf(f, "};\n");
+       }
+
+       ShowWorker(FILE *f, RTLIL::Design *design) : f(f), design(design)
+       {
+               ct.setup_internals();
+               ct.setup_internals_mem();
+               ct.setup_stdcells();
+               ct.setup_stdcells_mem();
+
+               design->optimize();
+               page_counter = 0;
+               for (auto &mod_it : design->modules)
+               {
+                       module = mod_it.second;
+                       if (!design->selected_module(module->name))
+                               continue;
+                       if (design->selected_whole_module(module->name))
+                               log("Dumping module %s to page %d.\n", module->name.c_str(), ++page_counter);
+                       else
+                               log("Dumping selected parts of module %s to page %d.\n", module->name.c_str(), ++page_counter);
+                       handle_module();
+               }
+       }
+};
+
+struct ShowPass : public Pass {
+       ShowPass() : Pass("show") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Generating Graphviz representation of design.\n");
+
+               std::string viewer_exe;
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++)
+               {
+                       std::string arg = args[argidx];
+                       if (arg == "-viewer" && argidx+1 < args.size()) {
+                               viewer_exe = args[++argidx];
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               log("Writing dot description to `yosys-show.dot'.\n");
+               FILE *f = fopen("yosys-show.dot", "w");
+               if (f == NULL)
+                       log_cmd_error("Can't open dot file `yosys-show.dot' for writing.\n");
+               ShowWorker worker(f, design);
+               fclose(f);
+
+               if (worker.page_counter == 0)
+                       log_cmd_error("Nothing there to show.\n");
+
+               std::string cmd = stringf("dot -Tps -o yosys-show.ps yosys-show.dot");
+               log("Exec: %s\n", cmd.c_str());
+               if (system(cmd.c_str()) != 0)
+                       log_cmd_error("Shell command failed!\n");
+
+               if (!viewer_exe.empty()) {
+                       cmd = stringf("%s yosys-show.ps &", viewer_exe.c_str());
+                       log("Exec: %s\n", cmd.c_str());
+                       if (system(cmd.c_str()) != 0)
+                               log_cmd_error("Shell command failed!\n");
+               }
+       }
+} ShowPass;
diff --git a/kernel/sigtools.h b/kernel/sigtools.h
new file mode 100644 (file)
index 0000000..e76fd60
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ *  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 SIGTOOLS_H
+#define SIGTOOLS_H
+
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+#include <assert.h>
+#include <set>
+
+struct SigPool
+{
+       typedef std::pair<RTLIL::Wire*,int> bitDef_t;
+       std::set<bitDef_t> bits;
+
+       void clear()
+       {
+               bits.clear();
+       }
+
+       void add(RTLIL::SigSpec sig)
+       {
+               sig.expand();
+               for (auto &c : sig.chunks) {
+                       if (c.wire == NULL)
+                               continue;
+                       assert(c.width == 1);
+                       bitDef_t bit(c.wire, c.offset);
+                       bits.insert(bit);
+               }
+       }
+
+       void add(const SigPool &other)
+       {
+               for (auto &bit : other.bits)
+                       bits.insert(bit);
+       }
+
+       void del(RTLIL::SigSpec sig)
+       {
+               sig.expand();
+               for (auto &c : sig.chunks) {
+                       if (c.wire == NULL)
+                               continue;
+                       assert(c.width == 1);
+                       bitDef_t bit(c.wire, c.offset);
+                       bits.erase(bit);
+               }
+       }
+
+       void del(const SigPool &other)
+       {
+               for (auto &bit : other.bits)
+                       bits.insert(bit);
+       }
+
+       void expand(RTLIL::SigSpec from, RTLIL::SigSpec to)
+       {
+               from.expand();
+               to.expand();
+               assert(from.chunks.size() == to.chunks.size());
+               for (size_t i = 0; i < from.chunks.size(); i++) {
+                       bitDef_t bit_from(from.chunks[i].wire, from.chunks[i].offset);
+                       bitDef_t bit_to(to.chunks[i].wire, to.chunks[i].offset);
+                       if (bit_from.first == NULL || bit_to.first == NULL)
+                               continue;
+                       if (bits.count(bit_from) > 0)
+                               bits.insert(bit_to);
+               }
+       }
+
+       RTLIL::SigSpec extract(RTLIL::SigSpec sig)
+       {
+               RTLIL::SigSpec result;
+               sig.expand();
+               for (auto &c : sig.chunks) {
+                       if (c.wire == NULL)
+                               continue;
+                       bitDef_t bit(c.wire, c.offset);
+                       if (bits.count(bit) > 0)
+                               result.append(c);
+               }
+               return result;
+       }
+
+       RTLIL::SigSpec remove(RTLIL::SigSpec sig)
+       {
+               RTLIL::SigSpec result;
+               sig.expand();
+               for (auto &c : sig.chunks) {
+                       if (c.wire == NULL)
+                               continue;
+                       bitDef_t bit(c.wire, c.offset);
+                       if (bits.count(bit) == 0)
+                               result.append(c);
+               }
+               return result;
+       }
+
+       bool check_any(RTLIL::SigSpec sig)
+       {
+               sig.expand();
+               for (auto &c : sig.chunks) {
+                       if (c.wire == NULL)
+                               continue;
+                       bitDef_t bit(c.wire, c.offset);
+                       if (bits.count(bit) != 0)
+                               return true;
+               }
+               return false;
+       }
+
+       bool check_all(RTLIL::SigSpec sig)
+       {
+               sig.expand();
+               for (auto &c : sig.chunks) {
+                       if (c.wire == NULL)
+                               continue;
+                       bitDef_t bit(c.wire, c.offset);
+                       if (bits.count(bit) == 0)
+                               return false;
+               }
+               return true;
+       }
+};
+
+template <typename T>
+struct SigSet
+{
+       typedef std::pair<RTLIL::Wire*,int> bitDef_t;
+       std::map<bitDef_t, std::set<T>> bits;
+
+       void clear()
+       {
+               bits.clear();
+       }
+
+       void insert(RTLIL::SigSpec sig, T data)
+       {
+               sig.expand();
+               for (auto &c : sig.chunks) {
+                       if (c.wire == NULL)
+                               continue;
+                       assert(c.width == 1);
+                       bitDef_t bit(c.wire, c.offset);
+                       bits[bit].insert(data);
+               }
+       }
+
+       void erase(RTLIL::SigSpec sig)
+       {
+               sig.expand();
+               for (auto &c : sig.chunks) {
+                       if (c.wire == NULL)
+                               continue;
+                       assert(c.width == 1);
+                       bitDef_t bit(c.wire, c.offset);
+                       bits[bit].clear();
+               }
+       }
+
+       void erase(RTLIL::SigSpec sig, T data)
+       {
+               sig.expand();
+               for (auto &c : sig.chunks) {
+                       if (c.wire == NULL)
+                               continue;
+                       assert(c.width == 1);
+                       bitDef_t bit(c.wire, c.offset);
+                       bits[bit].erase(data);
+               }
+       }
+
+       void find(RTLIL::SigSpec sig, std::set<T> &result)
+       {
+               sig.expand();
+               for (auto &c : sig.chunks) {
+                       if (c.wire == NULL)
+                               continue;
+                       assert(c.width == 1);
+                       bitDef_t bit(c.wire, c.offset);
+                       for (auto &data : bits[bit])
+                               result.insert(data);
+               }
+       }
+
+       std::set<T> find(RTLIL::SigSpec sig)
+       {
+               std::set<T> result;
+               find(sig, result);
+               return result;
+       }
+};
+
+struct SigMap
+{
+       typedef std::pair<RTLIL::Wire*,int> bitDef_t;
+
+       struct shared_bit_data_t {
+               RTLIL::SigChunk chunk;
+               std::set<bitDef_t> bits;
+       };
+
+       std::map<bitDef_t, shared_bit_data_t*> bits;
+
+       SigMap(RTLIL::Module *module = NULL)
+       {
+               if (module != NULL)
+                       set(module);
+       }
+
+       SigMap(const SigMap &other)
+       {
+               copy(other);
+       }
+
+       const SigMap &operator=(const SigMap &other)
+       {
+               copy(other);
+               return *this;
+       }
+
+       void copy(const SigMap &other)
+       {
+               clear();
+               for (auto &bit : other.bits) {
+                       bits[bit.first] = new shared_bit_data_t;
+                       bits[bit.first]->chunk = bit.second->chunk;
+                       bits[bit.first]->bits = bit.second->bits;
+               }
+       }
+
+       void swap(SigMap &other)
+       {
+               bits.swap(other.bits);
+       }
+
+       ~SigMap()
+       {
+               clear();
+       }
+
+       void clear()
+       {
+               std::set<shared_bit_data_t*> all_bd_ptr;
+               for (auto &it : bits)
+                       all_bd_ptr.insert(it.second);
+               for (auto bd_ptr : all_bd_ptr)
+                       delete bd_ptr;
+               bits.clear();
+       }
+
+       void set(RTLIL::Module *module)
+       {
+               clear();
+               for (auto &it : module->connections)
+                       add(it.first, it.second);
+       }
+
+       // internal helper function
+       void register_bit(const RTLIL::SigChunk &c)
+       {
+               assert(c.width == 1);
+               bitDef_t bit(c.wire, c.offset);
+               if (c.wire && bits.count(bit) == 0) {
+                       shared_bit_data_t *bd = new shared_bit_data_t;
+                       bd->chunk = c;
+                       bd->bits.insert(bit);
+                       bits[bit] = bd;
+               }
+       }
+
+       // internal helper function
+       void unregister_bit(const RTLIL::SigChunk &c)
+       {
+               assert(c.width == 1);
+               bitDef_t bit(c.wire, c.offset);
+               if (c.wire && bits.count(bit) > 0) {
+                       shared_bit_data_t *bd = bits[bit];
+                       bd->bits.erase(bit);
+                       if (bd->bits.size() == 0)
+                               delete bd;
+                       bits.erase(bit);
+               }
+       }
+
+       // internal helper function
+       void merge_bit(const RTLIL::SigChunk &c1, const RTLIL::SigChunk &c2)
+       {
+               assert(c1.wire != NULL && c2.wire != NULL);
+               assert(c1.width == 1 && c2.width == 1);
+
+               bitDef_t b1(c1.wire, c1.offset);
+               bitDef_t b2(c2.wire, c2.offset);
+
+               shared_bit_data_t *bd1 = bits[b1];
+               shared_bit_data_t *bd2 = bits[b2];
+               assert(bd1 != NULL && bd2 != NULL);
+
+               if (bd1 == bd2)
+                       return;
+
+               if (bd1->bits.size() < bd2->bits.size())
+               {
+                       for (auto &bit : bd1->bits)
+                               bits[bit] = bd2;
+                       bd2->bits.insert(bd1->bits.begin(), bd1->bits.end());
+                       delete bd1;
+               }
+               else
+               {
+                       bd1->chunk = bd2->chunk;
+                       for (auto &bit : bd2->bits)
+                               bits[bit] = bd1;
+                       bd1->bits.insert(bd2->bits.begin(), bd2->bits.end());
+                       delete bd2;
+               }
+       }
+
+       // internal helper function
+       void set_bit(const RTLIL::SigChunk &c1, const RTLIL::SigChunk &c2)
+       {
+               assert(c1.wire != NULL);
+               assert(c1.width == 1 && c2.width == 1);
+               bitDef_t bit(c1.wire, c1.offset);
+               assert(bits.count(bit) > 0);
+               bits[bit]->chunk = c2;
+       }
+
+       // internal helper function
+       void map_bit(RTLIL::SigChunk &c)
+       {
+               assert(c.width == 1);
+               bitDef_t bit(c.wire, c.offset);
+               if (c.wire && bits.count(bit) > 0)
+                       c = bits[bit]->chunk;
+       }
+
+       void add(RTLIL::SigSpec from, RTLIL::SigSpec to)
+       {
+               from.expand();
+               to.expand();
+
+               assert(from.chunks.size() == to.chunks.size());
+               for (size_t i = 0; i < from.chunks.size(); i++)
+               {
+                       RTLIL::SigChunk &cf = from.chunks[i];
+                       RTLIL::SigChunk &ct = to.chunks[i];
+
+                       if (cf.wire == NULL)
+                               continue;
+
+                       register_bit(cf);
+                       register_bit(ct);
+
+                       if (ct.wire != NULL)
+                               merge_bit(cf, ct);
+                       else
+                               set_bit(cf, ct);
+               }
+       }
+
+       void add(RTLIL::SigSpec sig)
+       {
+               sig.expand();
+               for (size_t i = 0; i < sig.chunks.size(); i++)
+               {
+                       RTLIL::SigChunk &c = sig.chunks[i];
+                       if (c.wire != NULL) {
+                               register_bit(c);
+                               set_bit(c, c);
+                       }
+               }
+       }
+
+       void del(RTLIL::SigSpec sig)
+       {
+               sig.expand();
+               for (auto &c : sig.chunks)
+                       unregister_bit(c);
+       }
+
+       void apply(RTLIL::SigSpec &sig)
+       {
+               sig.expand();
+               for (auto &c : sig.chunks)
+                       map_bit(c);
+               sig.optimize();
+       }
+
+       RTLIL::SigSpec operator()(RTLIL::SigSpec sig)
+       {
+               apply(sig);
+               return sig;
+       }
+};
+
+#endif /* SIGTOOLS_H */
diff --git a/passes/abc/Makefile.inc b/passes/abc/Makefile.inc
new file mode 100644 (file)
index 0000000..25aadcd
--- /dev/null
@@ -0,0 +1,4 @@
+
+OBJS += passes/abc/abc.o
+OBJS += passes/abc/vlparse.o
+
diff --git a/passes/abc/abc.cc b/passes/abc/abc.cc
new file mode 100644 (file)
index 0000000..251d0ba
--- /dev/null
@@ -0,0 +1,645 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *  
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include "vlparse.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <sstream>
+
+struct gate_t
+{
+       int id;
+       char type;
+       int in1, in2, in3;
+       bool is_port;
+       RTLIL::SigSpec sig;
+};
+
+static int map_autoidx;
+static SigMap assign_map;
+static RTLIL::Module *module;
+static std::vector<gate_t> signal_list;
+static std::map<RTLIL::SigSpec, int> signal_map;
+
+static int map_signal(RTLIL::SigSpec sig, char gate_type = -1, int in1 = -1, int in2 = -1, int in3 = -1)
+{
+       assert(sig.width == 1);
+       assert(sig.chunks.size() == 1);
+
+       assign_map.apply(sig);
+
+       if (signal_map.count(sig) == 0) {
+               gate_t gate;
+               gate.id = signal_list.size();
+               gate.type = -1;
+               gate.in1 = -1;
+               gate.in2 = -1;
+               gate.in3 = -1;
+               gate.is_port = false;
+               gate.sig = sig;
+               signal_list.push_back(gate);
+               signal_map[sig] = gate.id;
+       }
+
+       gate_t &gate = signal_list[signal_map[sig]];
+
+       if (gate_type >= 0)
+               gate.type = gate_type;
+       if (in1 >= 0)
+               gate.in1 = in1;
+       if (in2 >= 0)
+               gate.in2 = in2;
+       if (in3 >= 0)
+               gate.in3 = in3;
+
+       return gate.id;
+}
+
+static void mark_port(RTLIL::SigSpec sig)
+{
+       assign_map.apply(sig);
+       sig.expand();
+       for (auto &c : sig.chunks) {
+               if (c.wire != NULL && signal_map.count(c) > 0)
+                       signal_list[signal_map[c]].is_port = true;
+       }
+}
+
+static void extract_cell(RTLIL::Cell *cell)
+{
+       if (cell->type == "$_INV_")
+       {
+               RTLIL::SigSpec sig_a = cell->connections["\\A"];
+               RTLIL::SigSpec sig_y = cell->connections["\\Y"];
+
+               assign_map.apply(sig_a);
+               assign_map.apply(sig_y);
+
+               map_signal(sig_y, 'n', map_signal(sig_a));
+
+               module->cells.erase(cell->name);
+               delete cell;
+               return;
+       }
+
+       if (cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_")
+       {
+               RTLIL::SigSpec sig_a = cell->connections["\\A"];
+               RTLIL::SigSpec sig_b = cell->connections["\\B"];
+               RTLIL::SigSpec sig_y = cell->connections["\\Y"];
+
+               assign_map.apply(sig_a);
+               assign_map.apply(sig_b);
+               assign_map.apply(sig_y);
+
+               if (cell->type == "$_AND_")
+                       map_signal(sig_y, 'a', map_signal(sig_a), map_signal(sig_b));
+               else if (cell->type == "$_OR_")
+                       map_signal(sig_y, 'o', map_signal(sig_a), map_signal(sig_b));
+               else if (cell->type == "$_XOR_")
+                       map_signal(sig_y, 'x', map_signal(sig_a), map_signal(sig_b));
+               else
+                       abort();
+
+               module->cells.erase(cell->name);
+               delete cell;
+               return;
+       }
+
+       if (cell->type == "$_MUX_")
+       {
+               RTLIL::SigSpec sig_a = cell->connections["\\A"];
+               RTLIL::SigSpec sig_b = cell->connections["\\B"];
+               RTLIL::SigSpec sig_s = cell->connections["\\S"];
+               RTLIL::SigSpec sig_y = cell->connections["\\Y"];
+
+               assign_map.apply(sig_a);
+               assign_map.apply(sig_b);
+               assign_map.apply(sig_s);
+               assign_map.apply(sig_y);
+
+               map_signal(sig_y, 'm', map_signal(sig_a), map_signal(sig_b), map_signal(sig_s));
+
+               module->cells.erase(cell->name);
+               delete cell;
+               return;
+       }
+}
+
+static std::string remap_name(std::string abc_name)
+{
+       std::stringstream sstr;
+       sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1);
+       return sstr.str();
+}
+
+static void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std::set<int> &workpool, std::vector<int> &in_counts)
+{
+       if (f == NULL)
+               return;
+
+       log("Dumping loop state graph to slide %d.\n", ++nr);
+
+       fprintf(f, "digraph slide%d {\n", nr);
+       fprintf(f, "  rankdir=\"LR\";\n");
+
+       std::set<int> nodes;
+       for (auto &e : edges) {
+               nodes.insert(e.first);
+               for (auto n : e.second)
+                       nodes.insert(n);
+       }
+
+       for (auto n : nodes)
+               fprintf(f, "  n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].sig),
+                               n, in_counts[n], workpool.count(n) ? ", shape=box" : "");
+
+       for (auto &e : edges)
+       for (auto n : e.second)
+               fprintf(f, "  n%d -> n%d;\n", e.first, n);
+
+       fprintf(f, "}\n");
+}
+
+static void handle_loops()
+{
+       // http://en.wikipedia.org/wiki/Topological_sorting
+
+       std::map<int, std::set<int>> edges;
+       std::vector<int> in_edges_count(signal_list.size());
+       std::set<int> workpool;
+
+       FILE *dot_f = NULL;
+       int dot_nr = 0;
+
+       // uncomment for troubleshooting the loop detection code
+       // dot_f = fopen("test.dot", "w");
+
+       for (auto &g : signal_list) {
+               if (g.type == -1) {
+                       workpool.insert(g.id);
+               }
+               if (g.in1 >= 0) {
+                       edges[g.in1].insert(g.id);
+                       in_edges_count[g.id]++;
+               }
+               if (g.in2 >= 0 && g.in2 != g.in1) {
+                       edges[g.in2].insert(g.id);
+                       in_edges_count[g.id]++;
+               }
+               if (g.in3 >= 0 && g.in3 != g.in2 && g.in3 != g.in1) {
+                       edges[g.in3].insert(g.id);
+                       in_edges_count[g.id]++;
+               }
+       }
+
+       dump_loop_graph(dot_f, dot_nr, edges, workpool, in_edges_count);
+
+       while (workpool.size() > 0)
+       {
+               int id = *workpool.begin();
+               workpool.erase(id);
+
+               // log("Removing non-loop node %d from graph: %s\n", id, log_signal(signal_list[id].sig));
+
+               for (int id2 : edges[id]) {
+                       assert(in_edges_count[id2] > 0);
+                       if (--in_edges_count[id2] == 0)
+                               workpool.insert(id2);
+               }
+               edges.erase(id);
+
+               dump_loop_graph(dot_f, dot_nr, edges, workpool, in_edges_count);
+
+               while (workpool.size() == 0)
+               {
+                       if (edges.size() == 0)
+                               break;
+
+                       int id1 = edges.begin()->first;
+
+                       for (auto &edge_it : edges) {
+                               int id2 = edge_it.first;
+                               RTLIL::Wire *w1 = signal_list[id1].sig.chunks[0].wire;
+                               RTLIL::Wire *w2 = signal_list[id2].sig.chunks[0].wire;
+                               if (w1 != NULL)
+                                       continue;
+                               else if (w2 == NULL)
+                                       id1 = id2;
+                               else if (w1->name[0] == '$' && w2->name[0] == '\\')
+                                       id1 = id2;
+                               else if (w1->name[0] == '\\' && w2->name[0] == '$')
+                                       continue;
+                               else if (edges[id1].size() < edges[id2].size())
+                                       id1 = id2;
+                               else if (edges[id1].size() > edges[id2].size())
+                                       continue;
+                               else if (w1->name > w2->name)
+                                       id1 = id2;
+                       }
+
+                       if (edges[id1].size() == 0) {
+                               edges.erase(id1);
+                               continue;
+                       }
+
+                       RTLIL::Wire *wire = new RTLIL::Wire;
+                       std::stringstream sstr;
+                       sstr << "$abcloop$" << (RTLIL::autoidx++);
+                       wire->name = sstr.str();
+                       module->wires[wire->name] = wire;
+
+                       bool first_line = true;
+                       for (int id2 : edges[id1]) {
+                               if (first_line)
+                                       log("Breaking loop using new signal %s: %s -> %s\n", log_signal(RTLIL::SigSpec(wire)),
+                                                       log_signal(signal_list[id1].sig), log_signal(signal_list[id2].sig));
+                               else
+                                       log("                               %*s  %s -> %s\n", int(strlen(log_signal(RTLIL::SigSpec(wire)))), "",
+                                                       log_signal(signal_list[id1].sig), log_signal(signal_list[id2].sig));
+                               first_line = false;
+                       }
+
+                       int id3 = map_signal(RTLIL::SigSpec(wire));
+                       signal_list[id1].is_port = true;
+                       signal_list[id3].is_port = true;
+                       assert(id3 == int(in_edges_count.size()));
+                       in_edges_count.push_back(0);
+                       workpool.insert(id3);
+
+                       for (int id2 : edges[id1]) {
+                               if (signal_list[id2].in1 == id1)
+                                       signal_list[id2].in1 = id3;
+                               if (signal_list[id2].in2 == id1)
+                                       signal_list[id2].in2 = id3;
+                               if (signal_list[id2].in3 == id1)
+                                       signal_list[id2].in3 = id3;
+                       }
+                       edges[id1].swap(edges[id3]);
+
+                       module->connections.push_back(RTLIL::SigSig(signal_list[id3].sig, signal_list[id1].sig));
+                       dump_loop_graph(dot_f, dot_nr, edges, workpool, in_edges_count);
+               }
+       }
+
+       if (dot_f != NULL)
+               fclose(dot_f);
+}
+
+static void abc_module(RTLIL::Module *current_module, std::string script_file, std::string exe_file, std::string liberty_file, bool cleanup)
+{
+       module = current_module;
+       map_autoidx = RTLIL::autoidx++;
+
+       signal_map.clear();
+       signal_list.clear();
+       assign_map.set(module);
+
+       char tempdir_name[] = "/tmp/yosys-abc-XXXXXX";
+       if (!cleanup)
+               tempdir_name[0] = tempdir_name[4] = '_';
+       char *p = mkdtemp(tempdir_name);
+       log_header("Extracting gate logic of module `%s' to `%s/input.v'..\n", module->name.c_str(), tempdir_name);
+       assert(p != NULL);
+
+       std::vector<RTLIL::Cell*> cells;
+       cells.reserve(module->cells.size());
+       for (auto &it : module->cells)
+               cells.push_back(it.second);
+       for (auto c : cells)
+               extract_cell(c);
+
+       for (auto &wire_it : module->wires) {
+               if (wire_it.second->port_id > 0)
+                       mark_port(RTLIL::SigSpec(wire_it.second));
+       }
+
+       for (auto &cell_it : module->cells)
+       for (auto &port_it : cell_it.second->connections)
+               mark_port(port_it.second);
+       
+       handle_loops();
+
+       if (asprintf(&p, "%s/input.v", tempdir_name) < 0) abort();
+       FILE *f = fopen(p, "wt");
+       assert(f != NULL);
+       free(p);
+
+       fprintf(f, "module logic (");
+       bool first = true;
+       for (auto &si : signal_list) {
+               if (!si.is_port)
+                       continue;
+               if (!first)
+                       fprintf(f, ", ");
+               fprintf(f, "n%d", si.id);
+               first = false;
+       }
+       fprintf(f, "); // %s\n", module->name.c_str());
+
+       int count_input = 0, count_output = 0;
+       for (auto &si : signal_list) {
+               if (si.is_port) {
+                       if (si.type >= 0)
+                               count_output++;
+                       else
+                               count_input++;
+               }
+               fprintf(f, "%s n%d; // %s\n", si.is_port ? si.type >= 0 ?
+                               "output" : "input" : "wire", si.id, log_signal(si.sig));
+       }
+       for (auto &si : signal_list) {
+               assert(si.sig.width == 1 && si.sig.chunks.size() == 1);
+               if (si.sig.chunks[0].wire == NULL)
+                       fprintf(f, "assign n%d = %c;\n", si.id, si.sig.chunks[0].data.bits[0] == RTLIL::State::S1 ? '1' : '0');
+       }
+
+       int count_gates = 0;
+       for (auto &si : signal_list) {
+               if (si.type == 'n')
+                       fprintf(f, "not (n%d, n%d);\n", si.id, si.in1);
+               else if (si.type == 'a')
+                       fprintf(f, "and (n%d, n%d, n%d);\n", si.id, si.in1, si.in2);
+               else if (si.type == 'o')
+                       fprintf(f, "or (n%d, n%d, n%d);\n", si.id, si.in1, si.in2);
+               else if (si.type == 'x')
+                       fprintf(f, "xor (n%d, n%d, n%d);\n", si.id, si.in1, si.in2);
+               else if (si.type == 'm')
+                       fprintf(f, "assign n%d = n%d ? n%d : n%d;\n", si.id, si.in3, si.in2, si.in1);
+               else if (si.type >= 0)
+                       abort();
+               if (si.type >= 0)
+                       count_gates++;
+       }
+
+       fprintf(f, "endmodule\n");
+       fclose(f);
+
+       log("Extracted %d gates and %zd wires to a logic network with %d inputs and %d outputs.\n",
+                       count_gates, signal_list.size(), count_input, count_output);
+       log_push();
+       
+       if (count_output > 0)
+       {
+               log_header("Executing ABC.\n");
+
+               if (asprintf(&p, "%s/stdcells.genlib", tempdir_name) < 0) abort();
+               f = fopen(p, "wt");
+               assert(f != NULL);
+               fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
+               fprintf(f, "GATE ONE  1 Y=CONST1;\n");
+               fprintf(f, "GATE BUF  1 Y=A;                  PIN * NONINV  1 999 1 0 1 0\n");
+               fprintf(f, "GATE INV  1 Y=!A;                 PIN * INV     1 999 1 0 1 0\n");
+               fprintf(f, "GATE AND  1 Y=A*B;                PIN * NONINV  1 999 1 0 1 0\n");
+               fprintf(f, "GATE OR   1 Y=A+B;                PIN * NONINV  1 999 1 0 1 0\n");
+               fprintf(f, "GATE XOR  1 Y=(A*!B)+(!A*B);      PIN * UNKNOWN 1 999 1 0 1 0\n");
+               fprintf(f, "GATE MUX  1 Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n");
+               fclose(f);
+               free(p);
+
+               char buffer[1024];
+               if (!liberty_file.empty())
+                       snprintf(buffer, 1024, "%s -c 'read_verilog %s/input.v; read_liberty %s; "
+                                       "map; write_verilog %s/output.v' 2>&1", exe_file.c_str(), tempdir_name, liberty_file.c_str(), tempdir_name);
+               else
+               if (!script_file.empty())
+                       snprintf(buffer, 1024, "%s -c 'read_verilog %s/input.v; source %s; "
+                                       "map; write_verilog %s/output.v' 2>&1", exe_file.c_str(), tempdir_name, script_file.c_str(), tempdir_name);
+               else
+                       snprintf(buffer, 1024, "%s -c 'read_verilog %s/input.v; read_library %s/stdcells.genlib; "
+                                       "map; write_verilog %s/output.v' 2>&1", exe_file.c_str(), tempdir_name, tempdir_name, tempdir_name);
+               f = popen(buffer, "r");
+               while (fgets(buffer, 1024, f) != NULL)
+                       log("ABC: %s", buffer);
+               fclose(f);
+
+               if (asprintf(&p, "%s/output.v", tempdir_name) < 0) abort();
+               f = fopen(p, "rt");
+               if (f == NULL)
+                       log_error("Can't open ABC output file `%s'.\n", p);
+#if 0
+               RTLIL::Design *mapped_design = new RTLIL::Design;
+               frontend_register["verilog"]->execute(f, p, std::vector<std::string>(), mapped_design);
+#else
+               RTLIL::Design *mapped_design = abc_parse_verilog(f);
+#endif
+               fclose(f);
+               free(p);
+
+               log_header("Re-integrating ABC results.\n");
+               RTLIL::Module *mapped_mod = mapped_design->modules["\\logic"];
+               if (mapped_mod == NULL)
+                       log_error("ABC output file does not contain a module `logic'.\n");
+               for (auto &it : mapped_mod->wires) {
+                       RTLIL::Wire *w = it.second;
+                       RTLIL::Wire *wire = new RTLIL::Wire;
+                       wire->name = remap_name(w->name);
+                       module->wires[wire->name] = wire;
+               }
+
+               std::map<std::string, int> cell_stats;
+               if (liberty_file.empty() && script_file.empty())
+               {
+                       for (auto &it : mapped_mod->cells) {
+                               RTLIL::Cell *c = it.second;
+                               cell_stats[c->type.substr(1)]++;
+                               if (c->type == "\\ZERO" || c->type == "\\ONE") {
+                                       RTLIL::SigSig conn;
+                                       conn.first = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
+                                       conn.second = RTLIL::SigSpec(c->type == "\\ZERO" ? 0 : 1, 1);
+                                       module->connections.push_back(conn);
+                                       continue;
+                               }
+                               if (c->type == "\\BUF") {
+                                       RTLIL::SigSig conn;
+                                       conn.first = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
+                                       conn.second = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
+                                       module->connections.push_back(conn);
+                                       continue;
+                               }
+                               if (c->type == "\\INV") {
+                                       RTLIL::Cell *cell = new RTLIL::Cell;
+                                       cell->type = "$_INV_";
+                                       cell->name = remap_name(c->name);
+                                       cell->connections["\\A"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
+                                       cell->connections["\\Y"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
+                                       module->cells[cell->name] = cell;
+                                       continue;
+                               }
+                               if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR") {
+                                       RTLIL::Cell *cell = new RTLIL::Cell;
+                                       cell->type = "$_" + c->type.substr(1) + "_";
+                                       cell->name = remap_name(c->name);
+                                       cell->connections["\\A"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
+                                       cell->connections["\\B"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\B"].chunks[0].wire->name)]);
+                                       cell->connections["\\Y"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
+                                       module->cells[cell->name] = cell;
+                                       continue;
+                               }
+                               if (c->type == "\\MUX") {
+                                       RTLIL::Cell *cell = new RTLIL::Cell;
+                                       cell->type = "$_MUX_";
+                                       cell->name = remap_name(c->name);
+                                       cell->connections["\\A"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
+                                       cell->connections["\\B"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\B"].chunks[0].wire->name)]);
+                                       cell->connections["\\S"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\S"].chunks[0].wire->name)]);
+                                       cell->connections["\\Y"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
+                                       module->cells[cell->name] = cell;
+                                       continue;
+                               }
+                               assert(0);
+                       }
+               }
+               else
+               {
+                       for (auto &it : mapped_mod->cells) {
+                               RTLIL::Cell *c = it.second;
+                               cell_stats[c->type.substr(1)]++;
+                               if (c->type == "$_const0_" || c->type == "$_const1_") {
+                                       RTLIL::SigSig conn;
+                                       conn.first = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
+                                       conn.second = RTLIL::SigSpec(c->type == "$_const0_" ? 0 : 1, 1);
+                                       module->connections.push_back(conn);
+                                       continue;
+                               }
+                               RTLIL::Cell *cell = new RTLIL::Cell;
+                               cell->type = c->type;
+                               cell->name = remap_name(c->name);
+                               for (auto &conn : c->connections)
+                                       cell->connections[conn.first] = RTLIL::SigSpec(module->wires[remap_name(conn.second.chunks[0].wire->name)]);
+                               module->cells[cell->name] = cell;
+                       }
+               }
+
+               for (auto &it : cell_stats)
+                       log("ABC RESULTS:   %15s cells: %8d\n", it.first.c_str(), it.second);
+               int in_wires = 0, out_wires = 0;
+               for (auto &si : signal_list)
+                       if (si.is_port) {
+                               char buffer[100];
+                               snprintf(buffer, 100, "\\n%d", si.id);
+                               RTLIL::SigSig conn;
+                               if (si.type >= 0) {
+                                       conn.first = si.sig;
+                                       conn.second = RTLIL::SigSpec(module->wires[remap_name(buffer)]);
+                                       out_wires++;
+                               } else {
+                                       conn.first = RTLIL::SigSpec(module->wires[remap_name(buffer)]);
+                                       conn.second = si.sig;
+                                       in_wires++;
+                               }
+                               module->connections.push_back(conn);
+                       }
+               log("ABC RESULTS:        internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
+               log("ABC RESULTS:           input signals: %8d\n", in_wires);
+               log("ABC RESULTS:          output signals: %8d\n", out_wires);
+
+               delete mapped_design;
+       }
+       else
+       {
+               log("Don't call ABC as there is nothing to map.\n");
+       }
+
+       if (cleanup)
+       {
+               log_header("Removing temp directory `%s':\n", tempdir_name);
+
+               struct dirent **namelist;
+               int n = scandir(tempdir_name, &namelist, 0, alphasort);
+               assert(n >= 0);
+               for (int i = 0; i < n; i++) {
+                       if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) {
+                               if (asprintf(&p, "%s/%s", tempdir_name, namelist[i]->d_name) < 0) abort();
+                               log("Removing `%s'.\n", p);
+                               remove(p);
+                               free(p);
+                       }
+                       free(namelist[i]);
+               }
+               free(namelist);
+               log("Removing `%s'.\n", tempdir_name);
+               rmdir(tempdir_name);
+       }
+
+       log_pop();
+}
+
+struct AbcPass : public Pass {
+       AbcPass() : Pass("abc") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing ABC pass (technology mapping using ABC).\n");
+               log_push();
+
+               std::string exe_file = "abc";
+               std::string script_file, liberty_file;
+               bool cleanup = true;
+
+               size_t argidx;
+               char *pwd = get_current_dir_name();
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       std::string arg = args[argidx];
+                       if (arg == "-exe" && argidx+1 < args.size()) {
+                               exe_file = args[++argidx];
+                               continue;
+                       }
+                       if (arg == "-script" && argidx+1 < args.size() && liberty_file.empty()) {
+                               script_file = args[++argidx];
+                               if (!script_file.empty() && script_file[0] != '/')
+                                       script_file = std::string(pwd) + "/" + script_file;
+                               continue;
+                       }
+                       if (arg == "-liberty" && argidx+1 < args.size() && script_file.empty()) {
+                               liberty_file = args[++argidx];
+                               if (!liberty_file.empty() && liberty_file[0] != '/')
+                                       liberty_file = std::string(pwd) + "/" + liberty_file;
+                               continue;
+                       }
+                       if (arg == "-nocleanup") {
+                               cleanup = false;
+                               continue;
+                       }
+                       break;
+               }
+               free(pwd);
+               extra_args(args, argidx, design);
+
+               for (auto &mod_it : design->modules) {
+                       if (mod_it.second->processes.size() > 0)
+                               log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
+                       else
+                               abc_module(mod_it.second, script_file, exe_file, liberty_file, cleanup);
+               }
+
+               assign_map.clear();
+               signal_list.clear();
+               signal_map.clear();
+
+               log_pop();
+       }
+} AbcPass;
diff --git a/passes/abc/vlparse.cc b/passes/abc/vlparse.cc
new file mode 100644 (file)
index 0000000..5c0cb7e
--- /dev/null
@@ -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.
+ *
+ */
+
+#include "vlparse.h"
+#include "kernel/log.h"
+#include <stdio.h>
+#include <string>
+
+static int lex_line, lex_tok;
+static std::string lex_str;
+
+static int token(int tok)
+{
+       lex_tok = tok;
+#if 0
+       if (lex_tok == 256)
+               fprintf(stderr, "STR in line %d: >>%s<<\n", lex_line, lex_str.c_str());
+       else if (tok >= 32 && tok < 255)
+               fprintf(stderr, "CHAR in line %d: >>%c<<\n", lex_line, lex_tok);
+       else
+               fprintf(stderr, "CHAR in line %d: %d\n", lex_line, lex_tok);
+#endif
+       return tok;
+}
+
+static int lex(FILE *f)
+{
+       int ch = getc(f);
+
+       while (ch == ' ' || ch == '\t' || ch == '\n') {
+               if (ch == '\n')
+                       lex_line++;
+               ch = getc(f);
+       }
+
+       if (ch <= 0 || 255 < ch)
+               return token(lex_tok);
+       
+       if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
+                       ('0' <= ch && ch <= '9') || ch == '_') {
+               lex_str = char(ch);
+               while (1) {
+                       ch = getc(f);
+                       if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
+                                       ('0' <= ch && ch <= '9') || ch == '_') {
+                               lex_str += char(ch);
+                               continue;
+                       }
+                       break;
+               }
+               ungetc(ch, f);
+               return token(256);
+       }
+
+       if (ch == '/') {
+               ch = getc(f);
+               if (ch == '/') {
+                       while (ch != '\n')
+                               ch = getc(f);
+                       ungetc(ch, f);
+                       return lex(f);
+               }
+               ungetc(ch, f);
+               return token('/');
+       }
+
+       return token(ch);
+}
+
+RTLIL::Design *abc_parse_verilog(FILE *f)
+{
+       RTLIL::Design *design = new RTLIL::Design;
+       RTLIL::Module *module;
+       RTLIL::Wire *wire;
+       RTLIL::Cell *cell;
+
+       int port_count = 1;
+       lex_line = 1;
+
+       // parse module header
+       if (lex(f) != 256 || lex_str != "module")
+               goto error;
+       if (lex(f) != 256)
+               goto error;
+
+       module = new RTLIL::Module;
+       module->name = "\\" + lex_str;
+       design->modules[module->name] = module;
+
+       if (lex(f) != '(')
+               goto error;
+       while (lex(f) != ')') {
+               if (lex_tok != 256 && lex_tok != ',')
+                       goto error;
+       }
+       if (lex(f) != ';')
+               goto error;
+
+       // parse module body
+       while (1)
+       {
+               if (lex(f) != 256)
+                       goto error;
+
+               if (lex_str == "endmodule")
+                       return design;
+
+               if (lex_str == "input" || lex_str == "output" || lex_str == "wire")
+               {
+                       std::string mode = lex_str;
+                       while (lex(f) != ';') {
+                               if (lex_tok != 256 && lex_tok != ',')
+                                       goto error;
+                               if (lex_tok == 256) {
+                                       // printf("%s [%s]\n", mode.c_str(), lex_str.c_str());
+                                       wire = new RTLIL::Wire;
+                                       wire->name = "\\" + lex_str;
+                                       if (mode == "input") {
+                                               wire->port_id = port_count++;
+                                               wire->port_input = true;
+                                       }
+                                       if (mode == "output") {
+                                               wire->port_id = port_count++;
+                                               wire->port_output = true;
+                                       }
+                                       module->wires[wire->name] = wire;
+                               }
+                       }
+               }
+               else
+               {
+                       std::string cell_type = lex_str;
+
+                       if (lex(f) != 256)
+                               goto error;
+
+                       std::string cell_name = lex_str;
+
+                       if (lex(f) != '(')
+                               goto error;
+
+                       // printf("cell [%s] [%s]\n", cell_type.c_str(), cell_name.c_str());
+                       cell = new RTLIL::Cell;
+                       cell->type = "\\" + cell_type;
+                       cell->name = "\\" + cell_name;
+                       module->cells[cell->name] = cell;
+
+                       lex(f);
+                       while (lex_tok != ')')
+                       {
+                               if (lex_tok != '.' || lex(f) != 256)
+                                       goto error;
+
+                               std::string cell_port = lex_str;
+
+                               if (lex(f) != '(' || lex(f) != 256)
+                                       goto error;
+
+                               std::string wire_name = lex_str;
+
+                               // printf("  [%s] <- [%s]\n", cell_port.c_str(), wire_name.c_str());
+                               if (module->wires.count("\\" + wire_name) == 0)
+                                       goto error;
+                               cell->connections["\\" + cell_port] = RTLIL::SigSpec(module->wires["\\" + wire_name]);
+
+                               if (lex(f) != ')' || (lex(f) != ',' && lex_tok != ')'))
+                                       goto error;
+                               while (lex_tok == ',')
+                                       lex(f);
+                       }
+
+                       if (lex(f) != ';')
+                               goto error;
+               }
+       }
+
+error:
+       log_error("Syntax error in line %d!\n", lex_line);
+       // delete design;
+       // return NULL;
+}
+
diff --git a/passes/abc/vlparse.h b/passes/abc/vlparse.h
new file mode 100644 (file)
index 0000000..9514c41
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *  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 ABC_VLPARSE
+#define ABC_VLPARSE
+
+#include "kernel/rtlil.h"
+
+extern RTLIL::Design *abc_parse_verilog(FILE *f);
+
+#endif
+
diff --git a/passes/dfflibmap/Makefile.inc b/passes/dfflibmap/Makefile.inc
new file mode 100644 (file)
index 0000000..ed92b29
--- /dev/null
@@ -0,0 +1,10 @@
+
+OBJS += passes/dfflibmap/dfflibmap.o
+OBJS += passes/dfflibmap/libparse.o
+
+TARGETS += filterlib
+GENFILES += passes/dfflibmap/filterlib.o
+
+filterlib: passes/dfflibmap/filterlib.o
+       $(CXX) -o filterlib $(LDFLAGS) $^ $(LDLIBS)
+
diff --git a/passes/dfflibmap/dfflibmap.cc b/passes/dfflibmap/dfflibmap.cc
new file mode 100644 (file)
index 0000000..86e8bcb
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ *  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 "libparse.h"
+#include <string.h>
+
+using namespace PASS_DFFLIBMAP;
+
+struct cell_mapping {
+       std::string cell_name;
+       std::map<std::string, char> ports;
+};
+static std::map<std::string, cell_mapping> cell_mappings;
+
+static void logmap(std::string dff)
+{
+       if (cell_mappings.count(dff) == 0) {
+               log("    unmapped dff cell: %s\n", dff.c_str());
+       } else {
+               log("    %s %s(", cell_mappings[dff].cell_name.c_str(), dff.substr(1).c_str());
+               bool first = true;
+               for (auto &port : cell_mappings[dff].ports) {
+                       char arg[3] = { port.second, 0, 0 };
+                       if ('a' <= arg[0] && arg[0] <= 'z')
+                               arg[1] = arg[0] - ('a' - 'A'), arg[0] = '~';
+                       log("%s.%s(%s)", first ? "" : ", ", port.first.c_str(), arg);
+                       first = false;
+               }
+               log(");\n");
+       }
+}
+
+static void logmap_all()
+{
+       logmap("$_DFF_N_");
+       logmap("$_DFF_P_");
+       logmap("$_DFF_NN0_");
+       logmap("$_DFF_NN1_");
+       logmap("$_DFF_NP0_");
+       logmap("$_DFF_NP1_");
+       logmap("$_DFF_PN0_");
+       logmap("$_DFF_PN1_");
+       logmap("$_DFF_PP0_");
+       logmap("$_DFF_PP1_");
+}
+
+static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name, bool &pin_pol)
+{
+       if (cell == NULL || attr == NULL || attr->value.empty())
+               return false;
+       
+       std::string value = attr->value;
+
+       for (size_t pos = value.find_first_of("\" \t"); pos != std::string::npos; pos = value.find_first_of("\" \t"))
+               value.erase(pos, 1);
+
+       if (value[value.size()-1] == '\'') {
+               pin_name = value.substr(0, value.size()-1);
+               pin_pol = false;
+       } else {
+               pin_name = value;
+               pin_pol = true;
+       }
+
+       for (auto child : cell->children)
+               if (child->id == "pin" && child->args.size() == 1 && child->args[0] == pin_name)
+                       return true;
+       return false;
+}
+
+static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval)
+{
+       LibertyAst *best_cell = NULL;
+       std::map<std::string, char> best_cell_ports;
+       int best_cell_pins = 0;
+
+       if (ast->id != "library")
+               log_error("Format error in liberty file.\n");
+
+       for (auto cell : ast->children)
+       {
+               if (cell->id != "cell" || cell->args.size() != 1)
+                       continue;
+
+               LibertyAst *ff = cell->find("ff");
+               if (ff == NULL)
+                       continue;
+
+               std::string cell_clk_pin, cell_rst_pin, cell_next_pin;
+               bool cell_clk_pol, cell_rst_pol, cell_next_pol;
+
+               if (!parse_pin(cell, ff->find("clocked_on"), cell_clk_pin, cell_clk_pol) || cell_clk_pol != clkpol)
+                       continue;
+               if (!parse_pin(cell, ff->find("next_state"), cell_next_pin, cell_next_pol))
+                       continue;
+               if (has_reset && rstval == false) {
+                       if (!parse_pin(cell, ff->find("clear"), cell_rst_pin, cell_rst_pol) || cell_rst_pol != rstpol)
+                               continue;
+               }
+               if (has_reset && rstval == true) {
+                       if (!parse_pin(cell, ff->find("preset"), cell_rst_pin, cell_rst_pol) || cell_rst_pol != rstpol)
+                               continue;
+               }
+
+               std::map<std::string, char> this_cell_ports;
+               this_cell_ports[cell_clk_pin] = 'C';
+               if (has_reset)
+                       this_cell_ports[cell_rst_pin] = 'R';
+               this_cell_ports[cell_next_pin] = 'D';
+
+               int num_pins = 0;
+               bool found_output = false;
+               for (auto pin : cell->children)
+               {
+                       if (pin->id != "pin" || pin->args.size() != 1)
+                               continue;
+
+                       LibertyAst *dir = pin->find("direction");
+                       if (dir == NULL || dir->value == "internal")
+                               continue;
+                       num_pins++;
+
+                       if (dir->value == "input" && this_cell_ports.count(pin->args[0]) == 0)
+                               goto continue_cell_loop;
+
+                       LibertyAst *func = pin->find("function");
+                       if (dir->value == "output" && func != NULL) {
+                               std::string value = func->value;
+                               for (size_t pos = value.find_first_of("\" \t"); pos != std::string::npos; pos = value.find_first_of("\" \t"))
+                                       value.erase(pos, 1);
+                               if ((cell_next_pol == true && value == ff->args[0]) || (cell_next_pol == false && value == ff->args[1])) {
+                                       this_cell_ports[pin->args[0]] = 'Q';
+                                       found_output = true;
+                               }
+                       }
+
+                       if (this_cell_ports.count(pin->args[0]) == 0)
+                               this_cell_ports[pin->args[0]] = 0;
+               }
+
+               if (!found_output || (best_cell != NULL && num_pins > best_cell_pins))
+                       continue;
+
+               best_cell = cell;
+               best_cell_pins = num_pins;
+               best_cell_ports.swap(this_cell_ports);
+       continue_cell_loop:;
+       }
+
+       if (best_cell != NULL) {
+               log("  cell %s is a direct match for cell type %s.\n", best_cell->args[0].c_str(), cell_type.substr(1).c_str());
+               cell_mappings[cell_type].cell_name = best_cell->args[0];
+               cell_mappings[cell_type].ports = best_cell_ports;
+       }
+}
+
+static bool expand_cellmap_worker(std::string from, std::string to, std::string inv)
+{
+       if (cell_mappings.count(to) > 0)
+               return false;
+
+       log("  create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str());
+       cell_mappings[to].cell_name = cell_mappings[from].cell_name;
+       cell_mappings[to].ports = cell_mappings[from].ports;
+
+       for (auto &it : cell_mappings[to].ports) {
+               if (inv.find(it.second) == std::string::npos)
+                       continue;
+               if ('a' <= it.second && it.second <= 'z')
+                       it.second -= 'a' - 'A';
+               else if ('A' <= it.second && it.second <= 'Z')
+                       it.second += 'a' - 'A';
+       }
+       return true;
+}
+
+static bool expand_cellmap(std::string pattern, std::string inv)
+{
+       std::vector<std::pair<std::string, std::string>> from_to_list;
+       bool return_status = false;
+
+       for (auto &it : cell_mappings) {
+               std::string from = it.first, to = it.first;
+               if (from.size() != pattern.size())
+                       continue;
+               for (size_t i = 0; i < from.size(); i++) {
+                       if (pattern[i] == '*') {
+                               to[i] = from[i] == 'P' ? 'N' :
+                                       from[i] == 'N' ? 'P' :
+                                       from[i] == '1' ? '0' :
+                                       from[i] == '0' ? '1' : '*';
+                       } else
+                       if (pattern[i] != '?' && pattern[i] != from[i])
+                               goto pattern_failed;
+               }
+               from_to_list.push_back(std::pair<std::string, std::string>(from, to));
+       pattern_failed:;
+       }
+
+       for (auto &it : from_to_list)
+               return_status = return_status || expand_cellmap_worker(it.first, it.second, inv);
+       return return_status;
+}
+
+static void dfflibmap(RTLIL::Module *module)
+{
+       log("Mapping DFF cells in module `%s':\n", module->name.c_str());
+
+       std::vector<RTLIL::Cell*> cell_list;
+       for (auto &it : module->cells) {
+               if (cell_mappings.count(it.second->type) > 0)
+                       cell_list.push_back(it.second);
+       }
+
+       std::map<std::string, int> stats;
+       for (auto cell : cell_list) {
+               cell_mapping &cm = cell_mappings[cell->type];
+               RTLIL::Cell *new_cell = new RTLIL::Cell;
+               new_cell->name = cell->name;
+               new_cell->type = "\\" + cm.cell_name;
+               for (auto &port : cm.ports) {
+                       RTLIL::SigSpec sig;
+                       if ('A' <= port.second && port.second <= 'Z') {
+                               sig = cell->connections[std::string("\\") + port.second];
+                       } else
+                       if ('a' <= port.second && port.second <= 'z') {
+                               sig = cell->connections[std::string("\\") + char(port.second - ('a' - 'A'))];
+                               RTLIL::Cell *inv_cell = new RTLIL::Cell;
+                               RTLIL::Wire *inv_wire = new RTLIL::Wire;
+                               inv_cell->name = stringf("$dfflibmap$inv$%d", RTLIL::autoidx);
+                               inv_wire->name = stringf("$dfflibmap$sig$%d", RTLIL::autoidx++);
+                               inv_cell->type = "$_INV_";
+                               inv_cell->connections[port.second == 'q' ? "\\Y" : "\\A"] = sig;
+                               sig = RTLIL::SigSpec(inv_wire);
+                               inv_cell->connections[port.second == 'q' ? "\\A" : "\\Y"] = sig;
+                               module->cells[inv_cell->name] = inv_cell;
+                               module->wires[inv_wire->name] = inv_wire;
+                       }
+                       new_cell->connections["\\" + port.first] = sig;
+               }
+               stats[stringf("  mapped %%d %s cells to %s cells.\n", cell->type.c_str(), new_cell->type.c_str())]++;
+               module->cells[cell->name] = new_cell;
+               delete cell;
+       }
+
+       for (auto &stat: stats)
+               log(stat.first.c_str(), stat.second);
+}
+
+struct DfflibmapPass : public Pass {
+       DfflibmapPass() : Pass("dfflibmap") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
+
+               std::string liberty_file;
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++)
+               {
+                       std::string arg = args[argidx];
+                       if (arg == "-liberty" && argidx+1 < args.size()) {
+                               liberty_file = args[++argidx];
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               if (liberty_file.empty())
+                       log_cmd_error("Missing `-liberty liberty_file' option!\n");
+
+               FILE *f = fopen(liberty_file.c_str(), "r");
+               if (f == NULL)
+                       log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno));
+               LibertyParer libparser(f);
+               fclose(f);
+
+               find_cell(libparser.ast, "$_DFF_N_", false, false, false, false);
+               find_cell(libparser.ast, "$_DFF_P_", true, false, false, false);
+               find_cell(libparser.ast, "$_DFF_NN0_", false, true, false, false);
+               find_cell(libparser.ast, "$_DFF_NN1_", false, true, false, true);
+               find_cell(libparser.ast, "$_DFF_NP0_", false, true, true, false);
+               find_cell(libparser.ast, "$_DFF_NP1_", false, true, true, true);
+               find_cell(libparser.ast, "$_DFF_PN0_", true, true, false, false);
+               find_cell(libparser.ast, "$_DFF_PN1_", true, true, false, true);
+               find_cell(libparser.ast, "$_DFF_PP0_", true, true, true, false);
+               find_cell(libparser.ast, "$_DFF_PP1_", true, true, true, true);
+
+               bool keep_running = true;
+               while (keep_running) {
+                       keep_running = false;
+                       keep_running |= expand_cellmap("$_DFF_*_", "C");
+                       keep_running |= expand_cellmap("$_DFF_*??_", "C");
+                       keep_running |= expand_cellmap("$_DFF_?*?_", "R");
+                       keep_running |= expand_cellmap("$_DFF_??*_", "DQ");
+               }
+               log("  final dff cell mappings:\n");
+               logmap_all();
+
+               for (auto &it : design->modules)
+                       dfflibmap(it.second);
+
+               cell_mappings.clear();
+       }
+} DfflibmapPass;
diff --git a/passes/dfflibmap/filterlib.cc b/passes/dfflibmap/filterlib.cc
new file mode 100644 (file)
index 0000000..05cfa6d
--- /dev/null
@@ -0,0 +1,4 @@
+
+#define FILTERLIB
+#include "libparse.cc"
+
diff --git a/passes/dfflibmap/libparse.cc b/passes/dfflibmap/libparse.cc
new file mode 100644 (file)
index 0000000..8fc03b5
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ *  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 "libparse.h"
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef FILTERLIB
+#include "kernel/log.h"
+#endif
+
+using namespace PASS_DFFLIBMAP;
+
+std::set<std::string> LibertyAst::blacklist;
+std::set<std::string> LibertyAst::whitelist;
+
+LibertyAst::~LibertyAst()
+{
+       for (auto child : children)
+               delete child;
+       children.clear();
+}
+
+LibertyAst *LibertyAst::find(std::string name)
+{
+       if (this == NULL)
+               return NULL;
+       for (auto child : children)
+               if (child->id == name)
+                       return child;
+       return NULL;
+}
+
+void LibertyAst::dump(FILE *f, std::string indent, std::string path, bool path_ok)
+{
+       if (whitelist.count(path + "/*") > 0)
+               path_ok = true;
+
+       path += "/" + id;
+
+       if (blacklist.count(id) > 0 || blacklist.count(path) > 0)
+               return;
+       if (whitelist.size() > 0 && whitelist.count(id) == 0 && whitelist.count(path) == 0 && !path_ok) {
+               fprintf(stderr, "Automatically added to blacklist: %s\n", path.c_str());
+               blacklist.insert(id);
+               return;
+       }
+
+       fprintf(f, "%s%s", indent.c_str(), id.c_str());
+       if (!args.empty()) {
+               for (size_t i = 0; i < args.size(); i++)
+                       fprintf(f, "%s%s", i > 0 ? ", " : "(", args[i].c_str());
+               fprintf(f, ")");
+       }
+       if (!value.empty())
+               fprintf(f, " : %s", value.c_str());
+       if (!children.empty()) {
+               fprintf(f, " {\n");
+               for (size_t i = 0; i < children.size(); i++)
+                       children[i]->dump(f, indent + "  ", path, path_ok);
+               fprintf(f, "%s}\n", indent.c_str());
+       } else
+               fprintf(f, " ;\n");
+}
+
+int LibertyParer::lexer(std::string &str)
+{
+       int c;
+
+       do {
+               c = fgetc(f);
+       } while (c == ' ' || c == '\t' || c == '\r');
+
+       if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '.') {
+               str = c;
+               while (1) {
+                       c = fgetc(f);
+                       if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '.')
+                               str += c;
+                       else
+                               break;
+               }
+               ungetc(c, f);
+               // fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str());
+               return 'v';
+       }
+
+       if (c == '"') {
+               str = c;
+               while (1) {
+                       c = fgetc(f);
+                       if (c == '\n')
+                               line++;
+                       str += c;
+                       if (c == '"')
+                               break;
+               }
+               // fprintf(stderr, "LEX: string >>%s<<\n", str.c_str());
+               return 'v';
+       }
+
+       if (c == '/') {
+               c = fgetc(f);
+               if (c == '*') {
+                       int last_c = 0;
+                       while (c > 0 && (last_c != '*' || c != '/')) {
+                               last_c = c;
+                               c = fgetc(f);
+                               if (c == '\n')
+                                       line++;
+                       }
+                       return lexer(str);
+               }
+               ungetc(c, f);
+               // fprintf(stderr, "LEX: char >>/<<\n");
+               return '/';
+       }
+
+       if (c == '\\') {
+               c = fgetc(f);
+               if (c == '\r')
+                       c = fgetc(f);
+               if (c == '\n')
+                       return lexer(str);
+               ungetc(c, f);
+               return '\\';
+       }
+
+       if (c == '\n') {
+               line++;
+               return ';';
+       }
+
+       // if (c >= 32 && c < 255)
+       //      fprintf(stderr, "LEX: char >>%c<<\n", c);
+       // else
+       //      fprintf(stderr, "LEX: char %d\n", c);
+       return c;
+}
+
+LibertyAst *LibertyParer::parse()
+{
+       std::string str;
+
+       int tok = lexer(str);
+
+       while (tok == ';')
+               tok = lexer(str);
+
+       if (tok == '}' || tok < 0)
+               return NULL;
+       
+       if (tok != 'v')
+               error();
+
+       LibertyAst *ast = new LibertyAst;
+       ast->id = str;
+
+       while (1)
+       {
+               tok = lexer(str);
+
+               if (tok == ';')
+                       break;
+
+               if (tok == ':' && ast->value.empty()) {
+                       tok = lexer(ast->value);
+                       if (tok != 'v')
+                               error();
+                       continue;
+               }
+
+               if (tok == '(') {
+                       while (1) {
+                               std::string arg;
+                               tok = lexer(arg);
+                               if (tok == ',')
+                                       continue;
+                               if (tok == ')')
+                                       break;
+                               if (tok != 'v')
+                                       error();
+                               ast->args.push_back(arg);
+                       }
+                       continue;
+               }
+
+               if (tok == '{') {
+                       while (1) {
+                               LibertyAst *child = parse();
+                               if (child == NULL)
+                                       break;
+                               ast->children.push_back(child);
+                       }
+                       break;
+               }
+
+               error();
+       }
+
+       return ast;
+}
+
+#ifndef FILTERLIB
+
+void LibertyParer::error()
+{
+       log_error("Syntax error in line %d.\n", line);
+}
+
+#else
+
+void LibertyParer::error()
+{
+       fprintf(stderr, "Syntax error in line %d.\n", line);
+       exit(1);
+}
+
+/**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
+
+// This is to not confuse the VIM syntax highlighting
+#define CHECK_VAL_OPEN (
+#define CHECK_VAL_CLOSE )
+
+#define CHECK(result, check)                                         \
+   CHECK_VAL_OPEN{                                                   \
+     auto _R = (result);                                             \
+     if (!(_R check)) {                                              \
+       fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n",       \
+               #result, (long int)_R, #check, __FILE__, __LINE__);   \
+       abort();                                                      \
+     }                                                               \
+     _R;                                                             \
+   }CHECK_VAL_CLOSE
+
+#define CHECK_NV(result, check)                                      \
+   do {                                                              \
+     auto _R = (result);                                             \
+     if (!(_R check)) {                                              \
+       fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n",       \
+               #result, (long int)_R, #check, __FILE__, __LINE__);   \
+       abort();                                                      \
+     }                                                               \
+   } while(0)
+
+#define CHECK_COND(result)                                           \
+   do {                                                              \
+     if (!(result)) {                                                \
+       fprintf(stderr, "Error from '%s' in %s:%d.\n",                \
+               #result, __FILE__, __LINE__);                         \
+       abort();                                                      \
+     }                                                               \
+   } while(0)
+
+/**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/
+
+std::string func2vl(std::string str)
+{
+       for (size_t pos = str.find_first_of("\" \t"); pos != std::string::npos; pos = str.find_first_of("\" \t")) {
+               char c_left = pos > 0 ? str[pos-1] : ' ';
+               char c_right = pos+1 < str.size() ? str[pos+1] : ' ';
+               if (std::string("\" \t*+").find(c_left) != std::string::npos)
+                       str.erase(pos, 1);
+               else if (std::string("\" \t*+").find(c_right) != std::string::npos)
+                       str.erase(pos, 1);
+               else
+                       str[pos] = '*';
+       }
+
+       std::vector<size_t> group_start;
+       for (size_t pos = 0; pos < str.size(); pos++) {
+               if (str[pos] == '(')
+                       group_start.push_back(pos);
+               if (str[pos] == ')' && group_start.size() > 0) {
+                       if (pos+1 < str.size() && str[pos+1] == '\'') {
+                               std::string group = str.substr(group_start.back(), pos-group_start.back()+1);
+                               str[group_start.back()] = '~';
+                               str.replace(group_start.back()+1, group.size(), group);
+                               pos++;
+                       }
+                       group_start.pop_back();
+               }
+               if (str[pos] == '\'' && pos > 0) {
+                       size_t start = str.find_last_of("()'*+^&| ", pos-1)+1;
+                       std::string group = str.substr(start, pos-start);
+                       str[start] = '~';
+                       str.replace(start+1, group.size(), group);
+               }
+               if (str[pos] == '*')
+                       str[pos] = '&';
+               if (str[pos] == '+')
+                       str[pos] = '|';
+       }
+
+       return str;
+}
+
+void event2vl(LibertyAst *ast, std::string &edge, std::string &expr)
+{
+       edge.clear();
+       expr.clear();
+
+       if (ast != NULL) {
+               expr = func2vl(ast->value);
+               if (expr.size() > 0 && expr[0] == '~')
+                       edge = "negedge " + expr.substr(1);
+               else
+                       edge = "posedge " + expr;
+       }
+}
+
+void clear_preset_var(std::string var, std::string type)
+{
+       if (type.find('L') != std::string::npos) {
+               printf("      %s <= 0;\n", var.c_str());
+               return;
+       }
+       if (type.find('H') != std::string::npos) {
+               printf("      %s <= 1;\n", var.c_str());
+               return;
+       }
+       if (type.find('T') != std::string::npos) {
+               printf("      %s <= ~%s;\n", var.c_str(), var.c_str());
+               return;
+       }
+       if (type.find('X') != std::string::npos) {
+               printf("      %s <= 'bx;\n", var.c_str());
+               return;
+       }
+}
+
+void gen_verilogsim_cell(LibertyAst *ast)
+{
+       if (ast->find("statetable") != NULL)
+               return;
+
+       CHECK_NV(ast->args.size(), == 1);
+       printf("module %s (", ast->args[0].c_str());
+       bool first = true;
+       for (auto child : ast->children) {
+               if (child->id != "pin")
+                       continue;
+               CHECK_NV(child->args.size(), == 1);
+               printf("%s%s", first ? "" : ", ", child->args[0].c_str());
+               first = false;
+       }
+       printf(");\n");
+
+       for (auto child : ast->children) {
+               if (child->id != "ff" && child->id != "latch")
+                       continue;
+               printf("  reg ");
+               first = true;
+               for (auto arg : child->args) {
+                       printf("%s%s", first ? "" : ", ", arg.c_str());
+                       first = false;
+               }
+               printf(";\n");
+       }
+
+       for (auto child : ast->children) {
+               if (child->id != "pin")
+                       continue;
+               CHECK_NV(child->args.size(), == 1);
+               LibertyAst *dir = CHECK(child->find("direction"), != NULL);
+               LibertyAst *func = child->find("function");
+               printf("  %s %s;\n", dir->value.c_str(), child->args[0].c_str());
+               if (func != NULL)
+                       printf("  assign %s = %s; // %s\n", child->args[0].c_str(), func2vl(func->value).c_str(), func->value.c_str());
+       }
+
+       for (auto child : ast->children)
+       {
+               if (child->id != "ff" || child->args.size() != 2)
+                       continue;
+
+               std::string iq_var = child->args[0];
+               std::string iqn_var = child->args[1];
+
+               std::string clock_edge, clock_expr;
+               event2vl(child->find("clocked_on"), clock_edge, clock_expr);
+
+               std::string clear_edge, clear_expr;
+               event2vl(child->find("clear"), clear_edge, clear_expr);
+
+               std::string preset_edge, preset_expr;
+               event2vl(child->find("preset"), preset_edge, preset_expr);
+
+               std::string edge = "";
+               if (!clock_edge.empty())
+                       edge += (edge.empty() ? "" : ", ") + clock_edge;
+               if (!clear_edge.empty())
+                       edge += (edge.empty() ? "" : ", ") + clear_edge;
+               if (!preset_edge.empty())
+                       edge += (edge.empty() ? "" : ", ") + preset_edge;
+
+               if (edge.empty())
+                       continue;
+
+               printf("  always @(%s) begin\n", edge.c_str());
+
+               const char *else_prefix = "";
+               if (!clear_expr.empty() && !preset_expr.empty()) {
+                       printf("    %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
+                       clear_preset_var(iq_var, CHECK(child->find("clear_preset_var1"), != NULL)->value);
+                       clear_preset_var(iqn_var, CHECK(child->find("clear_preset_var2"), != NULL)->value);
+                       printf("    end\n");
+                       else_prefix = "else ";
+               }
+               if (!clear_expr.empty()) {
+                       printf("    %sif (%s) begin\n", else_prefix, clear_expr.c_str());
+                       printf("      %s <= 0;\n", iq_var.c_str());
+                       printf("      %s <= 1;\n", iqn_var.c_str());
+                       printf("    end\n");
+                       else_prefix = "else ";
+               }
+               if (!preset_expr.empty()) {
+                       printf("    %sif (%s) begin\n", else_prefix, preset_expr.c_str());
+                       printf("      %s <= 1;\n", iq_var.c_str());
+                       printf("      %s <= 0;\n", iqn_var.c_str());
+                       printf("    end\n");
+                       else_prefix = "else ";
+               }
+               if (*else_prefix)
+                       printf("    %sbegin\n", else_prefix);
+               std::string expr = CHECK(child->find("next_state"), != NULL)->value;
+               printf("      // %s\n", expr.c_str());
+               printf("      %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
+               printf("      %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
+               if (*else_prefix)
+                       printf("    end\n");
+
+               printf("  end\n");
+       }
+
+       for (auto child : ast->children)
+       {
+               if (child->id != "latch" || child->args.size() != 2)
+                       continue;
+
+               std::string iq_var = child->args[0];
+               std::string iqn_var = child->args[1];
+
+               std::string enable_edge, enable_expr;
+               event2vl(child->find("enable"), enable_edge, enable_expr);
+
+               std::string clear_edge, clear_expr;
+               event2vl(child->find("clear"), clear_edge, clear_expr);
+
+               std::string preset_edge, preset_expr;
+               event2vl(child->find("preset"), preset_edge, preset_expr);
+
+               printf("  always @* begin\n");
+
+               const char *else_prefix = "";
+               if (!clear_expr.empty() && !preset_expr.empty()) {
+                       printf("    %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
+                       clear_preset_var(iq_var, CHECK(child->find("clear_preset_var1"), != NULL)->value);
+                       clear_preset_var(iqn_var, CHECK(child->find("clear_preset_var2"), != NULL)->value);
+                       printf("    end\n");
+                       else_prefix = "else ";
+               }
+               if (!clear_expr.empty()) {
+                       printf("    %sif (%s) begin\n", else_prefix, clear_expr.c_str());
+                       printf("      %s <= 0;\n", iq_var.c_str());
+                       printf("      %s <= 1;\n", iqn_var.c_str());
+                       printf("    end\n");
+                       else_prefix = "else ";
+               }
+               if (!preset_expr.empty()) {
+                       printf("    %sif (%s) begin\n", else_prefix, preset_expr.c_str());
+                       printf("      %s <= 1;\n", iq_var.c_str());
+                       printf("      %s <= 0;\n", iqn_var.c_str());
+                       printf("    end\n");
+                       else_prefix = "else ";
+               }
+               if (!enable_expr.empty()) {
+                       printf("    %sif (%s) begin\n", else_prefix, enable_expr.c_str());
+                       std::string expr = CHECK(child->find("data_in"), != NULL)->value;
+                       printf("      %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
+                       printf("      %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
+                       printf("    end\n");
+                       else_prefix = "else ";
+               }
+
+               printf("  end\n");
+       }
+
+       printf("endmodule\n");
+}
+
+void gen_verilogsim(LibertyAst *ast)
+{
+       CHECK_COND(ast->id == "library");
+
+       for (auto child : ast->children)
+               if (child->id == "cell" && !child->find("dont_use"))
+                       gen_verilogsim_cell(child);
+}
+
+void usage()
+{
+       fprintf(stderr, "Usage: filterlib [rules-file [liberty-file]]\n");
+       fprintf(stderr, "   or: filterlib -verilogsim [liberty-file]\n");
+       exit(1);
+}
+
+int main(int argc, char **argv)
+{
+       bool flag_verilogsim = false;
+
+       if (argc > 3)
+               usage();
+
+       if (argc > 1)
+       {
+               if (!strcmp(argv[1], "-verilogsim"))
+                       flag_verilogsim = true;
+               if (!strcmp(argv[1], "-") || !strcmp(argv[1], "-verilogsim"))
+               {
+                       LibertyAst::whitelist.insert("/library");
+                       LibertyAst::whitelist.insert("/library/cell");
+                       LibertyAst::whitelist.insert("/library/cell/area");
+                       LibertyAst::whitelist.insert("/library/cell/cell_footprint");
+                       LibertyAst::whitelist.insert("/library/cell/dont_touch");
+                       LibertyAst::whitelist.insert("/library/cell/dont_use");
+                       LibertyAst::whitelist.insert("/library/cell/ff");
+                       LibertyAst::whitelist.insert("/library/cell/ff/*");
+                       LibertyAst::whitelist.insert("/library/cell/latch");
+                       LibertyAst::whitelist.insert("/library/cell/latch/*");
+                       LibertyAst::whitelist.insert("/library/cell/pin");
+                       LibertyAst::whitelist.insert("/library/cell/pin/clock");
+                       LibertyAst::whitelist.insert("/library/cell/pin/direction");
+                       LibertyAst::whitelist.insert("/library/cell/pin/driver_type");
+                       LibertyAst::whitelist.insert("/library/cell/pin/function");
+                       LibertyAst::whitelist.insert("/library/cell/pin_opposite");
+                       LibertyAst::whitelist.insert("/library/cell/pin/state_function");
+                       LibertyAst::whitelist.insert("/library/cell/pin/three_state");
+                       LibertyAst::whitelist.insert("/library/cell/statetable");
+                       LibertyAst::whitelist.insert("/library/cell/statetable/*");
+               }
+               else
+               {
+                       FILE *f = fopen(argv[1], "r");
+                       if (f == NULL) {
+                               fprintf(stderr, "Can't open rules file `%s'.\n", argv[1]);
+                               usage();
+                       }
+
+                       char buffer[1024];
+                       while (fgets(buffer, 1024, f) != NULL)
+                       {
+                               char mode = 0;
+                               std::string id;
+                               for (char *p = buffer; *p; p++)
+                               {
+                                       if (*p == '-' || *p == '+') {
+                                               if (mode != 0)
+                                                       goto syntax_error;
+                                               mode = *p;
+                                               continue;
+                                       }
+                                       if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == '#') {
+                                               if (!id.empty()) {
+                                                       if (mode == '-')
+                                                               LibertyAst::blacklist.insert(id);
+                                                       else
+                                                       if (mode == '+')
+                                                               LibertyAst::whitelist.insert(id);
+                                                       else
+                                                               goto syntax_error;
+                                               }
+                                               id.clear();
+                                               if (*p == '#')
+                                                       break;
+                                               continue;
+                                       }
+                                       id += *p;
+                                       continue;
+
+                               syntax_error:
+                                       fprintf(stderr, "Syntax error in rules file:\n%s", buffer);
+                                       exit(1);
+                               }
+                       }
+               }
+       }
+
+       FILE *f = stdin;
+       if (argc == 3) {
+               f = fopen(argv[2], "r");
+               if (f == NULL) {
+                       fprintf(stderr, "Can't open liberty file `%s'.\n", argv[2]);
+                       usage();
+               }
+       }
+
+       LibertyParer parser(f);
+       if (parser.ast) {
+               if (flag_verilogsim)
+                       gen_verilogsim(parser.ast);
+               else
+                       parser.ast->dump(stdout);
+       }
+
+       if (argc == 3)
+               fclose(f);
+
+       return 0;
+}
+
+#endif
+
diff --git a/passes/dfflibmap/libparse.h b/passes/dfflibmap/libparse.h
new file mode 100644 (file)
index 0000000..8c4a2f5
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  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 LIBPARSE_H
+#define LIBPARSE_H
+
+#include <stdio.h>
+#include <string>
+#include <vector>
+#include <set>
+
+namespace PASS_DFFLIBMAP
+{
+       struct LibertyAst
+       {
+               std::string id, value;
+               std::vector<std::string> args;
+               std::vector<LibertyAst*> children;
+               ~LibertyAst();
+               LibertyAst *find(std::string name);
+               void dump(FILE *f, std::string indent = "", std::string path = "", bool path_ok = false);
+               static std::set<std::string> blacklist;
+               static std::set<std::string> whitelist;
+       };
+
+       struct LibertyParer
+       {
+               FILE *f;
+               int line;
+               LibertyAst *ast;
+               LibertyParer(FILE *f) : f(f), line(1), ast(parse()) {}
+               ~LibertyParer() { if (ast) delete ast; }
+               int lexer(std::string &str);
+               LibertyAst *parse();
+               void error();
+       };
+}
+
+#endif
+
diff --git a/passes/fsm/Makefile.inc b/passes/fsm/Makefile.inc
new file mode 100644 (file)
index 0000000..38623e4
--- /dev/null
@@ -0,0 +1,11 @@
+
+OBJS += passes/fsm/fsm.o
+OBJS += passes/fsm/fsm_detect.o
+OBJS += passes/fsm/fsm_extract.o
+OBJS += passes/fsm/fsm_opt.o
+OBJS += passes/fsm/fsm_expand.o
+OBJS += passes/fsm/fsm_recode.o
+OBJS += passes/fsm/fsm_info.o
+OBJS += passes/fsm/fsm_export.o
+OBJS += passes/fsm/fsm_map.o
+
diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc
new file mode 100644 (file)
index 0000000..61322fb
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *  
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/log.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+struct FsmPass : public Pass {
+       FsmPass() : Pass("fsm") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               bool flag_nomap = false;
+               bool flag_norecode = false;
+               bool flag_expand = false;
+               bool flag_export = false;
+               std::string fm_set_fsm_file_opt;
+
+               log_header("Executing FSM pass (extract and optimize FSM).\n");
+               log_push();
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       std::string arg = args[argidx];
+                       if (arg == "-fm_set_fsm_file" && argidx+1 < args.size() && fm_set_fsm_file_opt.empty()) {
+                               fm_set_fsm_file_opt = " -fm_set_fsm_file " + args[++argidx];
+                               continue;
+                       }
+                       if (arg == "-norecode") {
+                               flag_norecode = true;
+                               continue;
+                       }
+                       if (arg == "-nomap") {
+                               flag_nomap = true;
+                               continue;
+                       }
+                       if (arg == "-expand") {
+                               flag_expand = true;
+                               continue;
+                       }
+                       if (arg == "-export") {
+                               flag_export = true;
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               Pass::call(design, "fsm_detect");
+               Pass::call(design, "fsm_extract");
+
+               Pass::call(design, "fsm_opt");
+               Pass::call(design, "opt_rmunused");
+               Pass::call(design, "fsm_opt");
+
+               if (flag_expand) {
+                       Pass::call(design, "fsm_expand");
+                       Pass::call(design, "opt_rmunused");
+                       Pass::call(design, "fsm_opt");
+               }
+
+               if (!flag_norecode)
+                       Pass::call(design, "fsm_recode" + fm_set_fsm_file_opt);
+               Pass::call(design, "fsm_info");
+
+               if (!flag_nomap)
+                       Pass::call(design, "fsm_map");
+
+               if (flag_export)
+                       Pass::call(design, "fsm_export");
+
+               log_pop();
+       }
+} FsmPass;
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc
new file mode 100644 (file)
index 0000000..067ed17
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ *  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 "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/consteval.h"
+#include "kernel/celltypes.h"
+#include "fsmdata.h"
+
+static RTLIL::Module *module;
+static SigMap assign_map;
+typedef std::pair<RTLIL::Cell*,std::string> sig2driver_entry_t;
+static SigSet<sig2driver_entry_t> sig2driver, sig2user;
+static std::set<RTLIL::Cell*> muxtree_cells;
+static SigPool sig_at_port;
+
+static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig)
+{
+       if (sig_at_port.check_any(assign_map(sig)))
+               return false;
+
+       if (sig.is_fully_const() || old_sig == sig)
+               return true;
+
+       std::set<sig2driver_entry_t> cellport_list;
+       sig2driver.find(sig, cellport_list);
+       for (auto &cellport : cellport_list) {
+               if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux" && cellport.first->type != "$safe_pmux") || cellport.second != "\\Y")
+                       return false;
+               RTLIL::SigSpec sig_a = assign_map(cellport.first->connections["\\A"]);
+               RTLIL::SigSpec sig_b = assign_map(cellport.first->connections["\\B"]);
+               if (!check_state_mux_tree(old_sig, sig_a))
+                       return false;
+               for (int i = 0; i < sig_b.width; i += sig_a.width)
+                       if (!check_state_mux_tree(old_sig, sig_b.extract(i, sig_a.width)))
+                               return false;
+               muxtree_cells.insert(cellport.first);
+       }
+
+       return true;
+}
+
+static bool check_state_users(RTLIL::SigSpec sig)
+{
+       if (sig_at_port.check_any(assign_map(sig)))
+               return false;
+
+       std::set<sig2driver_entry_t> cellport_list;
+       sig2user.find(sig, cellport_list);
+       for (auto &cellport : cellport_list) {
+               RTLIL::Cell *cell = cellport.first;
+               if (muxtree_cells.count(cell) > 0)
+                       continue;
+               if (cellport.second != "\\A" && cellport.second != "\\B")
+                       return false;
+               if (cell->connections.count("\\A") == 0 || cell->connections.count("\\B") == 0 || cell->connections.count("\\Y") == 0)
+                       return false;
+               for (auto &port_it : cell->connections)
+                       if (port_it.first != "\\A" && port_it.first != "\\B" && port_it.first != "\\Y")
+                               return false;
+               if (assign_map(cell->connections["\\A"]) == sig && cell->connections["\\B"].is_fully_const())
+                       continue;
+               if (assign_map(cell->connections["\\B"]) == sig && cell->connections["\\A"].is_fully_const())
+                       continue;
+               return false;
+       }
+
+       return true;
+}
+
+static void detect_fsm(RTLIL::Wire *wire)
+{
+       if (wire->attributes.count("\\fsm_encoding") > 0 || wire->width <= 1)
+               return;
+       if (sig_at_port.check_any(assign_map(RTLIL::SigSpec(wire))))
+               return;
+
+       std::set<sig2driver_entry_t> cellport_list;
+       sig2driver.find(RTLIL::SigSpec(wire), cellport_list);
+       for (auto &cellport : cellport_list) {
+               if ((cellport.first->type != "$dff" && cellport.first->type != "$adff") || cellport.second != "\\Q")
+                       continue;
+               muxtree_cells.clear();
+               RTLIL::SigSpec sig_q = assign_map(cellport.first->connections["\\Q"]);
+               RTLIL::SigSpec sig_d = assign_map(cellport.first->connections["\\D"]);
+               if (sig_q == RTLIL::SigSpec(wire) && check_state_mux_tree(sig_q, sig_d) && check_state_users(sig_q)) {
+                       log("Found FSM state register %s in module %s.\n", wire->name.c_str(), module->name.c_str());
+                       wire->attributes["\\fsm_encoding"] = RTLIL::Const("auto");
+                       return;
+               }
+       }
+}
+
+struct FsmDetectPass : public Pass {
+       FsmDetectPass() : Pass("fsm_detect") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing FSM_DETECT pass (finding FSMs in design).\n");
+               extra_args(args, 1, design);
+
+               CellTypes ct;
+               ct.setup_internals();
+               ct.setup_internals_mem();
+               ct.setup_stdcells();
+               ct.setup_stdcells_mem();
+
+               for (auto &mod_it : design->modules)
+               {
+                       module = mod_it.second;
+                       assign_map.set(module);
+
+                       sig2driver.clear();
+                       sig2user.clear();
+                       sig_at_port.clear();
+                       for (auto &cell_it : module->cells)
+                               for (auto &conn_it : cell_it.second->connections) {
+                                       if (ct.cell_output(cell_it.second->type, conn_it.first)) {
+                                               RTLIL::SigSpec sig = conn_it.second;
+                                               assign_map.apply(sig);
+                                               sig2driver.insert(sig, sig2driver_entry_t(cell_it.second, conn_it.first));
+                                       }
+                                       if (!ct.cell_known(cell_it.second->type) || ct.cell_input(cell_it.second->type, conn_it.first)) {
+                                               RTLIL::SigSpec sig = conn_it.second;
+                                               assign_map.apply(sig);
+                                               sig2user.insert(sig, sig2driver_entry_t(cell_it.second, conn_it.first));
+                                       }
+                               }
+
+                       for (auto &wire_it : module->wires)
+                               if (wire_it.second->port_id != 0)
+                                       sig_at_port.add(assign_map(RTLIL::SigSpec(wire_it.second)));
+
+                       for (auto &wire_it : module->wires)
+                               detect_fsm(wire_it.second);
+               }
+
+               assign_map.clear();
+               sig2driver.clear();
+               sig2user.clear();
+               muxtree_cells.clear();
+       }
+} FsmDetectPass;
diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc
new file mode 100644 (file)
index 0000000..0d5bc76
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ *  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 "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/consteval.h"
+#include "kernel/celltypes.h"
+#include "fsmdata.h"
+#include <string.h>
+
+struct FsmExpand
+{
+       RTLIL::Module *module;
+       RTLIL::Cell *fsm_cell;
+       SigMap assign_map;
+       SigSet<RTLIL::Cell*> sig2driver, sig2user;
+       CellTypes ct;
+
+       std::set<RTLIL::Cell*> merged_set;
+       std::set<RTLIL::Cell*> current_set;
+       std::set<RTLIL::Cell*> no_candidate_set;
+
+       bool already_optimized;
+       int limit_transitions;
+
+       bool is_cell_merge_candidate(RTLIL::Cell *cell)
+       {
+               RTLIL::SigSpec new_signals;
+               if (cell->connections.count("\\A") > 0)
+                       new_signals.append(assign_map(cell->connections["\\A"]));
+               if (cell->connections.count("\\B") > 0)
+                       new_signals.append(assign_map(cell->connections["\\B"]));
+               if (cell->connections.count("\\S") > 0)
+                       new_signals.append(assign_map(cell->connections["\\S"]));
+
+               new_signals.sort_and_unify();
+               new_signals.remove_const();
+
+               if (new_signals.width > 4)
+                       return false;
+
+               new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_IN"]));
+               new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_OUT"]));
+
+               if (cell->connections.count("\\Y") > 0) {
+                       new_signals.append(assign_map(cell->connections["\\Y"]));
+                       new_signals.sort_and_unify();
+                       new_signals.remove_const();
+                       new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_IN"]));
+                       new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_OUT"]));
+               }
+
+               if (new_signals.width > 2)
+                       return false;
+
+               return true;
+       }
+
+       void create_current_set()
+       {
+               std::vector<RTLIL::Cell*> cell_list;
+
+               for (auto c : sig2driver.find(assign_map(fsm_cell->connections["\\CTRL_IN"])))
+                       cell_list.push_back(c);
+
+               for (auto c : sig2user.find(assign_map(fsm_cell->connections["\\CTRL_OUT"])))
+                       cell_list.push_back(c);
+
+               current_set.clear();
+               for (auto c : cell_list)
+               {
+                       if (merged_set.count(c) > 0 || current_set.count(c) > 0 || no_candidate_set.count(c) > 0)
+                               continue;
+                       for (auto &p : c->connections) {
+                               if (p.first != "\\A" && p.first != "\\B" && p.first != "\\S" && p.first != "\\Y")
+                                       goto next_cell;
+                       }
+                       if (!is_cell_merge_candidate(c)) {
+                               no_candidate_set.insert(c);
+                               continue;
+                       }
+                       current_set.insert(c);
+               next_cell:;
+               }
+       }
+
+       void optimze_as_needed()
+       {
+               if (already_optimized)
+                       return;
+
+               int trans_num = fsm_cell->parameters["\\TRANS_NUM"].as_int();
+               if (trans_num > limit_transitions)
+               {
+                       log("  grown transition table to %d entries -> optimize.\n", trans_num);
+                       FsmData::optimize_fsm(fsm_cell, module);
+                       already_optimized = true;
+
+                       trans_num = fsm_cell->parameters["\\TRANS_NUM"].as_int();
+                       log("  transition table size after optimizaton: %d\n", trans_num);
+                       limit_transitions = 16 * trans_num;
+               }
+       }
+
+       void merge_cell_into_fsm(RTLIL::Cell *cell)
+       {
+               optimze_as_needed();
+
+               log("  merging %s cell %s.\n", cell->type.c_str(), cell->name.c_str());
+               merged_set.insert(cell);
+               already_optimized = false;
+
+               RTLIL::SigSpec input_sig, output_sig;
+
+               for (auto &p : cell->connections)
+                       if (ct.cell_output(cell->type, p.first))
+                               output_sig.append(assign_map(p.second));
+                       else
+                               input_sig.append(assign_map(p.second));
+               input_sig.sort_and_unify();
+               input_sig.remove_const();
+
+               assert(input_sig.width <= 4);
+               std::vector<RTLIL::Const> truth_tab;
+
+               for (int i = 0; i < (1 << input_sig.width); i++) {
+                       RTLIL::Const in_val(i, input_sig.width);
+                       RTLIL::SigSpec A, B, S;
+                       if (cell->connections.count("\\A") > 0)
+                               A = assign_map(cell->connections["\\A"]);
+                       if (cell->connections.count("\\B") > 0)
+                               B = assign_map(cell->connections["\\B"]);
+                       if (cell->connections.count("\\S") > 0)
+                               S = assign_map(cell->connections["\\S"]);
+                       A.replace(input_sig, RTLIL::SigSpec(in_val));
+                       B.replace(input_sig, RTLIL::SigSpec(in_val));
+                       S.replace(input_sig, RTLIL::SigSpec(in_val));
+                       assert(A.is_fully_const());
+                       assert(B.is_fully_const());
+                       assert(S.is_fully_const());
+                       truth_tab.push_back(ct.eval(cell, A.as_const(), B.as_const(), S.as_const()));
+               }
+
+               FsmData fsm_data;
+               fsm_data.copy_from_cell(fsm_cell);
+
+               fsm_data.num_inputs += input_sig.width;
+               fsm_cell->connections["\\CTRL_IN"].append(input_sig);
+
+               fsm_data.num_outputs += output_sig.width;
+               fsm_cell->connections["\\CTRL_OUT"].append(output_sig);
+
+               std::vector<FsmData::transition_t> new_transition_table;
+               for (auto &tr : fsm_data.transition_table) {
+                       for (int i = 0; i < (1 << input_sig.width); i++) {
+                               FsmData::transition_t new_tr = tr;
+                               RTLIL::Const in_val(i, input_sig.width);
+                               RTLIL::Const out_val = truth_tab[i];
+                               RTLIL::SigSpec ctrl_in = new_tr.ctrl_in;
+                               RTLIL::SigSpec ctrl_out = new_tr.ctrl_out;
+                               ctrl_in.append(in_val);
+                               ctrl_out.append(out_val);
+                               new_tr.ctrl_in = ctrl_in.as_const();
+                               new_tr.ctrl_out = ctrl_out.as_const();
+                               new_transition_table.push_back(new_tr);
+                       }
+               }
+               fsm_data.transition_table.swap(new_transition_table);
+               new_transition_table.clear();
+
+               fsm_data.copy_to_cell(fsm_cell);
+       }
+
+       FsmExpand(RTLIL::Cell *cell, RTLIL::Module *mod)
+       {
+               module = mod;
+               fsm_cell = cell;
+
+               assign_map.set(module);
+               ct.setup_internals();
+
+               for (auto &cell_it : module->cells) {
+                       RTLIL::Cell *c = cell_it.second;
+                       if (ct.cell_known(c->type))
+                               for (auto &p : c->connections) {
+                                       if (ct.cell_output(c->type, p.first))
+                                               sig2driver.insert(assign_map(p.second), c);
+                                       else
+                                               sig2user.insert(assign_map(p.second), c);
+                               }
+               }
+       }
+
+       void execute()
+       {
+               log("\n");
+               log("Expanding FSM `%s' from module `%s':\n", fsm_cell->name.c_str(), module->name.c_str());
+
+               already_optimized = false;
+               limit_transitions =  16 * fsm_cell->parameters["\\TRANS_NUM"].as_int();
+
+               for (create_current_set(); current_set.size() > 0; create_current_set()) {
+                       for (auto c : current_set)
+                               merge_cell_into_fsm(c);
+               }
+
+               for (auto c : merged_set) {
+                       module->cells.erase(c->name);
+                       delete c;
+               }
+
+               if (merged_set.size() > 0 && !already_optimized)
+                       FsmData::optimize_fsm(fsm_cell, module);
+
+               log("  merged %zd cells into FSM.\n", merged_set.size());
+       }
+};
+
+struct FsmExpandPass : public Pass {
+       FsmExpandPass() : Pass("fsm_expand") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing FSM_EXPAND pass (re-assigning FSM state encoding).\n");
+               extra_args(args, 1, design);
+
+               for (auto &mod_it : design->modules) {
+                       std::vector<RTLIL::Cell*> fsm_cells;
+                       for (auto &cell_it : mod_it.second->cells)
+                               if (cell_it.second->type == "$fsm")
+                                       fsm_cells.push_back(cell_it.second);
+                       for (auto c : fsm_cells) {
+                               FsmExpand fsm_expand(c, mod_it.second);
+                               fsm_expand.execute();
+                       }
+               }
+       }
+} FsmExpandPass;
diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc
new file mode 100644 (file)
index 0000000..0219f4e
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2012  Martin Schmölzer <martin@schmoelzer.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 "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/consteval.h"
+#include "kernel/celltypes.h"
+#include "fsmdata.h"
+#include <string>
+#include <iostream>
+#include <fstream>
+
+/**
+ * Convert signal into a KISS-compatible textual representation.
+ */
+std::string kiss_convert_signal(const RTLIL::SigSpec &sig) {
+       if (!sig.is_fully_const()) {
+               throw 0;
+       }
+
+       return sig.as_const().as_string();
+}
+
+/**
+ * Exports each Finite State Machine (FSM) in the design to a file in KISS2 format.
+ */
+struct FsmExportPass : public Pass {
+       FsmExportPass() : Pass("fsm_export") {
+       }
+
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               FsmData       fsm_data;
+               std::string   kiss_name;
+               std::ofstream kiss_file;
+               size_t        i;
+               FsmData::transition_t tr;
+
+               log_header("Executing FSM_EXPORT pass (exporting FSMs in KISS2 file format).\n");
+               extra_args(args, 1, design);
+
+               for (auto &mod_it : design->modules)
+                       for (auto &cell_it : mod_it.second->cells)
+                               if (cell_it.second->type == "$fsm") {
+                                       kiss_name.assign(mod_it.first.c_str());
+                                       kiss_name.append("-" + cell_it.second->name + ".kiss2");
+                                       fsm_data.copy_from_cell(cell_it.second);
+
+                                       log("\n");
+                                       log("Exporting FSM `%s' from module `%s' to file `%s'.\n",
+                                                       cell_it.second->name.c_str(),
+                                                       mod_it.first.c_str(),
+                                                       kiss_name.c_str());
+
+                                       kiss_file.open(kiss_name, std::ios::out | std::ios::trunc);
+
+                                       if (!kiss_file.is_open()) {
+                                               log_error("Could not open file \"%s\" with write access.\n", kiss_name.c_str());
+                                               return;
+                                       }
+
+                                       kiss_file << ".start_kiss" << std::endl;
+                                       kiss_file << ".i " << std::dec << fsm_data.num_inputs << std::endl;
+                                       kiss_file << ".o " << std::dec << fsm_data.num_outputs << std::endl;
+                                       kiss_file << ".r s" << std::dec << fsm_data.reset_state << std::endl;
+
+                                       for (i = 0; i < fsm_data.transition_table.size(); i++) {
+                                               tr = fsm_data.transition_table[i];
+
+                                               try {
+                                                       kiss_file << kiss_convert_signal(tr.ctrl_in) << ' ';
+                                                       kiss_file << 's' << tr.state_in << ' ';
+                                                       kiss_file << 's' << tr.state_out << ' ';
+                                                       kiss_file << kiss_convert_signal(tr.ctrl_out) << std::endl;
+                                               }
+                                               catch (int) {
+                                                       log_error("exporting an FSM input or output signal failed.\n");
+                                               }
+                                       }
+
+                                       kiss_file << ".end_kiss" << std::endl << ".end" << std::endl;
+                                       kiss_file.close();
+                               }
+       }
+} FsmExportPass;
diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc
new file mode 100644 (file)
index 0000000..bdcb1d4
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ *  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 "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/consteval.h"
+#include "kernel/celltypes.h"
+#include "fsmdata.h"
+
+static RTLIL::Module *module;
+static SigMap assign_map;
+typedef std::pair<RTLIL::Cell*,std::string> sig2driver_entry_t;
+static SigSet<sig2driver_entry_t> sig2driver, sig2trigger;
+
+static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL::SigSpec &ctrl, std::map<RTLIL::Const, int> &states, RTLIL::Const *reset_state = NULL)
+{
+       sig.extend(dff_out.width, false);
+
+       if (sig == dff_out)
+               return true;
+
+       assign_map.apply(sig);
+       if (sig.is_fully_const()) {
+               sig.optimize();
+               assert(sig.chunks.size() == 1);
+               if (states.count(sig.chunks[0].data) == 0) {
+                       log("  found state code: %s\n", log_signal(sig));
+                       states[sig.chunks[0].data] = -1;
+               }
+               return true;
+       }
+
+       std::set<sig2driver_entry_t> cellport_list;
+       sig2driver.find(sig, cellport_list);
+       for (auto &cellport : cellport_list) {
+               if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux" && cellport.first->type != "$safe_pmux") || cellport.second != "\\Y") {
+                       log("  unexpected cell type %s (%s) found in state selection tree.\n",
+                                       cellport.first->type.c_str(), cellport.first->name.c_str());
+                       return false;
+               }
+               RTLIL::SigSpec sig_a = assign_map(cellport.first->connections["\\A"]);
+               RTLIL::SigSpec sig_b = assign_map(cellport.first->connections["\\B"]);
+               RTLIL::SigSpec sig_s = assign_map(cellport.first->connections["\\S"]);
+               if (reset_state && RTLIL::SigSpec(*reset_state).is_fully_undef())
+                       do {
+                               if (sig_a.is_fully_def())
+                                       *reset_state = sig_a.as_const();
+                               else if (sig_b.is_fully_def())
+                                       *reset_state = sig_b.as_const();
+                               else
+                                       break;
+                               log("  found reset state: %s (guessed from mux tree)\n", log_signal(*reset_state));
+                       } while (0);
+               if (ctrl.extract(sig_s).width == 0) {
+                       log("  found ctrl input: %s\n", log_signal(sig_s));
+                       ctrl.append(sig_s);
+               }
+               if (!find_states(sig_a, dff_out, ctrl, states))
+                       return false;
+               for (int i = 0; i < sig_b.width/sig_a.width; i++) {
+                       if (!find_states(sig_b.extract(i*sig_a.width, sig_a.width), dff_out, ctrl, states))
+                               return false;
+               }
+       }
+
+       return true;
+}
+
+static RTLIL::Const sig2const(ConstEval &ce, RTLIL::SigSpec sig, RTLIL::State noconst_state, RTLIL::SigSpec dont_care = RTLIL::SigSpec())
+{
+       if (dont_care.width > 0) {
+               sig.expand();
+               for (auto &chunk : sig.chunks) {
+                       assert(chunk.width == 1);
+                       if (dont_care.extract(chunk).width > 0)
+                               chunk.wire = NULL, chunk.data = RTLIL::Const(noconst_state);
+               }
+               sig.optimize();
+       }
+
+       ce.assign_map.apply(sig);
+       ce.values_map.apply(sig);
+
+       sig.expand();
+       for (auto &chunk : sig.chunks) {
+               assert(chunk.width == 1);
+               if (chunk.wire != NULL)
+                       chunk.wire = NULL, chunk.data = RTLIL::Const(noconst_state);
+       }
+       sig.optimize();
+
+       if (sig.width == 0)
+               return RTLIL::Const();
+       assert(sig.chunks.size() == 1 && sig.chunks[0].wire == NULL);
+       return sig.chunks[0].data;
+}
+
+static void find_transitions(ConstEval &ce, ConstEval &ce_nostop, FsmData &fsm_data, std::map<RTLIL::Const, int> &states, int state_in, RTLIL::SigSpec ctrl_in, RTLIL::SigSpec ctrl_out, RTLIL::SigSpec dff_in, RTLIL::SigSpec dont_care)
+{
+       RTLIL::SigSpec undef, constval;
+
+       if (ce.eval(ctrl_out, undef) && ce.eval(dff_in, undef)) {
+               assert(ctrl_out.is_fully_const() && dff_in.is_fully_const());
+               FsmData::transition_t tr;
+               tr.state_in = state_in;
+               tr.state_out = states[ce.values_map(ce.assign_map(dff_in)).as_const()];
+               tr.ctrl_in = sig2const(ce, ctrl_in, RTLIL::State::Sa, dont_care);
+               tr.ctrl_out = sig2const(ce, ctrl_out, RTLIL::State::Sx);
+               RTLIL::Const log_state_in = RTLIL::Const(RTLIL::State::Sx, fsm_data.state_bits);
+               if (state_in >= 0)
+                       log_state_in = fsm_data.state_table[tr.state_in];
+               if (dff_in.is_fully_def()) {
+                       fsm_data.transition_table.push_back(tr);
+                       log("  transition: %10s %s -> %10s %s\n",
+                                       log_signal(log_state_in), log_signal(tr.ctrl_in),
+                                       log_signal(fsm_data.state_table[tr.state_out]), log_signal(tr.ctrl_out));
+               } else {
+                       log("  transition: %10s %s -> %10s %s  <ignored undef transistion!>\n",
+                                       log_signal(log_state_in), log_signal(tr.ctrl_in),
+                                       log_signal(fsm_data.state_table[tr.state_out]), log_signal(tr.ctrl_out));
+               }
+               return;
+       }
+
+       assert(undef.width > 0);
+       assert(ce.stop_signals.check_all(undef));
+
+       undef = undef.extract(0, 1);
+       constval = undef;
+
+       if (ce_nostop.eval(constval))
+       {
+               ce.push();
+               dont_care.append(undef);
+               ce.set(undef, constval.as_const());
+               find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care);
+               ce.pop();
+       }
+       else
+       {
+               ce.push(), ce_nostop.push();
+               ce.set(undef, RTLIL::Const(0, 1));
+               ce_nostop.set(undef, RTLIL::Const(0, 1));
+               find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care);
+               ce.pop(), ce_nostop.pop();
+
+               ce.push(), ce_nostop.push();
+               ce.set(undef, RTLIL::Const(1, 1));
+               ce_nostop.set(undef, RTLIL::Const(1, 1));
+               find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care);
+               ce.pop(), ce_nostop.pop();
+       }
+}
+
+static void extract_fsm(RTLIL::Wire *wire)
+{
+       log("Extracting FSM `%s' from module `%s'.\n", wire->name.c_str(), module->name.c_str());
+
+       // get input and output signals for state ff 
+
+       RTLIL::SigSpec dff_out = assign_map(RTLIL::SigSpec(wire));
+       RTLIL::SigSpec dff_in(RTLIL::State::Sm, wire->width);
+       RTLIL::Const reset_state(RTLIL::State::Sx, wire->width);
+
+       RTLIL::SigSpec clk = RTLIL::SigSpec(0, 1);
+       RTLIL::SigSpec arst = RTLIL::SigSpec(0, 1);
+       bool clk_polarity = true;
+       bool arst_polarity = true;
+
+       std::set<sig2driver_entry_t> cellport_list;
+       sig2driver.find(dff_out, cellport_list);
+       for (auto &cellport : cellport_list) {
+               if ((cellport.first->type != "$dff" && cellport.first->type != "$adff") || cellport.second != "\\Q")
+                       continue;
+               log("  found %s cell for state register: %s\n", cellport.first->type.c_str(), cellport.first->name.c_str());
+               RTLIL::SigSpec sig_q = assign_map(cellport.first->connections["\\Q"]);
+               RTLIL::SigSpec sig_d = assign_map(cellport.first->connections["\\D"]);
+               clk = cellport.first->connections["\\CLK"];
+               clk_polarity = cellport.first->parameters["\\CLK_POLARITY"].as_bool();
+               if (cellport.first->type == "$adff") {
+                       arst = cellport.first->connections["\\ARST"];
+                       arst_polarity = cellport.first->parameters["\\ARST_POLARITY"].as_bool();
+                       reset_state = cellport.first->parameters["\\ARST_VALUE"];
+               }
+               sig_q.replace(dff_out, sig_d, &dff_in);
+               break;
+       }
+
+       log("  root of input selection tree: %s\n", log_signal(dff_in));
+       if (dff_in.has_marked_bits()) {
+               log("  fsm extraction failed: incomplete input selection tree root.\n");
+               return;
+       }
+
+       // find states and control inputs
+
+       RTLIL::SigSpec ctrl_in;
+       std::map<RTLIL::Const, int> states;
+       if (!arst.is_fully_const()) {
+               log("  found reset state: %s (from async reset)\n", log_signal(reset_state));
+               states[reset_state] = -1;
+       }
+       if (!find_states(dff_in, dff_out, ctrl_in, states, &reset_state)) {
+               log("  fsm extraction failed: state selection tree is not closed.\n");
+               return;
+       }
+
+       // find control outputs
+       // (add the state signals to the list of control outputs. if everything goes right, this signals
+       // become unused and can then be removed from the fsm control output)
+
+       RTLIL::SigSpec ctrl_out = dff_in;
+       cellport_list.clear();
+       sig2trigger.find(dff_out, cellport_list);
+       for (auto &cellport : cellport_list) {
+               RTLIL::SigSpec sig_a = assign_map(cellport.first->connections["\\A"]);
+               RTLIL::SigSpec sig_b = assign_map(cellport.first->connections["\\B"]);
+               RTLIL::SigSpec sig_y = assign_map(cellport.first->connections["\\Y"]);
+               if (cellport.second == "\\A" && !sig_b.is_fully_const())
+                       continue;
+               if (cellport.second == "\\B" && !sig_a.is_fully_const())
+                       continue;
+               log("  found ctrl output: %s\n", log_signal(sig_y));
+               ctrl_out.append(sig_y);
+       }
+       ctrl_in.remove(ctrl_out);
+
+       log("  ctrl inputs: %s\n", log_signal(ctrl_in));
+       log("  ctrl outputs: %s\n", log_signal(ctrl_out));
+
+       // Initialize fsm data struct
+
+       FsmData fsm_data;
+       fsm_data.num_inputs = ctrl_in.width;
+       fsm_data.num_outputs = ctrl_out.width;
+       fsm_data.state_bits = wire->width;
+       fsm_data.reset_state = -1;
+       for (auto &it : states) {
+               it.second = fsm_data.state_table.size();
+               fsm_data.state_table.push_back(it.first);
+       }
+       if (!arst.is_fully_const() || RTLIL::SigSpec(reset_state).is_fully_def())
+               fsm_data.reset_state = states[reset_state];
+
+       // Create transition table
+
+       ConstEval ce(module), ce_nostop(module);
+       ce.stop(ctrl_in);
+       for (int state_idx = 0; state_idx < int(fsm_data.state_table.size()); state_idx++) {
+               ce.push(), ce_nostop.push();
+               ce.set(dff_out, fsm_data.state_table[state_idx]);
+               ce_nostop.set(dff_out, fsm_data.state_table[state_idx]);
+               find_transitions(ce, ce_nostop, fsm_data, states, state_idx, ctrl_in, ctrl_out, dff_in, RTLIL::SigSpec());
+               ce.pop(), ce_nostop.pop();
+       }
+
+       // create fsm cell
+
+       RTLIL::Cell *fsm_cell = new RTLIL::Cell;
+       fsm_cell->name = stringf("$fsm$%s$%d", wire->name.c_str(), RTLIL::autoidx++);
+       fsm_cell->type = "$fsm";
+       fsm_cell->connections["\\CLK"] = clk;
+       fsm_cell->connections["\\ARST"] = arst;
+       fsm_cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity ? 1 : 0, 1);
+       fsm_cell->parameters["\\ARST_POLARITY"] = RTLIL::Const(arst_polarity ? 1 : 0, 1);
+       fsm_cell->connections["\\CTRL_IN"] = ctrl_in;
+       fsm_cell->connections["\\CTRL_OUT"] = ctrl_out;
+       fsm_cell->parameters["\\NAME"] = RTLIL::Const(wire->name);
+       fsm_data.copy_to_cell(fsm_cell);
+       module->cells[fsm_cell->name] = fsm_cell;
+
+       // rename original state wire
+
+       module->wires.erase(wire->name);
+       wire->attributes.erase("\\fsm_encoding");
+       wire->name = stringf("$fsm$oldstate%s", wire->name.c_str());
+       module->wires[wire->name] = wire;
+
+       // unconnect control outputs from old drivers
+
+       cellport_list.clear();
+       sig2driver.find(ctrl_out, cellport_list);
+       for (auto &cellport : cellport_list) {
+               RTLIL::SigSpec port_sig = assign_map(cellport.first->connections[cellport.second]);
+               RTLIL::SigSpec unconn_sig = port_sig.extract(ctrl_out);
+               RTLIL::Wire *unconn_wire = new RTLIL::Wire;
+               unconn_wire->name = stringf("$fsm_unconnect$%s$%d", log_signal(unconn_sig), RTLIL::autoidx++);
+               unconn_wire->width = unconn_sig.width;
+               module->wires[unconn_wire->name] = unconn_wire;
+               port_sig.replace(unconn_sig, RTLIL::SigSpec(unconn_wire), &cellport.first->connections[cellport.second]);
+       }
+}
+
+struct FsmExtractPass : public Pass {
+       FsmExtractPass() : Pass("fsm_extract") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing FSM_EXTRACT pass (extracting FSM from design).\n");
+               extra_args(args, 1, design);
+
+               CellTypes ct;
+               ct.setup_internals();
+               ct.setup_internals_mem();
+               ct.setup_stdcells();
+               ct.setup_stdcells_mem();
+
+               for (auto &mod_it : design->modules)
+               {
+                       module = mod_it.second;
+                       assign_map.set(module);
+
+                       sig2driver.clear();
+                       sig2trigger.clear();
+                       for (auto &cell_it : module->cells)
+                               for (auto &conn_it : cell_it.second->connections) {
+                                       if (ct.cell_output(cell_it.second->type, conn_it.first)) {
+                                               RTLIL::SigSpec sig = conn_it.second;
+                                               assign_map.apply(sig);
+                                               sig2driver.insert(sig, sig2driver_entry_t(cell_it.second, conn_it.first));
+                                       }
+                                       if (ct.cell_input(cell_it.second->type, conn_it.first) && cell_it.second->connections.count("\\Y") > 0 &&
+                                                       cell_it.second->connections["\\Y"].width == 1 && (conn_it.first == "\\A" || conn_it.first == "\\B")) {
+                                               RTLIL::SigSpec sig = conn_it.second;
+                                               assign_map.apply(sig);
+                                               sig2trigger.insert(sig, sig2driver_entry_t(cell_it.second, conn_it.first));
+                                       }
+                               }
+
+                       std::vector<RTLIL::Wire*> wire_list;
+                       for (auto &wire_it : module->wires)
+                               if (wire_it.second->attributes.count("\\fsm_encoding") > 0 && wire_it.second->attributes["\\fsm_encoding"].str != "none")
+                                       wire_list.push_back(wire_it.second);
+                       for (auto wire : wire_list)
+                               extract_fsm(wire);
+               }
+
+               assign_map.clear();
+               sig2driver.clear();
+               sig2trigger.clear();
+       }
+} FsmExtractPass;
diff --git a/passes/fsm/fsm_info.cc b/passes/fsm/fsm_info.cc
new file mode 100644 (file)
index 0000000..83f0657
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ *  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 "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/consteval.h"
+#include "kernel/celltypes.h"
+#include "fsmdata.h"
+#include <string.h>
+
+struct FsmInfoPass : public Pass {
+       FsmInfoPass() : Pass("fsm_info") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing FSM_INFO pass (dumping all available information on FSM cells).\n");
+               extra_args(args, 1, design);
+
+               for (auto &mod_it : design->modules)
+               for (auto &cell_it : mod_it.second->cells)
+                       if (cell_it.second->type == "$fsm") {
+                               log("\n");
+                               log("FSM `%s' from module `%s':\n", cell_it.second->name.c_str(), mod_it.first.c_str());
+                               FsmData fsm_data;
+                               fsm_data.copy_from_cell(cell_it.second);
+                               fsm_data.log_info(cell_it.second);
+                       }
+       }
+} FsmInfoPass;
diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc
new file mode 100644 (file)
index 0000000..4319dc0
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ *  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 "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/consteval.h"
+#include "kernel/celltypes.h"
+#include "fsmdata.h"
+#include <string.h>
+
+static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const, std::set<int>> &pattern_cache, std::set<int> &fullstate_cache, int num_states, RTLIL::Wire *state_onehot, RTLIL::SigSpec &ctrl_in, RTLIL::SigSpec output)
+{
+       RTLIL::SigSpec cases_vector;
+
+       for (int in_state : fullstate_cache)
+               cases_vector.append(RTLIL::SigSpec(state_onehot, 1, in_state));
+
+       for (auto &it : pattern_cache)
+       {
+               RTLIL::Const pattern = it.first;
+               RTLIL::SigSpec eq_sig_a, eq_sig_b, or_sig;
+
+               for (size_t j = 0; j < pattern.bits.size(); j++)
+                       if (pattern.bits[j] == RTLIL::State::S0 || pattern.bits[j] == RTLIL::State::S1) {
+                               eq_sig_a.append(ctrl_in.extract(j, 1));
+                               eq_sig_b.append(RTLIL::SigSpec(pattern.bits[j]));
+                       }
+               eq_sig_a.optimize();
+               eq_sig_b.optimize();
+
+               for (int in_state : it.second)
+                       if (fullstate_cache.count(in_state) == 0)
+                               or_sig.append(RTLIL::SigSpec(state_onehot, 1, in_state));
+               or_sig.optimize();
+
+               if (or_sig.width == 0)
+                       continue;
+
+               RTLIL::SigSpec and_sig;
+
+               if (eq_sig_a.width > 0)
+               {
+                       RTLIL::Wire *eq_wire = new RTLIL::Wire;
+                       eq_wire->name = NEW_ID;
+                       module->add(eq_wire);
+
+                       RTLIL::Cell *eq_cell = new RTLIL::Cell;
+                       eq_cell->name = NEW_ID;
+                       eq_cell->type = "$eq";
+                       eq_cell->connections["\\A"] = eq_sig_a;
+                       eq_cell->connections["\\B"] = eq_sig_b;
+                       eq_cell->connections["\\Y"] = RTLIL::SigSpec(eq_wire);
+                       eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
+                       eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(false);
+                       eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(eq_sig_a.width);
+                       eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(eq_sig_b.width);
+                       eq_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+                       module->add(eq_cell);
+
+                       and_sig.append(RTLIL::SigSpec(eq_wire));
+               }
+
+               if (or_sig.width == 1)
+               {
+                       and_sig.append(or_sig);
+               }
+               else if (or_sig.width < num_states && int(it.second.size()) < num_states)
+               {
+                       RTLIL::Wire *or_wire = new RTLIL::Wire;
+                       or_wire->name = NEW_ID;
+                       module->add(or_wire);
+
+                       RTLIL::Cell *or_cell = new RTLIL::Cell;
+                       or_cell->name = NEW_ID;
+                       or_cell->type = "$reduce_or";
+                       or_cell->connections["\\A"] = or_sig;
+                       or_cell->connections["\\Y"] = RTLIL::SigSpec(or_wire);
+                       or_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
+                       or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(or_sig.width);
+                       or_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+                       module->add(or_cell);
+
+                       and_sig.append(RTLIL::SigSpec(or_wire));
+               }
+
+               switch (and_sig.width)
+               {
+               case 2:
+                       {
+                               RTLIL::Wire *and_wire = new RTLIL::Wire;
+                               and_wire->name = NEW_ID;
+                               module->add(and_wire);
+
+                               RTLIL::Cell *and_cell = new RTLIL::Cell;
+                               and_cell->name = NEW_ID;
+                               and_cell->type = "$and";
+                               and_cell->connections["\\A"] = and_sig.extract(0, 1);
+                               and_cell->connections["\\B"] = and_sig.extract(1, 1);
+                               and_cell->connections["\\Y"] = RTLIL::SigSpec(and_wire);
+                               and_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
+                               and_cell->parameters["\\B_SIGNED"] = RTLIL::Const(false);
+                               and_cell->parameters["\\A_WIDTH"] = RTLIL::Const(1);
+                               and_cell->parameters["\\B_WIDTH"] = RTLIL::Const(1);
+                               and_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+                               module->add(and_cell);
+
+                               cases_vector.append(RTLIL::SigSpec(and_wire));
+                               break;
+                       }
+               case 1:
+                       cases_vector.append(and_sig);
+                       break;
+               case 0:
+                       cases_vector.append(RTLIL::SigSpec(1, 1));
+                       break;
+               default:
+                       assert(!"This should never happen!");
+               }
+       }
+
+       if (cases_vector.width > 1) {
+               RTLIL::Cell *or_cell = new RTLIL::Cell;
+               or_cell->name = NEW_ID;
+               or_cell->type = "$reduce_or";
+               or_cell->connections["\\A"] = cases_vector;
+               or_cell->connections["\\Y"] = output;
+               or_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
+               or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(cases_vector.width);
+               or_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+               module->add(or_cell);
+       } else if (cases_vector.width == 1) {
+               module->connections.push_back(RTLIL::SigSig(output, cases_vector));
+       } else {
+               module->connections.push_back(RTLIL::SigSig(output, RTLIL::SigSpec(0, 1)));
+       }
+}
+
+static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
+{
+       log("Mapping FSM `%s' from module `%s'.\n", fsm_cell->name.c_str(), module->name.c_str());
+
+       FsmData fsm_data;
+       fsm_data.copy_from_cell(fsm_cell);
+
+       RTLIL::SigSpec ctrl_in = fsm_cell->connections["\\CTRL_IN"];
+       RTLIL::SigSpec ctrl_out = fsm_cell->connections["\\CTRL_OUT"];
+
+       // create state register
+
+       RTLIL::Wire *state_wire = new RTLIL::Wire;
+       state_wire->name = fsm_cell->parameters["\\NAME"].str;
+       while (module->count_id(state_wire->name) > 0)
+               state_wire->name += "_";
+       state_wire->width = fsm_data.state_bits;
+       module->add(state_wire);
+
+       RTLIL::Wire *next_state_wire = new RTLIL::Wire;
+       next_state_wire->name = NEW_ID;
+       next_state_wire->width = fsm_data.state_bits;
+       module->add(next_state_wire);
+
+       RTLIL::Cell *state_dff = new RTLIL::Cell;
+       state_dff->name = NEW_ID;
+       if (fsm_cell->connections["\\ARST"].is_fully_const()) {
+               state_dff->type = "$dff";
+       } else {
+               state_dff->type = "$adff";
+               state_dff->parameters["\\ARST_POLARITY"] = fsm_cell->parameters["\\ARST_POLARITY"];
+               state_dff->parameters["\\ARST_VALUE"] = fsm_data.state_table[fsm_data.reset_state];
+               state_dff->connections["\\ARST"] = fsm_cell->connections["\\ARST"];
+       }
+       state_dff->parameters["\\WIDTH"] = RTLIL::Const(fsm_data.state_bits);
+       state_dff->parameters["\\CLK_POLARITY"] = fsm_cell->parameters["\\CLK_POLARITY"];
+       state_dff->connections["\\CLK"] = fsm_cell->connections["\\CLK"];
+       state_dff->connections["\\D"] = RTLIL::SigSpec(next_state_wire);
+       state_dff->connections["\\Q"] = RTLIL::SigSpec(state_wire);
+       module->add(state_dff);
+
+       // decode state register
+
+       bool encoding_is_onehot = true;
+
+       RTLIL::Wire *state_onehot = new RTLIL::Wire;
+       state_onehot->name = NEW_ID;
+       state_onehot->width = fsm_data.state_table.size();
+       module->add(state_onehot);
+
+       for (size_t i = 0; i < fsm_data.state_table.size(); i++)
+       {
+               RTLIL::Const state = fsm_data.state_table[i];
+               RTLIL::SigSpec sig_a, sig_b;
+
+               for (size_t j = 0; j < state.bits.size(); j++)
+                       if (state.bits[j] == RTLIL::State::S0 || state.bits[j] == RTLIL::State::S1) {
+                               sig_a.append(RTLIL::SigSpec(state_wire, 1, j));
+                               sig_b.append(RTLIL::SigSpec(state.bits[j]));
+                       }
+               sig_a.optimize();
+               sig_b.optimize();
+
+               if (sig_b == RTLIL::SigSpec(RTLIL::State::S1))
+               {
+                       module->connections.push_back(RTLIL::SigSig(RTLIL::SigSpec(state_onehot, 1, i), sig_a));
+               }
+               else
+               {
+                       if (sig_b.as_bool() || sig_b.width != fsm_data.state_bits)
+                               encoding_is_onehot = false;
+
+                       RTLIL::Cell *eq_cell = new RTLIL::Cell;
+                       eq_cell->name = NEW_ID;
+                       eq_cell->type = "$eq";
+                       eq_cell->connections["\\A"] = sig_a;
+                       eq_cell->connections["\\B"] = sig_b;
+                       eq_cell->connections["\\Y"] = RTLIL::SigSpec(state_onehot, 1, i);
+                       eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
+                       eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(false);
+                       eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig_a.width);
+                       eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(sig_b.width);
+                       eq_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+                       module->add(eq_cell);
+               }
+       }
+
+       // generate next_state signal
+
+       RTLIL::Wire *next_state_onehot = new RTLIL::Wire;
+       next_state_onehot->name = NEW_ID;
+       next_state_onehot->width = fsm_data.state_table.size();
+       module->add(next_state_onehot);
+
+       for (size_t i = 0; i < fsm_data.state_table.size(); i++)
+       {
+               std::map<RTLIL::Const, std::set<int>> pattern_cache;
+               std::set<int> fullstate_cache;
+
+               for (size_t j = 0; j < fsm_data.state_table.size(); j++)
+                       fullstate_cache.insert(j);
+
+               for (auto &tr : fsm_data.transition_table) {
+                       if (tr.state_out == int(i))
+                               pattern_cache[tr.ctrl_in].insert(tr.state_in);
+                       else
+                               fullstate_cache.erase(tr.state_in);
+               }
+
+               implement_pattern_cache(module, pattern_cache, fullstate_cache, fsm_data.state_table.size(), state_onehot, ctrl_in, RTLIL::SigSpec(next_state_onehot, 1, i));
+       }
+
+       if (encoding_is_onehot)
+       {
+               for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
+                       RTLIL::Const state = fsm_data.state_table[i];
+                       int bit_idx = -1;
+                       for (size_t j = 0; j < state.bits.size(); j++)
+                               if (state.bits[j] == RTLIL::State::S1)
+                                       bit_idx = j;
+                       if (bit_idx >= 0)
+                               module->connections.push_back(RTLIL::SigSig(RTLIL::SigSpec(next_state_wire, 1, bit_idx), RTLIL::SigSpec(next_state_onehot, 1, i)));
+               }
+       }
+       else
+       {
+               RTLIL::SigSpec sig_a, sig_b, sig_s;
+               int reset_state = fsm_data.reset_state;
+               if (reset_state < 0)
+                       reset_state = 0;
+
+               for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
+                       RTLIL::Const state = fsm_data.state_table[i];
+                       if (int(i) == fsm_data.reset_state) {
+                               sig_a = RTLIL::SigSpec(state);
+                       } else {
+                               sig_b.append(RTLIL::SigSpec(state));
+                               sig_s.append(RTLIL::SigSpec(next_state_onehot, 1, i));
+                       }
+               }
+
+               RTLIL::Cell *mux_cell = new RTLIL::Cell;
+               mux_cell->name = NEW_ID;
+               mux_cell->type = "$safe_pmux";
+               mux_cell->connections["\\A"] = sig_a;
+               mux_cell->connections["\\B"] = sig_b;
+               mux_cell->connections["\\S"] = sig_s;
+               mux_cell->connections["\\Y"] = RTLIL::SigSpec(next_state_wire);
+               mux_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_a.width);
+               mux_cell->parameters["\\S_WIDTH"] = RTLIL::Const(sig_s.width);
+               module->add(mux_cell);
+       }
+
+       // Generate ctrl_out signal
+
+       RTLIL::Wire *ctrl_out_wire = new RTLIL::Wire;
+       ctrl_out_wire->name = NEW_ID;
+       ctrl_out_wire->width = fsm_data.num_outputs;
+       module->add(ctrl_out_wire);
+
+       for (int i = 0; i < fsm_data.num_outputs; i++)
+       {
+               std::map<RTLIL::Const, std::set<int>> pattern_cache;
+               std::set<int> fullstate_cache;
+
+               for (size_t j = 0; j < fsm_data.state_table.size(); j++)
+                       fullstate_cache.insert(j);
+
+               for (auto &tr : fsm_data.transition_table) {
+                       if (tr.ctrl_out.bits[i] == RTLIL::State::S1)
+                               pattern_cache[tr.ctrl_in].insert(tr.state_in);
+                       else
+                               fullstate_cache.erase(tr.state_in);
+               }
+
+               implement_pattern_cache(module, pattern_cache, fullstate_cache, fsm_data.state_table.size(), state_onehot, ctrl_in, ctrl_out.extract(i, 1));
+       }
+
+       // Remove FSM cell
+
+       module->cells.erase(fsm_cell->name);
+       delete fsm_cell;
+}
+
+struct FsmMapPass : public Pass {
+       FsmMapPass() : Pass("fsm_map") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing FSM_MAP pass (simple optimizations of FSMs).\n");
+               extra_args(args, 1, design);
+
+               for (auto &mod_it : design->modules) {
+                       std::vector<RTLIL::Cell*> fsm_cells;
+                       for (auto &cell_it : mod_it.second->cells)
+                               if (cell_it.second->type == "$fsm")
+                                       fsm_cells.push_back(cell_it.second);
+                       for (auto cell : fsm_cells)
+                                       map_fsm(cell, mod_it.second);
+               }
+       }
+} FsmMapPass;
diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc
new file mode 100644 (file)
index 0000000..8ba9679
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ *  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 "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/consteval.h"
+#include "kernel/celltypes.h"
+#include "fsmdata.h"
+#include <string.h>
+
+struct FsmOpt
+{
+       FsmData fsm_data;
+       RTLIL::Cell *cell;
+       RTLIL::Module *module;
+       
+       bool signal_is_unused(RTLIL::SigSpec sig)
+       {
+               assert(sig.width == 1);
+               sig.optimize();
+
+               RTLIL::Wire *wire = sig.chunks[0].wire;
+               int bit = sig.chunks[0].offset;
+
+               if (!wire || wire->attributes.count("\\unused_bits") == 0)
+                       return false;
+               
+               char *str = strdup(wire->attributes["\\unused_bits"].str.c_str());
+               for (char *tok = strtok(str, " "); tok != NULL; tok = strtok(NULL, " ")) {
+                       if (tok[0] && bit == atoi(tok))
+                               return true;
+               }
+               free(str);
+
+               return false;
+       }
+
+       void opt_const_and_unused_inputs()
+       {
+               RTLIL::SigSpec ctrl_in = cell->connections["\\CTRL_IN"];
+               std::vector<bool> ctrl_in_used(ctrl_in.width);
+
+               std::vector<FsmData::transition_t> new_transition_table;
+               for (auto &tr : fsm_data.transition_table) {
+                       for (int i = 0; i < ctrl_in.width; i++) {
+                               RTLIL::SigSpec ctrl_bit = ctrl_in.extract(i, 1);
+                               if (ctrl_bit.is_fully_const()) {
+                                       if (tr.ctrl_in.bits[i] <= RTLIL::State::S1 && RTLIL::SigSpec(tr.ctrl_in.bits[i]) != ctrl_bit)
+                                               goto delete_this_transition;
+                                       continue;
+                               }
+                               if (tr.ctrl_in.bits[i] <= RTLIL::State::S1)
+                                       ctrl_in_used[i] = true;
+                       }
+                       new_transition_table.push_back(tr);
+               delete_this_transition:;
+               }
+
+               for (int i = int(ctrl_in_used.size())-1; i >= 0; i--) {
+                       if (!ctrl_in_used[i]) {
+                               log("  Removing unused input signal %s.\n", log_signal(cell->connections["\\CTRL_IN"].extract(i, 1)));
+                               for (auto &tr : new_transition_table) {
+                                       RTLIL::SigSpec tmp(tr.ctrl_in);
+                                       tmp.remove(i, 1);
+                                       tr.ctrl_in = tmp.as_const();
+                               }
+                               cell->connections["\\CTRL_IN"].remove(i, 1);
+                               fsm_data.num_inputs--;
+                       }
+               }
+
+               fsm_data.transition_table.swap(new_transition_table);
+               new_transition_table.clear();
+       }
+
+       void opt_unused_outputs()
+       {
+               for (int i = 0; i < fsm_data.num_outputs; i++) {
+                       RTLIL::SigSpec sig = cell->connections["\\CTRL_OUT"].extract(i, 1);
+                       if (signal_is_unused(sig)) {
+                               log("  Removing unused output signal %s.\n", log_signal(sig));
+                               cell->connections["\\CTRL_OUT"].remove(i, 1);
+                               for (auto &tr : fsm_data.transition_table) {
+                                       RTLIL::SigSpec tmp(tr.ctrl_out);
+                                       tmp.remove(i, 1);
+                                       tr.ctrl_out = tmp.as_const();
+                               }
+                               fsm_data.num_outputs--;
+                               i--;
+                       }
+               }
+       }
+
+       void opt_alias_inputs()
+       {
+               RTLIL::SigSpec &ctrl_in = cell->connections["\\CTRL_IN"];
+
+               for (int i = 0; i < ctrl_in.width; i++)
+               for (int j = i+1; j < ctrl_in.width; j++)
+                       if (ctrl_in.extract(i, 1) == ctrl_in.extract(j, 1))
+                       {
+                               log("  Optimize handling of signal %s that is connected to inputs %d and %d.\n", log_signal(ctrl_in.extract(i, 1)), i, j);
+                               std::vector<FsmData::transition_t> new_transition_table;
+
+                               for (auto tr : fsm_data.transition_table)
+                               {
+                                       RTLIL::State &si = tr.ctrl_in.bits[i];
+                                       RTLIL::State &sj = tr.ctrl_in.bits[j];
+
+                                       if (si > RTLIL::State::S1)
+                                               si = sj;
+                                       else if (sj > RTLIL::State::S1)
+                                               sj = si;
+
+                                       if (si == sj) {
+                                               RTLIL::SigSpec tmp(tr.ctrl_in);
+                                               tmp.remove(j, 1);
+                                               tr.ctrl_in = tmp.as_const();
+                                               new_transition_table.push_back(tr);
+                                       }
+                               }
+
+                               ctrl_in.remove(j--, 1);
+                               fsm_data.num_inputs--;
+
+                               fsm_data.transition_table.swap(new_transition_table);
+                               new_transition_table.clear();
+                       }
+       }
+
+       void opt_feedback_inputs()
+       {
+               RTLIL::SigSpec &ctrl_in = cell->connections["\\CTRL_IN"];
+               RTLIL::SigSpec &ctrl_out = cell->connections["\\CTRL_OUT"];
+
+               for (int j = 0; j < ctrl_out.width; j++)
+               for (int i = 0; i < ctrl_in.width; i++)
+                       if (ctrl_in.extract(i, 1) == ctrl_out.extract(j, 1))
+                       {
+                               log("  Optimize handling of signal %s that is connected to input %d and output %d.\n", log_signal(ctrl_in.extract(i, 1)), i, j);
+                               std::vector<FsmData::transition_t> new_transition_table;
+
+                               for (auto tr : fsm_data.transition_table)
+                               {
+                                       RTLIL::State &si = tr.ctrl_in.bits[i];
+                                       RTLIL::State &sj = tr.ctrl_out.bits[j];
+
+                                       if (si > RTLIL::State::S1 || si == sj) {
+                                               RTLIL::SigSpec tmp(tr.ctrl_in);
+                                               tmp.remove(i, 1);
+                                               tr.ctrl_in = tmp.as_const();
+                                               new_transition_table.push_back(tr);
+                                       }
+                               }
+
+                               ctrl_in.remove(i--, 1);
+                               fsm_data.num_inputs--;
+
+                               fsm_data.transition_table.swap(new_transition_table);
+                               new_transition_table.clear();
+                       }
+       }
+
+       void opt_find_dont_care_worker(std::set<RTLIL::Const> &set, int bit, FsmData::transition_t &tr, bool &did_something)
+       {
+               std::set<RTLIL::Const> new_set;
+
+               for (auto &pattern : set)
+               {
+                       if (pattern.bits[bit] > RTLIL::State::S1) {
+                               new_set.insert(pattern);
+                               continue;
+                       }
+
+                       RTLIL::Const other_pattern = pattern;
+
+                       if (pattern.bits[bit] == RTLIL::State::S1)
+                               other_pattern.bits[bit] = RTLIL::State::S0;
+                       else
+                               other_pattern.bits[bit] = RTLIL::State::S1;
+
+                       if (set.count(other_pattern) > 0) {
+                               log("  Merging pattern %s and %s from group (%d %d %s).\n", log_signal(pattern), log_signal(other_pattern),
+                                               tr.state_in, tr.state_out, log_signal(tr.ctrl_out));
+                               other_pattern.bits[bit] = RTLIL::State::Sa;
+                               new_set.insert(other_pattern);
+                               did_something = true;
+                               continue;
+                       }
+
+                       new_set.insert(pattern);
+               }
+
+               set.swap(new_set);
+       }
+
+       void opt_find_dont_care()
+       {
+               typedef std::pair<std::pair<int, int>, RTLIL::Const> group_t;
+               std::map<group_t, std::set<RTLIL::Const>> transitions_by_group;
+
+               for (auto &tr : fsm_data.transition_table) {
+                       group_t group(std::pair<int, int>(tr.state_in, tr.state_out), tr.ctrl_out);
+                       transitions_by_group[group].insert(tr.ctrl_in);
+               }
+
+               fsm_data.transition_table.clear();
+               for (auto &it : transitions_by_group)
+               {
+                       FsmData::transition_t tr;
+                       tr.state_in = it.first.first.first;
+                       tr.state_out = it.first.first.second;
+                       tr.ctrl_out = it.first.second;
+
+                       bool did_something = true;
+                       while (did_something) {
+                               did_something = false;
+                               for (int i = 0; i < fsm_data.num_inputs; i++)
+                                       opt_find_dont_care_worker(it.second, i, tr, did_something);
+                       }
+
+                       for (auto &ci : it.second) {
+                               tr.ctrl_in = ci;
+                               fsm_data.transition_table.push_back(tr);
+                       }
+               }
+       }
+
+       FsmOpt(RTLIL::Cell *cell, RTLIL::Module *module)
+       {
+               log("Optimizing FSM `%s' from module `%s'.\n", cell->name.c_str(), module->name.c_str());
+
+               fsm_data.copy_from_cell(cell);
+               this->cell = cell;
+               this->module = module;
+
+               opt_unused_outputs();
+
+               opt_alias_inputs();
+               opt_feedback_inputs();
+               opt_find_dont_care();
+
+               opt_const_and_unused_inputs();
+
+               fsm_data.copy_to_cell(cell);
+       }
+};
+
+void FsmData::optimize_fsm(RTLIL::Cell *cell, RTLIL::Module *module)
+{
+       FsmOpt fsmopt(cell, module);
+}
+
+struct FsmOptPass : public Pass {
+       FsmOptPass() : Pass("fsm_opt") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing FSM_OPT pass (simple optimizations of FSMs).\n");
+               extra_args(args, 1, design);
+
+               for (auto &mod_it : design->modules)
+               for (auto &cell_it : mod_it.second->cells) {
+                       if (cell_it.second->type == "$fsm")
+                               FsmData::optimize_fsm(cell_it.second, mod_it.second);
+               }
+       }
+} FsmOptPass;
diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc
new file mode 100644 (file)
index 0000000..5e258f2
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ *  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 "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/consteval.h"
+#include "kernel/celltypes.h"
+#include "fsmdata.h"
+#include <string.h>
+
+static void fm_set_fsm_print(RTLIL::Cell *cell, RTLIL::Module *module, FsmData &fsm_data, const char *prefix, FILE *f)
+{
+       fprintf(f, "set_fsm_state_vector {");
+       for (int i = fsm_data.state_bits-1; i >= 0; i--)
+               fprintf(f, " %s_reg[%d]", cell->parameters["\\NAME"].str[0] == '\\' ?
+                               cell->parameters["\\NAME"].str.substr(1).c_str() : cell->parameters["\\NAME"].str.c_str(), i);
+       fprintf(f, " } -name {%s_%s} {%s:/WORK/%s}\n",
+                       prefix, RTLIL::unescape_id(cell->parameters["\\NAME"].str).c_str(),
+                       prefix, RTLIL::unescape_id(module->name).c_str());
+
+       fprintf(f, "set_fsm_encoding {");
+       for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
+               fprintf(f, " s%zd=2#", i);
+               for (int j = int(fsm_data.state_table[i].bits.size())-1; j >= 0; j--)
+                       fprintf(f, "%c", fsm_data.state_table[i].bits[j] == RTLIL::State::S1 ? '1' : '0');
+       }
+       fprintf(f, " } -name {%s_%s} {%s:/WORK/%s}\n",
+                       prefix, RTLIL::unescape_id(cell->parameters["\\NAME"].str).c_str(),
+                       prefix, RTLIL::unescape_id(module->name).c_str());
+}
+
+static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fsm_file)
+{
+       FsmData fsm_data;
+       fsm_data.copy_from_cell(cell);
+
+       log("Recoding FSM `%s' from module `%s':\n", cell->name.c_str(), module->name.c_str());
+
+       if (fm_set_fsm_file != NULL)
+               fm_set_fsm_print(cell, module, fsm_data, "r", fm_set_fsm_file);
+
+       fsm_data.state_bits = fsm_data.state_table.size();
+       if (fsm_data.reset_state >= 0)
+               fsm_data.state_bits--;
+
+       int bit_pos = 0;
+       for (size_t i = 0; i < fsm_data.state_table.size(); i++)
+       {
+               RTLIL::Const new_code;
+               if (int(i) == fsm_data.reset_state)
+                       new_code = RTLIL::Const(RTLIL::State::S0, fsm_data.state_bits);
+               else {
+                       RTLIL::Const state_code(RTLIL::State::Sa, fsm_data.state_bits);
+                       state_code.bits[bit_pos++] = RTLIL::State::S1;
+                       new_code = state_code;
+               }
+
+               log("  %s -> %s\n", fsm_data.state_table[i].as_string().c_str(), new_code.as_string().c_str());
+               fsm_data.state_table[i] = new_code;
+       }
+
+       if (fm_set_fsm_file != NULL)
+               fm_set_fsm_print(cell, module, fsm_data, "i", fm_set_fsm_file);
+
+       fsm_data.copy_to_cell(cell);
+}
+
+struct FsmRecodePass : public Pass {
+       FsmRecodePass() : Pass("fsm_recode") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               FILE *fm_set_fsm_file = NULL;
+
+               log_header("Executing FSM_RECODE pass (re-assigning FSM state encoding).\n");
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       std::string arg = args[argidx];
+                       if (arg == "-fm_set_fsm_file" && argidx+1 < args.size() && fm_set_fsm_file == NULL) {
+                               fm_set_fsm_file = fopen(args[++argidx].c_str(), "w");
+                               if (fm_set_fsm_file == NULL)
+                                       log_error("Can't open fm_set_fsm_file `%s' for writing: %s\n", args[argidx].c_str(), strerror(errno));
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               for (auto &mod_it : design->modules)
+               for (auto &cell_it : mod_it.second->cells)
+                       if (cell_it.second->type == "$fsm")
+                               fsm_recode(cell_it.second, mod_it.second, fm_set_fsm_file);
+
+               if (fm_set_fsm_file != NULL)
+                       fclose(fm_set_fsm_file);
+       }
+} FsmRecodePass;
diff --git a/passes/fsm/fsmdata.h b/passes/fsm/fsmdata.h
new file mode 100644 (file)
index 0000000..f43b25f
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ *  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 FSMDATA_H
+#define FSMDATA_H
+
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+struct FsmData
+{
+       int num_inputs, num_outputs, state_bits, reset_state;
+       struct transition_t { int state_in, state_out; RTLIL::Const ctrl_in, ctrl_out; };
+       std::vector<transition_t> transition_table;
+       std::vector<RTLIL::Const> state_table;
+
+       void copy_to_cell(RTLIL::Cell *cell)
+       {
+               cell->parameters["\\CTRL_IN_WIDTH"] = RTLIL::Const(num_inputs);
+               cell->parameters["\\CTRL_OUT_WIDTH"] = RTLIL::Const(num_outputs);
+
+               int state_num_log2 = 0;
+               for (int i = state_table.size(); i > 0; i = i >> 1)
+                       state_num_log2++;
+               state_num_log2 = std::max(state_num_log2, 1);
+
+               cell->parameters["\\STATE_BITS"] = RTLIL::Const(state_bits);
+               cell->parameters["\\STATE_NUM"] = RTLIL::Const(state_table.size());
+               cell->parameters["\\STATE_NUM_LOG2"] = RTLIL::Const(state_num_log2);
+               cell->parameters["\\STATE_RST"] = RTLIL::Const(reset_state);
+               cell->parameters["\\STATE_TABLE"] = RTLIL::Const();
+
+               for (int i = 0; i < int(state_table.size()); i++) {
+                       std::vector<RTLIL::State> &bits_table = cell->parameters["\\STATE_TABLE"].bits;
+                       std::vector<RTLIL::State> &bits_state = state_table[i].bits;
+                       bits_table.insert(bits_table.end(), bits_state.begin(), bits_state.end());
+               }
+
+               cell->parameters["\\TRANS_NUM"] = RTLIL::Const(transition_table.size());
+               cell->parameters["\\TRANS_TABLE"] = RTLIL::Const();
+               for (int i = 0; i < int(transition_table.size()); i++)
+               {
+                       std::vector<RTLIL::State> &bits_table = cell->parameters["\\TRANS_TABLE"].bits;
+                       transition_t &tr = transition_table[i];
+
+                       RTLIL::Const const_state_in = RTLIL::Const(tr.state_in, state_num_log2);
+                       RTLIL::Const const_state_out = RTLIL::Const(tr.state_out, state_num_log2);
+                       std::vector<RTLIL::State> &bits_state_in = const_state_in.bits;
+                       std::vector<RTLIL::State> &bits_state_out = const_state_out.bits;
+
+                       std::vector<RTLIL::State> &bits_ctrl_in = tr.ctrl_in.bits;
+                       std::vector<RTLIL::State> &bits_ctrl_out = tr.ctrl_out.bits;
+
+                       // append lsb first
+                       bits_table.insert(bits_table.end(), bits_ctrl_out.begin(), bits_ctrl_out.end());
+                       bits_table.insert(bits_table.end(), bits_state_out.begin(), bits_state_out.end());
+                       bits_table.insert(bits_table.end(), bits_ctrl_in.begin(), bits_ctrl_in.end());
+                       bits_table.insert(bits_table.end(), bits_state_in.begin(), bits_state_in.end());
+               }
+       }
+
+       void copy_from_cell(RTLIL::Cell *cell)
+       {
+               num_inputs = cell->parameters["\\CTRL_IN_WIDTH"].as_int();
+               num_outputs = cell->parameters["\\CTRL_OUT_WIDTH"].as_int();
+
+               state_bits = cell->parameters["\\STATE_BITS"].as_int();
+               reset_state = cell->parameters["\\STATE_RST"].as_int();
+
+               int state_num = cell->parameters["\\STATE_NUM"].as_int();
+               int state_num_log2 = cell->parameters["\\STATE_NUM_LOG2"].as_int();
+               int trans_num = cell->parameters["\\TRANS_NUM"].as_int();
+
+               if (reset_state < 0 || reset_state >= state_num)
+                       reset_state = -1;
+
+               RTLIL::Const state_table = cell->parameters["\\STATE_TABLE"];
+               RTLIL::Const trans_table = cell->parameters["\\TRANS_TABLE"];
+
+               for (int i = 0; i < state_num; i++) {
+                       RTLIL::Const state_code;
+                       int off_begin = i*state_bits, off_end = off_begin + state_bits;
+                       state_code.bits.insert(state_code.bits.begin(), state_table.bits.begin()+off_begin, state_table.bits.begin()+off_end);
+                       this->state_table.push_back(state_code);
+               }
+
+               for (int i = 0; i < trans_num; i++)
+               {
+                       auto off_ctrl_out = trans_table.bits.begin() + i*(num_inputs+num_outputs+2*state_num_log2);
+                       auto off_state_out = off_ctrl_out + num_outputs;
+                       auto off_ctrl_in = off_state_out + state_num_log2;
+                       auto off_state_in = off_ctrl_in + num_inputs;
+                       auto off_end = off_state_in + state_num_log2;
+
+                       RTLIL::Const state_in, state_out, ctrl_in, ctrl_out;
+                       ctrl_out.bits.insert(state_in.bits.begin(), off_ctrl_out, off_state_out);
+                       state_out.bits.insert(state_out.bits.begin(), off_state_out, off_ctrl_in);
+                       ctrl_in.bits.insert(ctrl_in.bits.begin(), off_ctrl_in, off_state_in);
+                       state_in.bits.insert(state_in.bits.begin(), off_state_in, off_end);
+
+                       transition_t tr;
+                       tr.state_in = state_in.as_int();
+                       tr.state_out = state_out.as_int();
+                       tr.ctrl_in = ctrl_in;
+                       tr.ctrl_out = ctrl_out;
+
+                       if (tr.state_in < 0 || tr.state_in >= state_num)
+                               tr.state_in = -1;
+                       if (tr.state_out < 0 || tr.state_out >= state_num)
+                               tr.state_out = -1;
+
+                       transition_table.push_back(tr);
+               }
+       }
+
+       void log_info(RTLIL::Cell *cell)
+       {
+               log("-------------------------------------\n");
+               log("\n");
+               log("  Information on FSM %s (%s):\n", cell->name.c_str(), cell->parameters["\\NAME"].str.c_str());
+               log("\n");
+               log("  Number of input signals:  %3d\n", num_inputs);
+               log("  Number of output signals: %3d\n", num_outputs);
+               log("  Number of state bits:     %3d\n", state_bits);
+
+               log("\n");
+               log("  Input signals:\n");
+               RTLIL::SigSpec sig_in = cell->connections["\\CTRL_IN"];
+               sig_in.expand();
+               for (size_t i = 0; i < sig_in.chunks.size(); i++)
+                       log("  %3zd: %s\n", i, log_signal(sig_in.chunks[i]));
+
+               log("\n");
+               log("  Output signals:\n");
+               RTLIL::SigSpec sig_out = cell->connections["\\CTRL_OUT"];
+               sig_out.expand();
+               for (size_t i = 0; i < sig_out.chunks.size(); i++)
+                       log("  %3zd: %s\n", i, log_signal(sig_out.chunks[i]));
+
+               log("\n");
+               log("  State encoding:\n");
+               for (size_t i = 0; i < state_table.size(); i++)
+                       log("  %3zd: %10s%s\n", i, log_signal(state_table[i], false),
+                                       int(i) == reset_state ? "  <RESET STATE>" : "");
+
+               log("\n");
+               log("  Transition Table (state_in, ctrl_in, state_out, ctrl_out):\n");
+               for (size_t i = 0; i < transition_table.size(); i++) {
+                       transition_t &tr = transition_table[i];
+                       log("  %5zd: %5d %s   -> %5d %s\n", i, tr.state_in, log_signal(tr.ctrl_in), tr.state_out, log_signal(tr.ctrl_out));
+               }
+
+               log("\n");
+               log("-------------------------------------\n");
+       }
+
+       // implemented in fsm_opt.cc
+       static void optimize_fsm(RTLIL::Cell *cell, RTLIL::Module *module);
+};
+
+#endif
diff --git a/passes/hierarchy/Makefile.inc b/passes/hierarchy/Makefile.inc
new file mode 100644 (file)
index 0000000..37cc287
--- /dev/null
@@ -0,0 +1,3 @@
+
+OBJS += passes/hierarchy/hierarchy.o
+
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
new file mode 100644 (file)
index 0000000..c8cd77a
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ *  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>
+#include <set>
+
+static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check)
+{
+       bool did_something = false;
+
+       for (auto &cell_it : module->cells) {
+               RTLIL::Cell *cell = cell_it.second;
+               if (design->modules.count(cell->type) == 0) {
+                       if (flag_check && cell->type[0] != '$')
+                               log_error("Module `%s' referenced in module `%s' in cell `%s' is not part of the design.\n",
+                                               cell->type.c_str(), module->name.c_str(), cell->name.c_str());
+                       continue;
+               }
+               if (cell->parameters.size() == 0)
+                       continue;
+               RTLIL::Module *mod = design->modules[cell->type];
+               cell->type = mod->derive(design, cell->parameters);
+               cell->parameters.clear();
+       }
+
+       if (did_something)
+               return did_something;
+
+       std::map<RTLIL::SigSpec, int> auto_wires;
+
+       for (auto &wire_it : module->wires) {
+               if (wire_it.second->auto_width)
+                       auto_wires[RTLIL::SigSpec(wire_it.second)] = -1;
+       }
+
+       for (auto &cell_it : module->cells)
+       for (auto &conn : cell_it.second->connections)
+       for (auto &awit : auto_wires) {
+               if (awit.second >= 0 || conn.second != awit.first)
+                       continue;
+               if (design->modules.count(cell_it.second->type) == 0) {
+                       log("WARNING: Module `%s' used in auto-delaration of the wire `%s.%s' cannot be found.\n",
+                                       cell_it.second->type.c_str(), module->name.c_str(), log_signal(awit.first));
+                       continue;
+               }
+               RTLIL::Module *mod = design->modules[cell_it.second->type];
+               RTLIL::Wire *wire = NULL;
+               if (mod->wires.count(conn.first) == 0) {
+                       for (auto &wire_it : mod->wires) {
+                               if (wire_it.second->port_id == 0)
+                                       continue;
+                               char buffer[100];
+                               snprintf(buffer, 100, "$%d", wire_it.second->port_id);
+                               if (buffer == conn.first) {
+                                       wire = wire_it.second;
+                                       break;
+                               }
+                       }
+               } else
+                       wire = mod->wires[conn.first];
+               if (!wire || wire->port_id == 0)
+                       log_error("No port `%s' found in `%s' but used by instanciation in `%s'!\n",
+                                       conn.first.c_str(), mod->name.c_str(), module->name.c_str());
+               if (wire->auto_width)
+                       log_error("Signal `%s' found in `%s' and used by instanciation in `%s' for an auto wire is an auto-wire itself!\n",
+                                       log_signal(awit.first), mod->name.c_str(), module->name.c_str());
+               awit.second = wire->width;
+       }
+
+       std::map<RTLIL::IdString, int> auto_sizes;
+       for (auto &awit : auto_wires) {
+               if (awit.second < 0)
+                       log("Can't further resolve auto-wire `%s.%s' (width %d) using cell ports.\n",
+                                       module->name.c_str(), awit.first.chunks[0].wire->name.c_str(),
+                                       awit.first.chunks[0].wire->width);
+               else
+                       auto_sizes[awit.first.chunks[0].wire->name] = awit.second;
+       }
+
+       if (auto_sizes.size() > 0) {
+               module->update_auto_wires(auto_sizes);
+               log_header("Continuing EXPAND pass.\n");
+               did_something = true;
+       }
+
+       return did_something;
+}
+
+static void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTLIL::Module *mod, bool is_top = false)
+{
+       if (used.count(mod) > 0)
+               return;
+
+       log("%s module: %s\n", is_top ? "Top" : "Used", mod->name.c_str());
+       used.insert(mod);
+
+       for (auto &it : mod->cells) {
+               if (design->modules.count(it.second->type) > 0)
+                       hierarchy_worker(design, used, design->modules[it.second->type]);
+       }
+}
+
+static void hierarchy(RTLIL::Design *design, RTLIL::Module *top)
+{
+       std::set<RTLIL::Module*> used;
+       hierarchy_worker(design, used, top, true);
+
+       std::vector<RTLIL::Module*> del_modules;
+       for (auto &it : design->modules)
+               if (used.count(it.second) == 0)
+                       del_modules.push_back(it.second);
+
+       for (auto mod : del_modules) {
+               log("Removing unused module `%s'.\n", mod->name.c_str());
+               design->modules.erase(mod->name);
+               delete mod;
+       }
+
+       log("Removed %zd unused modules.\n", del_modules.size());
+}
+
+struct HierarchyPass : public Pass {
+       HierarchyPass() : Pass("hierarchy") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing HIERARCHY pass (removing modules outside design hierarchy).\n");
+
+               bool flag_check = false;
+               RTLIL::Module *top_mod = NULL;
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++)
+               {
+                       if (args[argidx] == "-check") {
+                               flag_check = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-top") {
+                               if (++argidx >= args.size())
+                                       log_cmd_error("Option -top requires an additional argument!\n");
+                               if (args[argidx][0] != '$' && args[argidx][0] != '\\')
+                                       top_mod = design->modules.count("\\" + args[argidx]) > 0 ? design->modules["\\" + args[argidx]] : NULL;
+                               else
+                                       top_mod = design->modules.count(args[argidx]) > 0 ? design->modules[args[argidx]] : NULL;
+                               if (top_mod == NULL)
+                                       log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               if (top_mod != NULL)
+                       hierarchy(design, top_mod);
+
+               bool did_something = true;
+               while (did_something) {
+                       did_something = false;
+                       std::vector<std::string> modnames;
+                       modnames.reserve(design->modules.size());
+                       for (auto &mod_it : design->modules)
+                               modnames.push_back(mod_it.first);
+                       for (auto &modname : modnames) {
+                               if (design->modules.count(modname) == 0)
+                                       continue;
+                               if (expand_module(design, design->modules[modname], flag_check))
+                                       did_something = true;
+                       }
+               }
+
+               if (top_mod != NULL)
+                       hierarchy(design, top_mod);
+       }
+} HierarchyPass;
diff --git a/passes/memory/Makefile.inc b/passes/memory/Makefile.inc
new file mode 100644 (file)
index 0000000..cffdefe
--- /dev/null
@@ -0,0 +1,6 @@
+
+OBJS += passes/memory/memory.o
+OBJS += passes/memory/memory_dff.o
+OBJS += passes/memory/memory_collect.o
+OBJS += passes/memory/memory_map.o
+
diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc
new file mode 100644 (file)
index 0000000..c5533b6
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  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>
+
+struct MemoryPass : public Pass {
+       MemoryPass() : Pass("memory") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing MEMORY pass.\n");
+               log_push();
+
+               extra_args(args, 1, design);
+               Pass::call(design, "memory_dff");
+               Pass::call(design, "memory_collect");
+               Pass::call(design, "memory_map");
+
+               log_pop();
+       }
+} MemoryPass;
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
new file mode 100644 (file)
index 0000000..b89b976
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ *  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 <sstream>
+#include <stdlib.h>
+#include <assert.h>
+
+static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
+{
+       log("Collecting $memrd and $memwr for memory `%s' in module `%s':\n",
+                       memory->name.c_str(), module->name.c_str());
+
+       int addr_bits = 0;
+       while ((1 << addr_bits) < memory->size)
+               addr_bits++;
+
+       int wr_ports = 0;
+       RTLIL::SigSpec sig_wr_clk;
+       RTLIL::SigSpec sig_wr_clk_enable;
+       RTLIL::SigSpec sig_wr_clk_polarity;
+       RTLIL::SigSpec sig_wr_addr;
+       RTLIL::SigSpec sig_wr_data;
+       RTLIL::SigSpec sig_wr_en;
+
+       int rd_ports = 0;
+       RTLIL::SigSpec sig_rd_clk;
+       RTLIL::SigSpec sig_rd_clk_enable;
+       RTLIL::SigSpec sig_rd_clk_polarity;
+       RTLIL::SigSpec sig_rd_addr;
+       RTLIL::SigSpec sig_rd_data;
+
+       std::vector<std::string> del_cell_ids;
+
+       for (auto &cell_it : module->cells)
+       {
+               RTLIL::Cell *cell = cell_it.second;
+
+               if (cell->type == "$memwr" && cell->parameters["\\MEMID"].str == memory->name)
+               {
+                       wr_ports++;
+                       del_cell_ids.push_back(cell->name);
+
+                       RTLIL::SigSpec clk = cell->connections["\\CLK"];
+                       RTLIL::SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]);
+                       RTLIL::SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]);
+                       RTLIL::SigSpec addr = cell->connections["\\ADDR"];
+                       RTLIL::SigSpec data = cell->connections["\\DATA"];
+                       RTLIL::SigSpec en = cell->connections["\\EN"];
+
+                       clk.extend(1, false);
+                       clk_enable.extend(1, false);
+                       clk_polarity.extend(1, false);
+                       addr.extend(addr_bits, false);
+                       data.extend(memory->width, false);
+                       en.extend(1, false);
+
+                       sig_wr_clk.append(clk);
+                       sig_wr_clk_enable.append(clk_enable);
+                       sig_wr_clk_polarity.append(clk_polarity);
+                       sig_wr_addr.append(addr);
+                       sig_wr_data.append(data);
+                       sig_wr_en.append(en);
+               }
+
+               if (cell->type == "$memrd" && cell->parameters["\\MEMID"].str == memory->name)
+               {
+                       rd_ports++;
+                       del_cell_ids.push_back(cell->name);
+
+                       RTLIL::SigSpec clk = cell->connections["\\CLK"];
+                       RTLIL::SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]);
+                       RTLIL::SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]);
+                       RTLIL::SigSpec addr = cell->connections["\\ADDR"];
+                       RTLIL::SigSpec data = cell->connections["\\DATA"];
+
+                       clk.extend(1, false);
+                       clk_enable.extend(1, false);
+                       clk_polarity.extend(1, false);
+                       addr.extend(addr_bits, false);
+                       data.extend(memory->width, false);
+
+                       sig_rd_clk.append(clk);
+                       sig_rd_clk_enable.append(clk_enable);
+                       sig_rd_clk_polarity.append(clk_polarity);
+                       sig_rd_addr.append(addr);
+                       sig_rd_data.append(data);
+               }
+       }
+
+       std::stringstream sstr;
+       sstr << "$mem$" << memory->name << "$" << (RTLIL::autoidx++);
+
+       RTLIL::Cell *mem = new RTLIL::Cell;
+       mem->name = sstr.str();
+       mem->type = "$mem";
+
+       mem->parameters["\\MEMID"] = RTLIL::Const(memory->name);
+       mem->parameters["\\WIDTH"] = RTLIL::Const(memory->width);
+       mem->parameters["\\OFFSET"] = RTLIL::Const(memory->start_offset);
+       mem->parameters["\\SIZE"] = RTLIL::Const(memory->size);
+       mem->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
+
+       sig_wr_clk_enable.optimize();
+       sig_wr_clk_polarity.optimize();
+
+       assert(sig_wr_clk.width == wr_ports);
+       assert(sig_wr_clk_enable.width == wr_ports && sig_wr_clk_enable.is_fully_const());
+       assert(sig_wr_clk_polarity.width == wr_ports && sig_wr_clk_polarity.is_fully_const());
+       assert(sig_wr_addr.width == wr_ports * addr_bits);
+       assert(sig_wr_data.width == wr_ports * memory->width);
+       assert(sig_wr_en.width == wr_ports);
+
+       mem->parameters["\\WR_PORTS"] = RTLIL::Const(wr_ports);
+       mem->parameters["\\WR_CLK_ENABLE"] = wr_ports ? sig_wr_clk_enable.chunks[0].data : RTLIL::Const(0, 0);
+       mem->parameters["\\WR_CLK_POLARITY"] = wr_ports ? sig_wr_clk_enable.chunks[0].data : RTLIL::Const(0, 0);
+
+       mem->connections["\\WR_CLK"] = sig_wr_clk;
+       mem->connections["\\WR_ADDR"] = sig_wr_addr;
+       mem->connections["\\WR_DATA"] = sig_wr_data;
+       mem->connections["\\WR_EN"] = sig_wr_en;
+
+       sig_rd_clk_enable.optimize();
+       sig_rd_clk_polarity.optimize();
+
+       assert(sig_rd_clk.width == rd_ports);
+       assert(sig_rd_clk_enable.width == rd_ports && sig_rd_clk_enable.is_fully_const());
+       assert(sig_rd_clk_polarity.width == rd_ports && sig_rd_clk_polarity.is_fully_const());
+       assert(sig_rd_addr.width == rd_ports * addr_bits);
+       assert(sig_rd_data.width == rd_ports * memory->width);
+
+       mem->parameters["\\RD_PORTS"] = RTLIL::Const(rd_ports);
+       mem->parameters["\\RD_CLK_ENABLE"] = rd_ports ? sig_rd_clk_enable.chunks[0].data : RTLIL::Const(0, 0);
+       mem->parameters["\\RD_CLK_POLARITY"] = rd_ports ? sig_rd_clk_enable.chunks[0].data : RTLIL::Const(0, 0);
+
+       mem->connections["\\RD_CLK"] = sig_rd_clk;
+       mem->connections["\\RD_ADDR"] = sig_rd_addr;
+       mem->connections["\\RD_DATA"] = sig_rd_data;
+
+       for (auto &id : del_cell_ids) {
+               delete module->cells[id];
+               module->cells.erase(id);
+       }
+       module->cells[mem->name] = mem;
+}
+
+static void handle_module(RTLIL::Module *module)
+{
+       for (auto &mem_it : module->memories) {
+               handle_memory(module, mem_it.second);
+               delete mem_it.second;
+       }
+       module->memories.clear();
+}
+
+struct MemoryCollectPass : public Pass {
+       MemoryCollectPass() : Pass("memory_collect") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+               log_header("Executing MEMORY_COLLECT pass (generating $mem cells).\n");
+               extra_args(args, 1, design);
+               for (auto &mod_it : design->modules)
+                       handle_module(mod_it.second);
+       }
+} MemoryCollectPass;
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
new file mode 100644 (file)
index 0000000..e188a7a
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ *  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 <assert.h>
+#include <sstream>
+
+static void normalize_sig(RTLIL::Module *module, RTLIL::SigSpec &sig)
+{
+       for (auto &conn : module->connections)
+               sig.replace(conn.first, conn.second);
+}
+
+static bool find_sig_before_dff(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, bool after = false)
+{
+       bool replaced_bits = false;
+       normalize_sig(module, sig);
+       sig.expand();
+
+       for (size_t i = 0; i < sig.chunks.size(); i++)
+       {
+               RTLIL::SigChunk &chunk = sig.chunks[i];
+
+               if (chunk.wire == NULL)
+                       continue;
+
+               for (auto &cell_it : module->cells)
+               {
+                       RTLIL::Cell *cell = cell_it.second;
+
+                       if (cell->type != "$dff")
+                               continue;
+
+                       if (clk != RTLIL::SigSpec(RTLIL::State::Sx)) {
+                               if (cell->connections["\\CLK"] != clk)
+                                       continue;
+                               if (cell->parameters["\\CLK_POLARITY"].as_bool() != clk_polarity)
+                                       continue;
+                       }
+
+                       RTLIL::SigSpec q_norm = cell->connections[after ? "\\D" : "\\Q"];
+                       normalize_sig(module, q_norm);
+
+                       RTLIL::SigSpec d = q_norm.extract(chunk, &cell->connections[after ? "\\Q" : "\\D"]);
+                       if (d.width != 1)
+                               continue;
+
+                       assert(d.chunks.size() == 1);
+                       chunk = d.chunks[0];
+                       clk = cell->connections["\\CLK"];
+                       clk_polarity = cell->parameters["\\CLK_POLARITY"].as_bool();
+                       replaced_bits = true;
+                       goto replaced_this_bit;
+               }
+
+               return false;
+       replaced_this_bit:;
+       }
+
+       sig.optimize();
+       return replaced_bits;
+}
+
+static void handle_wr_cell(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+       log("Checking cell `%s' in module `%s': ", cell->name.c_str(), module->name.c_str());
+
+       RTLIL::SigSpec clk = RTLIL::SigSpec(RTLIL::State::Sx);
+       bool clk_polarity = 0;
+
+       RTLIL::SigSpec sig_addr = cell->connections["\\ADDR"];
+       if (!find_sig_before_dff(module, sig_addr, clk, clk_polarity)) {
+               log("no (compatible) $dff for address input found.\n");
+               return;
+       }
+
+       RTLIL::SigSpec sig_data = cell->connections["\\DATA"];
+       if (!find_sig_before_dff(module, sig_data, clk, clk_polarity)) {
+               log("no (compatible) $dff for data input found.\n");
+               return;
+       }
+
+       RTLIL::SigSpec sig_en = cell->connections["\\EN"];
+       if (!find_sig_before_dff(module, sig_en, clk, clk_polarity)) {
+               log("no (compatible) $dff for enable input found.\n");
+               return;
+       }
+
+       cell->connections["\\CLK"] = clk;
+       cell->connections["\\ADDR"] = sig_addr;
+       cell->connections["\\DATA"] = sig_data;
+       cell->connections["\\EN"] = sig_en;
+       cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
+       cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
+       log("merged $dff to cell.\n");
+}
+
+#if 1
+static void handle_rd_cell(RTLIL::Module*, RTLIL::Cell*)
+{
+       // merging dffs into read ports isn't neccessary for memory_map.
+       // we'd loose the information if the register is on the address or
+       // data port and wouldn't get any benefits.
+}
+#else
+static void disconnect_dff(RTLIL::Module *module, RTLIL::SigSpec sig)
+{
+       normalize_sig(module, sig);
+       sig.sort_and_unify();
+
+       std::stringstream sstr;
+       sstr << "$memory_dff_disconnected$" << (RTLIL::autoidx++);
+
+       RTLIL::Wire *wire = new RTLIL::Wire;
+       wire->name = sstr.str();
+       wire->width = sig.width;
+       module->wires[wire->name] = wire;
+
+       RTLIL::SigSpec newsig(wire);
+
+       for (auto &cell_it : module->cells) {
+               RTLIL::Cell *cell = cell_it.second;
+               if (cell->type == "$dff")
+                       cell->connections["\\Q"].replace(sig, newsig);
+       }
+}
+
+static void handle_rd_cell(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+       log("Checking cell `%s' in module `%s': ", cell->name.c_str(), module->name.c_str());
+
+       bool clk_polarity = 0;
+
+       RTLIL::SigSpec clk_addr = RTLIL::SigSpec(RTLIL::State::Sx);
+       RTLIL::SigSpec sig_addr = cell->connections["\\ADDR"];
+       if (find_sig_before_dff(module, sig_addr, clk_addr, clk_polarity))
+       {
+               cell->connections["\\CLK"] = clk_addr;
+               cell->connections["\\ADDR"] = sig_addr;
+               cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
+               cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
+               log("merged address $dff to cell.\n");
+               return;
+       }
+
+       RTLIL::SigSpec clk_data = RTLIL::SigSpec(RTLIL::State::Sx);
+       RTLIL::SigSpec sig_data = cell->connections["\\DATA"];
+       if (find_sig_before_dff(module, sig_data, clk_data, clk_polarity, true))
+       {
+               disconnect_dff(module, sig_data);
+               cell->connections["\\CLK"] = clk_data;
+               cell->connections["\\DATA"] = sig_data;
+               cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
+               cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
+               log("merged data $dff to cell.\n");
+               return;
+       }
+
+       log("no (compatible) $dff found.\n");
+}
+#endif
+
+static void handle_module(RTLIL::Module *module)
+{
+       for (auto &cell_it : module->cells) {
+               if (cell_it.second->type == "$memwr" && !cell_it.second->parameters["\\CLK_ENABLE"].as_bool())
+                               handle_wr_cell(module, cell_it.second);
+               if (cell_it.second->type == "$memrd" && !cell_it.second->parameters["\\CLK_ENABLE"].as_bool())
+                               handle_rd_cell(module, cell_it.second);
+       }
+}
+
+struct MemoryDffPass : public Pass {
+       MemoryDffPass() : Pass("memory_dff") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+               log_header("Executing MEMORY_DFF pass (merging $dff cells to $memrd and $memwr).\n");
+               extra_args(args, 1, design);
+               for (auto &mod_it : design->modules)
+                       handle_module(mod_it.second);
+       }
+} MemoryDffPass;
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
new file mode 100644 (file)
index 0000000..e778308
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ *  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 <sstream>
+#include <set>
+#include <stdlib.h>
+#include <assert.h>
+
+static std::string genid(std::string name, std::string token1 = "", int i = -1, std::string token2 = "", int j = -1, std::string token3 = "", int k = -1, std::string token4 = "")
+{
+       std::stringstream sstr;
+       sstr << "$memory" << name << token1;
+       
+       if (i >= 0)
+               sstr << "[" << i << "]";
+
+       sstr << token2;
+
+       if (j >= 0)
+               sstr << "[" << j << "]";
+
+       sstr << token3;
+
+       if (k >= 0)
+               sstr << "[" << k << "]";
+
+       sstr << token4 << "$" << (RTLIL::autoidx++);
+       return sstr.str();
+}
+
+static void handle_cell(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+       std::set<int> static_ports;
+       std::map<int, RTLIL::SigSpec> static_cells_map;
+       int mem_size = cell->parameters["\\SIZE"].as_int();
+       int mem_width = cell->parameters["\\WIDTH"].as_int();
+       int mem_offset = cell->parameters["\\OFFSET"].as_int();
+       int mem_abits = cell->parameters["\\ABITS"].as_int();
+
+       // delete unused memory cell
+       if (cell->parameters["\\RD_PORTS"].as_int() == 0 && cell->parameters["\\WR_PORTS"].as_int() == 0) {
+               module->cells.erase(cell->name);
+               delete cell;
+               return;
+       }
+
+       // all write ports must share the same clock
+       RTLIL::SigSpec clocks = cell->connections["\\WR_CLK"];
+       RTLIL::Const clocks_pol = cell->parameters["\\WR_CLK_POLARITY"];
+       RTLIL::Const clocks_en = cell->parameters["\\WR_CLK_ENABLE"];
+       RTLIL::SigSpec refclock;
+       RTLIL::State refclock_pol = RTLIL::State::Sx;
+       for (int i = 0; i < clocks.width; i++) {
+               RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(i, 1);
+               if (wr_en.is_fully_const() && wr_en.as_int() == 0) {
+                       static_ports.insert(i);
+                       continue;
+               }
+               if (clocks_en.bits[i] != RTLIL::State::S1) {
+                       RTLIL::SigSpec wr_addr = cell->connections["\\WR_ADDR"].extract(i*mem_abits, mem_abits);
+                       RTLIL::SigSpec wr_data = cell->connections["\\WR_DATA"].extract(i*mem_width, mem_width);
+                       if (wr_addr.is_fully_const()) {
+                               // FIXME: Actually we should check for wr_en.is_fully_const() also and
+                               // create a $adff cell with this ports wr_en input as reset pin when wr_en
+                               // is not a simple static 1.
+                               static_cells_map[wr_addr.as_int()] = wr_data;
+                               static_ports.insert(i);
+                               continue;
+                       }
+                       log("Not mapping memory cell %s in module %s (write port %d has no clock).\n",
+                                       cell->name.c_str(), module->name.c_str(), i);
+                       return;
+               }
+               if (refclock.width == 0) {
+                       refclock = clocks.extract(i, 1);
+                       refclock_pol = clocks_pol.bits[i];
+               }
+               if (clocks.extract(i, 1) != refclock || clocks_pol.bits[i] != refclock_pol) {
+                       log("Not mapping memory cell %s in module %s (write clock %d is incompatible with other clocks).\n",
+                                       cell->name.c_str(), module->name.c_str(), i);
+                       return;
+               }
+       }
+
+       log("Mapping memory cell %s in module %s:\n", cell->name.c_str(), module->name.c_str());
+
+       std::vector<RTLIL::SigSpec> data_reg_in;
+       std::vector<RTLIL::SigSpec> data_reg_out;
+
+       int count_static = 0;
+
+       for (int i = 0; i < mem_size; i++)
+       {
+               if (static_cells_map.count(i) > 0)
+               {
+                       data_reg_in.push_back(RTLIL::SigSpec(RTLIL::State::Sz, mem_width));
+                       data_reg_out.push_back(static_cells_map[i]);
+                       count_static++;
+               }
+               else
+               {
+                       RTLIL::Cell *c = new RTLIL::Cell;
+                       c->name = genid(cell->name, "", i);
+                       c->type = "$dff";
+                       c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
+                       c->parameters["\\CLK_POLARITY"] = RTLIL::Const(clocks_pol.bits[0]);
+                       c->connections["\\CLK"] = clocks.extract(0, 1);
+                       module->cells[c->name] = c;
+
+                       RTLIL::Wire *w_in = new RTLIL::Wire;
+                       w_in->name = genid(cell->name, "", i, "$d");
+                       w_in->width = mem_width;
+                       module->wires[w_in->name] = w_in;
+                       data_reg_in.push_back(RTLIL::SigSpec(w_in));
+                       c->connections["\\D"] = data_reg_in.back();
+
+                       RTLIL::Wire *w_out = new RTLIL::Wire;
+                       w_out->name = stringf("%s[%d]", cell->parameters["\\MEMID"].str.c_str(), i);
+                       if (module->wires.count(w_out->name) > 0)
+                               w_out->name = genid(cell->name, "", i, "$q");
+                       w_out->width = mem_width;
+                       w_out->start_offset = mem_offset;
+                       module->wires[w_out->name] = w_out;
+                       data_reg_out.push_back(RTLIL::SigSpec(w_out));
+                       c->connections["\\Q"] = data_reg_out.back();
+               }
+       }
+
+       log("  created %d $dff cells and %d static cells of width %d.\n", mem_size-count_static, count_static, mem_width);
+
+       int count_dff = 0, count_mux = 0, count_wrmux = 0;
+
+       for (int i = 0; i < cell->parameters["\\RD_PORTS"].as_int(); i++)
+       {
+               RTLIL::SigSpec rd_addr = cell->connections["\\RD_ADDR"].extract(i*mem_abits, mem_abits);
+
+               std::vector<RTLIL::SigSpec> rd_signals;
+               rd_signals.push_back(cell->connections["\\RD_DATA"].extract(i*mem_width, mem_width));
+
+               if (cell->parameters["\\RD_CLK_ENABLE"].bits[i] == RTLIL::State::S1)
+               {
+#if 1
+                       RTLIL::Cell *c = new RTLIL::Cell;
+                       c->name = genid(cell->name, "$rdreg", i);
+                       c->type = "$dff";
+                       c->parameters["\\WIDTH"] = RTLIL::Const(mem_abits);
+                       c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
+                       c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1);
+                       c->connections["\\D"] = rd_addr;
+                       module->cells[c->name] = c;
+                       count_dff++;
+
+                       RTLIL::Wire *w = new RTLIL::Wire;
+                       w->name = genid(cell->name, "$rdreg", i, "$q");
+                       w->width = mem_abits;
+                       module->wires[w->name] = w;
+
+                       c->connections["\\Q"] = RTLIL::SigSpec(w);
+                       rd_addr = RTLIL::SigSpec(w);
+#else
+                       RTLIL::Cell *c = new RTLIL::Cell;
+                       c->name = genid(cell->name, "$rdreg", i);
+                       c->type = "$dff";
+                       c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
+                       c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
+                       c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1);
+                       c->connections["\\Q"] = rd_signals.back();
+                       module->cells[c->name] = c;
+                       count_dff++;
+
+                       RTLIL::Wire *w = new RTLIL::Wire;
+                       w->name = genid(cell->name, "$rdreg", i, "$d");
+                       w->width = mem_width;
+                       module->wires[w->name] = w;
+
+                       rd_signals.clear();
+                       rd_signals.push_back(RTLIL::SigSpec(w));
+                       c->connections["\\D"] = rd_signals.back();
+#endif
+               }
+
+               for (int j = 0; j < mem_abits; j++)
+               {
+                       std::vector<RTLIL::SigSpec> next_rd_signals;
+
+                       for (size_t k = 0; k < rd_signals.size(); k++)
+                       {
+                               RTLIL::Cell *c = new RTLIL::Cell;
+                               c->name = genid(cell->name, "$rdmux", i, "", j, "", k);
+                               c->type = "$mux";
+                               c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
+                               c->connections["\\Y"] = rd_signals[k];
+                               c->connections["\\S"] = rd_addr.extract(mem_abits-j-1, 1);
+                               module->cells[c->name] = c;
+                               count_mux++;
+
+                               RTLIL::Wire *w = new RTLIL::Wire;
+                               w->name = genid(cell->name, "$rdmux", i, "", j, "", k, "$a");
+                               w->width = mem_width;
+                               module->wires[w->name] = w;
+                               c->connections["\\A"] = RTLIL::SigSpec(w);
+
+                               w = new RTLIL::Wire;
+                               w->name = genid(cell->name, "$rdmux", i, "", j, "", k, "$b");
+                               w->width = mem_width;
+                               module->wires[w->name] = w;
+                               c->connections["\\B"] = RTLIL::SigSpec(w);
+
+                               next_rd_signals.push_back(c->connections["\\A"]);
+                               next_rd_signals.push_back(c->connections["\\B"]);
+                       }
+
+                       next_rd_signals.swap(rd_signals);
+               }
+
+               for (int j = 0; j < mem_size; j++)
+                       module->connections.push_back(RTLIL::SigSig(rd_signals[j], data_reg_out[j]));
+       }
+
+       log("  read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux);
+
+       for (int i = 0; i < mem_size; i++)
+       {
+               if (static_cells_map.count(i) > 0)
+                       continue;
+
+               RTLIL::SigSpec sig = data_reg_out[i];
+
+               for (int j = 0; j < cell->parameters["\\WR_PORTS"].as_int(); j++)
+               {
+                       RTLIL::SigSpec wr_addr = cell->connections["\\WR_ADDR"].extract(j*mem_abits, mem_abits);
+                       RTLIL::SigSpec wr_data = cell->connections["\\WR_DATA"].extract(j*mem_width, mem_width);
+                       RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(j, 1);
+
+                       RTLIL::Cell *c = new RTLIL::Cell;
+                       c->name = genid(cell->name, "$wreq", i, "", j);
+                       c->type = "$eq";
+                       c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
+                       c->parameters["\\B_SIGNED"] = RTLIL::Const(0);
+                       c->parameters["\\A_WIDTH"] = cell->parameters["\\ABITS"];
+                       c->parameters["\\B_WIDTH"] = cell->parameters["\\ABITS"];
+                       c->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+                       c->connections["\\A"] = RTLIL::SigSpec(i, mem_abits);
+                       c->connections["\\B"] = wr_addr;
+                       module->cells[c->name] = c;
+                       count_wrmux++;
+
+                       RTLIL::Wire *w = new RTLIL::Wire;
+                       w->name = genid(cell->name, "$wreq", i, "", j, "$y");
+                       module->wires[w->name] = w;
+                       c->connections["\\Y"] = RTLIL::SigSpec(w);
+
+                       c = new RTLIL::Cell;
+                       c->name = genid(cell->name, "$wren", i, "", j);
+                       c->type = "$and";
+                       c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
+                       c->parameters["\\B_SIGNED"] = RTLIL::Const(0);
+                       c->parameters["\\A_WIDTH"] = RTLIL::Const(1);
+                       c->parameters["\\B_WIDTH"] = RTLIL::Const(1);
+                       c->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+                       c->connections["\\A"] = RTLIL::SigSpec(w);
+                       c->connections["\\B"] = wr_en;
+                       module->cells[c->name] = c;
+
+                       w = new RTLIL::Wire;
+                       w->name = genid(cell->name, "$wren", i, "", j, "$y");
+                       module->wires[w->name] = w;
+                       c->connections["\\Y"] = RTLIL::SigSpec(w);
+
+                       c = new RTLIL::Cell;
+                       c->name = genid(cell->name, "$wrmux", i, "", j);
+                       c->type = "$mux";
+                       c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
+                       c->connections["\\A"] = sig;
+                       c->connections["\\B"] = wr_data;
+                       c->connections["\\S"] = RTLIL::SigSpec(w);
+                       module->cells[c->name] = c;
+
+                       w = new RTLIL::Wire;
+                       w->name = genid(cell->name, "$wrmux", i, "", j, "$y");
+                       w->width = mem_width;
+                       module->wires[w->name] = w;
+                       c->connections["\\Y"] = RTLIL::SigSpec(w);
+                       sig = RTLIL::SigSpec(w);
+               }
+
+               module->connections.push_back(RTLIL::SigSig(data_reg_in[i], sig));
+       }
+
+       log("  write interface: %d blocks of $eq, $and and $mux cells.\n", count_wrmux);
+
+       module->cells.erase(cell->name);
+       delete cell;
+       return;
+}
+
+static void handle_module(RTLIL::Module *module)
+{
+       std::vector<RTLIL::Cell*> cells;
+       for (auto &it : module->cells)
+               if (it.second->type == "$mem")
+                       cells.push_back(it.second);
+       for (auto cell : cells)
+               handle_cell(module, cell);
+}
+
+struct MemoryMapPass : public Pass {
+       MemoryMapPass() : Pass("memory_map") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+               log_header("Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
+               extra_args(args, 1, design);
+               for (auto &mod_it : design->modules)
+                       handle_module(mod_it.second);
+       }
+} MemoryMapPass;
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
new file mode 100644 (file)
index 0000000..3602b96
--- /dev/null
@@ -0,0 +1,9 @@
+
+OBJS += passes/opt/opt.o
+OBJS += passes/opt/opt_share.o
+OBJS += passes/opt/opt_muxtree.o
+OBJS += passes/opt/opt_reduce.o
+OBJS += passes/opt/opt_rmdff.o
+OBJS += passes/opt/opt_rmunused.o 
+OBJS += passes/opt/opt_const.o 
+
diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc
new file mode 100644 (file)
index 0000000..9e33f78
--- /dev/null
@@ -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.
+ *
+ */
+
+#include "opt_status.h"
+#include "kernel/register.h"
+#include "kernel/log.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+bool OPT_DID_SOMETHING;
+
+struct OptPass : public Pass {
+       OptPass() : Pass("opt") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing OPT pass (performing simple optimizations).\n");
+               log_push();
+
+               extra_args(args, 1, design);
+
+               log_header("Optimizing in-memory representation of design.\n");
+               design->optimize();
+
+               Pass::call(design, "opt_const");
+               Pass::call(design, "opt_share -nomux");
+               while (1) {
+                       OPT_DID_SOMETHING = false;
+                       Pass::call(design, "opt_muxtree");
+                       Pass::call(design, "opt_reduce");
+                       Pass::call(design, "opt_share");
+                       Pass::call(design, "opt_rmdff");
+                       Pass::call(design, "opt_rmunused");
+                       Pass::call(design, "opt_const");
+                       if (OPT_DID_SOMETHING == false)
+                               break;
+                       log_header("Rerunning OPT passes. (Maybe there is more to do..)\n");
+               }
+
+               log_header("Optimizing in-memory representation of design.\n");
+               design->optimize();
+
+               log_header("Finished OPT passes. (There is nothing left to do.)\n");
+               log_pop();
+       }
+} OptPass;
diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_const.cc
new file mode 100644 (file)
index 0000000..9edea67
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ *  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.
+ *
+ */
+
+#undef MUX_UNDEF_SEL_TO_UNDEF_RESULTS
+
+#include "opt_status.h"
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <set>
+
+bool did_something;
+
+void replace_cell(RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
+{
+       RTLIL::SigSpec Y = cell->connections[out_port];
+       log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
+                       cell->type.c_str(), cell->name.c_str(), info.c_str(),
+                       module->name.c_str(), log_signal(Y), log_signal(out_val));
+       OPT_DID_SOMETHING = true;
+       // ILANG_BACKEND::dump_cell(stderr, "--> ", cell);
+       module->connections.push_back(RTLIL::SigSig(Y, out_val));
+       module->cells.erase(cell->name);
+       delete cell;
+       did_something = true;
+}
+
+void replace_const_cells(RTLIL::Module *module)
+{
+       SigMap assign_map(module);
+
+       std::vector<RTLIL::Cell*> cells;
+       cells.reserve(module->cells.size());
+       for (auto &cell_it : module->cells)
+               cells.push_back(cell_it.second);
+
+       for (auto cell : cells)
+       {
+#define ACTION_DO(_p_, _s_) do { replace_cell(module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
+#define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
+
+               if (cell->type == "$_INV_") {
+                       RTLIL::SigSpec input = cell->connections["\\A"];
+                       assign_map.apply(input);
+                       if (input.match("1")) ACTION_DO_Y(0);
+                       if (input.match("0")) ACTION_DO_Y(1);
+                       if (input.match("*")) ACTION_DO_Y(x);
+               }
+
+               if (cell->type == "$_AND_") {
+                       RTLIL::SigSpec input;
+                       input.append(cell->connections["\\B"]);
+                       input.append(cell->connections["\\A"]);
+                       assign_map.apply(input);
+                       if (input.match(" 0")) ACTION_DO_Y(0);
+                       if (input.match("0 ")) ACTION_DO_Y(0);
+                       if (input.match("11")) ACTION_DO_Y(1);
+                       if (input.match(" *")) ACTION_DO_Y(x);
+                       if (input.match("* ")) ACTION_DO_Y(x);
+               }
+
+               if (cell->type == "$_OR_") {
+                       RTLIL::SigSpec input;
+                       input.append(cell->connections["\\B"]);
+                       input.append(cell->connections["\\A"]);
+                       assign_map.apply(input);
+                       if (input.match(" 1")) ACTION_DO_Y(1);
+                       if (input.match("1 ")) ACTION_DO_Y(1);
+                       if (input.match("00")) ACTION_DO_Y(0);
+                       if (input.match(" *")) ACTION_DO_Y(x);
+                       if (input.match("* ")) ACTION_DO_Y(x);
+               }
+
+               if (cell->type == "$_XOR_") {
+                       RTLIL::SigSpec input;
+                       input.append(cell->connections["\\B"]);
+                       input.append(cell->connections["\\A"]);
+                       assign_map.apply(input);
+                       if (input.match("00")) ACTION_DO_Y(0);
+                       if (input.match("01")) ACTION_DO_Y(1);
+                       if (input.match("10")) ACTION_DO_Y(1);
+                       if (input.match("11")) ACTION_DO_Y(0);
+                       if (input.match(" *")) ACTION_DO_Y(x);
+                       if (input.match("* ")) ACTION_DO_Y(x);
+               }
+
+               if (cell->type == "$_MUX_") {
+                       RTLIL::SigSpec input;
+                       input.append(cell->connections["\\S"]);
+                       input.append(cell->connections["\\B"]);
+                       input.append(cell->connections["\\A"]);
+                       assign_map.apply(input);
+                       if (input.extract(2, 1) == input.extract(1, 1))
+                               ACTION_DO("\\Y", input.extract(2, 1));
+                       if (input.match("  0")) ACTION_DO("\\Y", input.extract(2, 1));
+                       if (input.match("  1")) ACTION_DO("\\Y", input.extract(1, 1));
+#ifdef MUX_UNDEF_SEL_TO_UNDEF_RESULTS
+                       if (input.match("01 ")) ACTION_DO("\\Y", input.extract(0, 1));
+                       if (input.match("  *")) ACTION_DO_Y(x);
+#endif
+               }
+
+               if (cell->type == "$eq" || cell->type == "$ne")
+               {
+                       if (cell->parameters["\\A_WIDTH"].as_int() != cell->parameters["\\B_WIDTH"].as_int()) {
+                               int width = std::max(cell->parameters["\\A_WIDTH"].as_int(), cell->parameters["\\B_WIDTH"].as_int());
+                               cell->connections["\\A"].extend(width, cell->parameters["\\A_SIGNED"].as_bool());
+                               cell->connections["\\B"].extend(width, cell->parameters["\\B_SIGNED"].as_bool());
+                               cell->parameters["\\A_WIDTH"] = width;
+                               cell->parameters["\\B_WIDTH"] = width;
+                       }
+
+                       RTLIL::SigSpec a = cell->connections["\\A"];
+                       RTLIL::SigSpec b = cell->connections["\\B"];
+                       RTLIL::SigSpec new_a, new_b;
+                       a.expand(), b.expand();
+
+                       assert(a.chunks.size() == b.chunks.size());
+                       for (size_t i = 0; i < a.chunks.size(); i++) {
+                               if (a.chunks[i].wire == NULL && a.chunks[i].data.bits[0] > RTLIL::State::S1)
+                                       continue;
+                               if (b.chunks[i].wire == NULL && b.chunks[i].data.bits[0] > RTLIL::State::S1)
+                                       continue;
+                               new_a.append(a.chunks[i]);
+                               new_b.append(b.chunks[i]);
+                       }
+
+                       if (new_a.width != a.width) {
+                               new_a.optimize();
+                               new_b.optimize();
+                               cell->connections["\\A"] = new_a;
+                               cell->connections["\\B"] = new_b;
+                               cell->parameters["\\A_WIDTH"] = new_a.width;
+                               cell->parameters["\\B_WIDTH"] = new_b.width;
+                       }
+
+                       if (new_a.width == 0) {
+                               replace_cell(module, cell, "empty", "\\Y", RTLIL::SigSpec(cell->type == "$eq" ? RTLIL::State::S1 : RTLIL::State::S0));
+                               goto next_cell;
+                       }
+               }
+
+#define FOLD_1ARG_CELL(_t) \
+               if (cell->type == "$" #_t) { \
+                       RTLIL::SigSpec a = cell->connections["\\A"]; \
+                       assign_map.apply(a); \
+                       if (a.is_fully_const()) { \
+                               a.optimize(); \
+                               RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \
+                               RTLIL::SigSpec y(RTLIL::const_ ## _t(a.chunks[0].data, dummy_arg, \
+                                               cell->parameters["\\A_SIGNED"].as_bool(), false, \
+                                               cell->parameters["\\Y_WIDTH"].as_int())); \
+                               replace_cell(module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
+                               goto next_cell; \
+                       } \
+               }
+#define FOLD_2ARG_CELL(_t) \
+               if (cell->type == "$" #_t) { \
+                       RTLIL::SigSpec a = cell->connections["\\A"]; \
+                       RTLIL::SigSpec b = cell->connections["\\B"]; \
+                       assign_map.apply(a), assign_map.apply(b); \
+                       if (a.is_fully_const() && b.is_fully_const()) { \
+                               a.optimize(), b.optimize(); \
+                               RTLIL::SigSpec y(RTLIL::const_ ## _t(a.chunks[0].data, b.chunks[0].data, \
+                                               cell->parameters["\\A_SIGNED"].as_bool(), \
+                                               cell->parameters["\\B_SIGNED"].as_bool(), \
+                                               cell->parameters["\\Y_WIDTH"].as_int())); \
+                               replace_cell(module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
+                               goto next_cell; \
+                       } \
+               }
+
+               FOLD_1ARG_CELL(not)
+               FOLD_2ARG_CELL(and)
+               FOLD_2ARG_CELL(or)
+               FOLD_2ARG_CELL(xor)
+               FOLD_2ARG_CELL(xnor)
+
+               FOLD_1ARG_CELL(reduce_and)
+               FOLD_1ARG_CELL(reduce_or)
+               FOLD_1ARG_CELL(reduce_xor)
+               FOLD_1ARG_CELL(reduce_xnor)
+               FOLD_1ARG_CELL(reduce_bool)
+
+               FOLD_1ARG_CELL(logic_not)
+               FOLD_2ARG_CELL(logic_and)
+               FOLD_2ARG_CELL(logic_or)
+
+               FOLD_2ARG_CELL(shl)
+               FOLD_2ARG_CELL(shr)
+               FOLD_2ARG_CELL(sshl)
+               FOLD_2ARG_CELL(sshr)
+
+               FOLD_2ARG_CELL(lt)
+               FOLD_2ARG_CELL(le)
+               FOLD_2ARG_CELL(eq)
+               FOLD_2ARG_CELL(ne)
+               FOLD_2ARG_CELL(gt)
+               FOLD_2ARG_CELL(ge)
+
+               FOLD_2ARG_CELL(add)
+               FOLD_2ARG_CELL(sub)
+               FOLD_2ARG_CELL(mul)
+               FOLD_2ARG_CELL(div)
+               FOLD_2ARG_CELL(mod)
+               FOLD_2ARG_CELL(pow)
+
+               FOLD_1ARG_CELL(pos)
+               FOLD_1ARG_CELL(neg)
+
+               if (cell->type == "$mux") {
+                       RTLIL::SigSpec input = cell->connections["\\S"];
+                       assign_map.apply(input);
+                       if (input.is_fully_const())
+                               ACTION_DO("\\Y", input.as_bool() ? cell->connections["\\B"] : cell->connections["\\A"]);
+               }
+
+       next_cell:;
+#undef ACTION_DO
+#undef ACTION_DO_Y
+#undef FOLD_1ARG_CELL
+#undef FOLD_2ARG_CELL
+       }
+}
+
+struct OptConstPass : public Pass {
+       OptConstPass() : Pass("opt_const") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing OPT_CONST pass (perform const folding).\n");
+               log_push();
+
+               extra_args(args, 1, design);
+
+               for (auto &mod_it : design->modules)
+                       do {
+                               did_something = false;
+                               replace_const_cells(mod_it.second);
+                       } while (did_something);
+
+               log_pop();
+       }
+} OptConstPass;
+
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
new file mode 100644 (file)
index 0000000..d1f4e7b
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ *  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 "opt_status.h"
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include "kernel/celltypes.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <set>
+
+struct OptMuxtreeWorker
+{
+       RTLIL::Design *design;
+       RTLIL::Module *module;
+       SigMap assign_map;
+       int removed_count;
+
+       typedef std::pair<RTLIL::Wire*,int> bitDef_t;
+
+       struct bitinfo_t {
+               int num;
+               bitDef_t bit;
+               bool seen_non_mux;
+               std::vector<int> mux_users;
+               std::vector<int> mux_drivers;
+       };
+
+       std::map<bitDef_t, int> bit2num;
+       std::vector<bitinfo_t> bit2info;
+
+       struct portinfo_t {
+               std::vector<int> ctrl_sigs;
+               std::vector<int> input_sigs;
+               std::vector<int> input_muxes;
+               bool const_activated;
+               bool enabled;
+       };
+
+       struct muxinfo_t {
+               RTLIL::Cell *cell;
+               std::vector<portinfo_t> ports;
+       };
+
+       std::vector<muxinfo_t> mux2info;
+
+       OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) :
+                       design(design), module(module), assign_map(module), removed_count(0)
+       {
+               log("Running muxtree optimizier on module %s..\n", module->name.c_str());
+
+               log("  Creating internal representation of mux trees.\n");
+
+               // Populate bit2info[]:
+               //      .seen_non_mux
+               //      .mux_users
+               //      .mux_drivers
+               // Populate mux2info[].ports[]:
+               //      .ctrl_sigs
+               //      .input_sigs
+               //      .const_activated
+               for (auto &cell_it : module->cells)
+               {
+                       RTLIL::Cell *cell = cell_it.second;
+                       if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux")
+                       {
+                               RTLIL::SigSpec sig_a = cell->connections["\\A"];
+                               RTLIL::SigSpec sig_b = cell->connections["\\B"];
+                               RTLIL::SigSpec sig_s = cell->connections["\\S"];
+                               RTLIL::SigSpec sig_y = cell->connections["\\Y"];
+
+                               muxinfo_t muxinfo;
+                               muxinfo.cell = cell;
+
+                               for (int i = 0; i < sig_s.width; i++) {
+                                       RTLIL::SigSpec sig = sig_b.extract(i*sig_a.width, sig_a.width);
+                                       RTLIL::SigSpec ctrl_sig = assign_map(sig_s.extract(i, 1));
+                                       portinfo_t portinfo;
+                                       for (int idx : sig2bits(sig)) {
+                                               add_to_list(bit2info[idx].mux_users, mux2info.size());
+                                               add_to_list(portinfo.input_sigs, idx);
+                                       }
+                                       for (int idx : sig2bits(ctrl_sig))
+                                               add_to_list(portinfo.ctrl_sigs, idx);
+                                       portinfo.const_activated = ctrl_sig.is_fully_const() && ctrl_sig.as_bool();
+                                       portinfo.enabled = false;
+                                       muxinfo.ports.push_back(portinfo);
+                               }
+
+                               portinfo_t portinfo;
+                               for (int idx : sig2bits(sig_a)) {
+                                       add_to_list(bit2info[idx].mux_users, mux2info.size());
+                                       add_to_list(portinfo.input_sigs, idx);
+                               }
+                               portinfo.const_activated = false;
+                               portinfo.enabled = false;
+                               muxinfo.ports.push_back(portinfo);
+
+                               for (int idx : sig2bits(sig_y))
+                                       add_to_list(bit2info[idx].mux_drivers, mux2info.size());
+
+                               for (int idx : sig2bits(sig_s))
+                                       bit2info[idx].seen_non_mux = true;
+
+                               mux2info.push_back(muxinfo);
+                       }
+                       else
+                       {
+                               for (auto &it : cell->connections) {
+                                       for (int idx : sig2bits(it.second))
+                                               bit2info[idx].seen_non_mux = true;
+                               }
+                       }
+               }
+               for (auto &it : module->wires) {
+                       if (it.second->port_output)
+                               for (int idx : sig2bits(RTLIL::SigSpec(it.second)))
+                                       bit2info[idx].seen_non_mux = true;
+               }
+
+               if (mux2info.size() == 0) {
+                       log("  No muxes found in this module.\n");
+                       return;
+               }
+
+               // Populate mux2info[].ports[]:
+               //      .input_muxes
+               for (size_t i = 0; i < bit2info.size(); i++)
+               for (int j : bit2info[i].mux_users)
+               for (auto &p : mux2info[j].ports) {
+                       if (is_in_list(p.input_sigs, i))
+                               for (int k : bit2info[i].mux_drivers)
+                                       add_to_list(p.input_muxes, k);
+               }
+
+               log("  Evaluating internal representation of mux trees.\n");
+
+               std::set<int> root_muxes;
+               for (auto &bi : bit2info) {
+                       if (!bi.seen_non_mux)
+                               continue;
+                       for (int mux_idx : bi.mux_drivers)
+                               root_muxes.insert(mux_idx);
+               }
+               for (int mux_idx : root_muxes)
+                       eval_root_mux(mux_idx);
+
+               log("  Analyzing evaluation results.\n");
+
+               for (auto &mi : mux2info)
+               {
+                       std::vector<int> live_ports;
+                       for (size_t port_idx = 0; port_idx < mi.ports.size(); port_idx++) {
+                               portinfo_t &pi = mi.ports[port_idx];
+                               if (pi.enabled) {
+                                       live_ports.push_back(port_idx);
+                               } else {
+                                       log("    dead port %zd/%zd on %s %s.\n", port_idx+1, mi.ports.size(),
+                                                       mi.cell->type.c_str(), mi.cell->name.c_str());
+                                       OPT_DID_SOMETHING = true;
+                                       removed_count++;
+                               }
+                       }
+
+                       if (live_ports.size() == mi.ports.size())
+                               continue;
+
+                       if (live_ports.size() == 0) {
+                               module->cells.erase(mi.cell->name);
+                               delete mi.cell;
+                               continue;
+                       }
+
+                       RTLIL::SigSpec sig_a = mi.cell->connections["\\A"];
+                       RTLIL::SigSpec sig_b = mi.cell->connections["\\B"];
+                       RTLIL::SigSpec sig_s = mi.cell->connections["\\S"];
+                       RTLIL::SigSpec sig_y = mi.cell->connections["\\Y"];
+
+                       RTLIL::SigSpec sig_ports = sig_b;
+                       sig_ports.append(sig_a);
+
+                       if (live_ports.size() == 1)
+                       {
+                               RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[0]*sig_a.width, sig_a.width);
+                               module->connections.push_back(RTLIL::SigSig(sig_y, sig_in));
+                               module->cells.erase(mi.cell->name);
+                               delete mi.cell;
+                       }
+                       else
+                       {
+                               RTLIL::SigSpec new_sig_a, new_sig_b, new_sig_s;
+
+                               for (size_t i = 0; i < live_ports.size(); i++) {
+                                       RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[i]*sig_a.width, sig_a.width);
+                                       if (i == live_ports.size()-1) {
+                                               new_sig_a = sig_in;
+                                       } else {
+                                               new_sig_b.append(sig_in);
+                                               new_sig_s.append(sig_s.extract(live_ports[i], 1));
+                                       }
+                               }
+
+                               mi.cell->connections["\\A"] = new_sig_a;
+                               mi.cell->connections["\\B"] = new_sig_b;
+                               mi.cell->connections["\\S"] = new_sig_s;
+                               if (new_sig_s.width == 1) {
+                                       mi.cell->type = "$mux";
+                                       mi.cell->attributes.erase("\\S_WIDTH");
+                               } else {
+                                       mi.cell->attributes["\\S_WIDTH"] = RTLIL::Const(new_sig_s.width);
+                               }
+                       }
+               }
+       }
+
+       bool list_is_subset(const std::vector<int> &sub, const std::vector<int> &super)
+       {
+               for (int v : sub)
+                       if (!is_in_list(super, v))
+                               return false;
+               return true;
+       }
+
+       bool is_in_list(const std::vector<int> &list, int value)
+       {
+               for (int v : list)
+                       if (v == value)
+                               return true;
+               return false;
+       }
+
+       void add_to_list(std::vector<int> &list, int value)
+       {
+               if (!is_in_list(list, value))
+                       list.push_back(value);
+       }
+
+       std::vector<int> sig2bits(RTLIL::SigSpec sig)
+       {
+               std::vector<int> results;
+               assign_map.apply(sig);
+               sig.expand();
+               for (auto &c : sig.chunks)
+                       if (c.wire != NULL) {
+                               bitDef_t bit(c.wire, c.offset);
+                               if (bit2num.count(bit) == 0) {
+                                       bitinfo_t info;
+                                       info.num = bit2info.size();
+                                       info.bit = bit;
+                                       info.seen_non_mux = false;
+                                       bit2info.push_back(info);
+                                       bit2num[info.bit] = info.num;
+                               }
+                               results.push_back(bit2num[bit]);
+                       }
+               return results;
+       }
+
+       struct knowledge_t
+       {
+               // database of known inactive signals
+               // the 2nd integer is a reference counter used to manage the
+               // list. when it is non-zero the signal in known to be inactive
+               std::map<int, int> known_inactive;
+
+               // database of known active signals
+               // the 2nd dimension is the list of or-ed signals. so we know that
+               // for each i there is a j so that known_active[i][j] points to an
+               // inactive control signal.
+               std::vector<std::vector<int>> known_active;
+
+               // this is just used to keep track of visited muxes in order to prohibit
+               // endless recursion in mux loops
+               std::set<int> visited_muxes;
+       };
+
+       void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx)
+       {
+               muxinfo_t &muxinfo = mux2info[mux_idx];
+               muxinfo.ports[port_idx].enabled = true;
+
+               for (size_t i = 0; i < muxinfo.ports.size(); i++) {
+                       if (int(i) == port_idx)
+                               continue;
+                       for (int b : muxinfo.ports[i].ctrl_sigs)
+                               knowledge.known_inactive[b]++;
+               }
+
+               if (port_idx < int(muxinfo.ports.size())-1 && !muxinfo.ports[port_idx].const_activated)
+                       knowledge.known_active.push_back(muxinfo.ports[port_idx].ctrl_sigs);
+
+               for (int m : muxinfo.ports[port_idx].input_muxes) {
+                       if (knowledge.visited_muxes.count(m) > 0)
+                               continue;
+                       knowledge.visited_muxes.insert(m);
+                       eval_mux(knowledge, m);
+                       knowledge.visited_muxes.erase(m);
+               }
+
+               if (port_idx < int(muxinfo.ports.size())-1 && !muxinfo.ports[port_idx].const_activated)
+                       knowledge.known_active.pop_back();
+
+               for (size_t i = 0; i < muxinfo.ports.size(); i++) {
+                       if (int(i) == port_idx)
+                               continue;
+                       for (int b : muxinfo.ports[i].ctrl_sigs)
+                               knowledge.known_inactive[b]--;
+               }
+       }
+
+       void eval_mux(knowledge_t &knowledge, int mux_idx)
+       {
+               muxinfo_t &muxinfo = mux2info[mux_idx];
+
+               // if there is a constant activated port we just use it
+               for (size_t port_idx = 0; port_idx < muxinfo.ports.size()-1; port_idx++)
+               {
+                       portinfo_t &portinfo = muxinfo.ports[port_idx];
+                       if (portinfo.const_activated) {
+                               eval_mux_port(knowledge, mux_idx, port_idx);
+                               return;
+                       }
+               }
+
+               // compare ports with known_active signals. if we find a match, only this
+               // port can be active. do not include the last port (its the default port
+               // that has no control signals).
+               for (size_t port_idx = 0; port_idx < muxinfo.ports.size()-1; port_idx++)
+               {
+                       portinfo_t &portinfo = muxinfo.ports[port_idx];
+                       for (size_t i = 0; i < knowledge.known_active.size(); i++) {
+                               if (list_is_subset(knowledge.known_active[i], portinfo.ctrl_sigs)) {
+                                       eval_mux_port(knowledge, mux_idx, port_idx);
+                                       return;
+                               }
+                       }
+               }
+
+               // compare ports with known_inactive and known_active signals. If all control
+               // signals of the port are know_inactive or if the control signals of all other
+               // ports are known_active this port can't be activated. this loop includes the
+               // default port but no known_inactive match is performed on the default port.
+               for (size_t port_idx = 0; port_idx < muxinfo.ports.size(); port_idx++)
+               {
+                       portinfo_t &portinfo = muxinfo.ports[port_idx];
+
+                       if (port_idx < muxinfo.ports.size()-1) {
+                               bool found_non_known_inactive = false;
+                               for (int i : portinfo.ctrl_sigs)
+                                       if (knowledge.known_inactive[i] == 0)
+                                               found_non_known_inactive = true;
+                               if (!found_non_known_inactive)
+                                       continue;
+                       }
+
+                       bool port_active = true;
+                       std::vector<int> other_ctrl_sig;
+                       for (size_t i = 0; i < muxinfo.ports.size()-1; i++) {
+                               if (i == port_idx)
+                                       continue;
+                               other_ctrl_sig.insert(other_ctrl_sig.end(),
+                                               muxinfo.ports[i].ctrl_sigs.begin(), muxinfo.ports[i].ctrl_sigs.end());
+                       }
+                       for (size_t i = 0; i < knowledge.known_active.size(); i++) {
+                               if (list_is_subset(knowledge.known_active[i], other_ctrl_sig))
+                                       port_active = false;
+                       }
+                       if (port_active)
+                               eval_mux_port(knowledge, mux_idx, port_idx);
+               }
+       }
+
+       void eval_root_mux(int mux_idx)
+       {
+               knowledge_t knowledge;
+               eval_mux(knowledge, mux_idx);
+       }
+};
+
+struct OptMuxtreePass : public Pass {
+       OptMuxtreePass() : Pass("opt_muxtree") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n");
+               extra_args(args, 1, design);
+
+               int total_count = 0;
+               for (auto &mod_it : design->modules) {
+                       if (mod_it.second->processes.size() > 0) {
+                               log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
+                       } else {
+                               OptMuxtreeWorker worker(design, mod_it.second);
+                               total_count += worker.removed_count;
+                       }
+               }
+               log("Removed %d multiplexer ports.\n", total_count);
+       }
+} OptMuxtreePass;
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
new file mode 100644 (file)
index 0000000..9a1b263
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ *  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 "opt_status.h"
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include "kernel/sha1.h"
+#include "kernel/celltypes.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <set>
+
+struct OptReduceWorker
+{
+       RTLIL::Design *design;
+       RTLIL::Module *module;
+       SigMap assign_map;
+
+       int total_count;
+       bool did_something;
+
+       void opt_reduce(std::set<RTLIL::Cell*> &cells, SigSet<RTLIL::Cell*> &drivers, RTLIL::Cell *cell)
+       {
+               if (cells.count(cell) == 0)
+                       return;
+               cells.erase(cell);
+
+               RTLIL::SigSpec sig_a = assign_map(cell->connections["\\A"]);
+               sig_a.sort_and_unify();
+               sig_a.expand();
+
+               RTLIL::SigSpec new_sig_a;
+               for (auto &chunk : sig_a.chunks)
+               {
+                       if (chunk.wire == NULL && chunk.data.bits[0] == RTLIL::State::S0) {
+                               if (cell->type == "$reduce_and") {
+                                       new_sig_a = RTLIL::SigSpec(RTLIL::State::S0);
+                                       break;
+                               }
+                               continue;
+                       }
+                       if (chunk.wire == NULL && chunk.data.bits[0] == RTLIL::State::S1) {
+                               if (cell->type == "$reduce_or") {
+                                       new_sig_a = RTLIL::SigSpec(RTLIL::State::S1);
+                                       break;
+                               }
+                               continue;
+                       }
+                       if (chunk.wire == NULL) {
+                               new_sig_a = RTLIL::SigSpec(RTLIL::State::Sx);
+                               break;
+                       }
+
+                       bool imported_children = false;
+                       for (auto child_cell : drivers.find(chunk)) {
+                               if (child_cell->type == cell->type) {
+                                       opt_reduce(cells, drivers, child_cell);
+                                       new_sig_a.append(child_cell->connections["\\A"]);
+                                       imported_children = true;
+                               }
+                       }
+                       if (!imported_children)
+                               new_sig_a.append(chunk);
+               }
+               new_sig_a.sort_and_unify();
+
+               if (new_sig_a != sig_a || sig_a.width != cell->connections["\\A"].width) {
+                       log("    New input vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_a));
+                       did_something = true;
+                       OPT_DID_SOMETHING = true;
+                       total_count++;
+               }
+
+               cell->connections["\\A"] = new_sig_a;
+               cell->parameters["\\A_WIDTH"] = RTLIL::Const(new_sig_a.width);
+               return;
+       }
+
+       void opt_mux(RTLIL::Cell *cell)
+       {
+               RTLIL::SigSpec sig_a = assign_map(cell->connections["\\A"]);
+               RTLIL::SigSpec sig_b = assign_map(cell->connections["\\B"]);
+               RTLIL::SigSpec sig_s = assign_map(cell->connections["\\S"]);
+
+               RTLIL::SigSpec new_sig_b, new_sig_s;
+               std::set<RTLIL::SigSpec> handled_sig;
+
+               handled_sig.insert(sig_a);
+               for (int i = 0; i < sig_s.width; i++)
+               {
+                       RTLIL::SigSpec this_b = sig_b.extract(i*sig_a.width, sig_a.width);
+                       if (handled_sig.count(this_b) > 0)
+                               continue;
+
+                       RTLIL::SigSpec this_s = sig_s.extract(i, 1);
+                       for (int j = i+1; j < sig_s.width; j++) {
+                               RTLIL::SigSpec that_b = sig_b.extract(j*sig_a.width, sig_a.width);
+                               if (this_b == that_b)
+                                       this_s.append(sig_s.extract(j, 1));
+                       }
+
+                       if (this_s.width > 1)
+                       {
+                               RTLIL::Wire *reduce_or_wire = new RTLIL::Wire;
+                               reduce_or_wire->name = NEW_ID;
+                               module->wires[reduce_or_wire->name] = reduce_or_wire;
+
+                               RTLIL::Cell *reduce_or_cell = new RTLIL::Cell;
+                               reduce_or_cell->name = NEW_ID;
+                               reduce_or_cell->type = "$reduce_or";
+                               reduce_or_cell->connections["\\A"] = this_s;
+                               reduce_or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(this_s.width);
+                               reduce_or_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+                               module->cells[reduce_or_cell->name] = reduce_or_cell;
+
+                               this_s = RTLIL::SigSpec(reduce_or_wire);
+                               reduce_or_cell->connections["\\Y"] = this_s;
+                       }
+
+                       new_sig_b.append(this_b);
+                       new_sig_s.append(this_s);
+                       handled_sig.insert(this_b);
+               }
+
+               if (new_sig_s.width != sig_s.width) {
+                       log("    New ctrl vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_s));
+                       did_something = true;
+                       OPT_DID_SOMETHING = true;
+                       total_count++;
+               }
+
+               if (new_sig_s.width == 0)
+               {
+                       module->connections.push_back(RTLIL::SigSig(cell->connections["\\Y"], cell->connections["\\A"]));
+                       assign_map.add(cell->connections["\\Y"], cell->connections["\\A"]);
+                       module->cells.erase(cell->name);
+                       delete cell;
+               }
+               else
+               {
+                       cell->connections["\\B"] = new_sig_b;
+                       cell->connections["\\S"] = new_sig_s;
+                       if (new_sig_s.width > 1) {
+                               cell->parameters["\\S_WIDTH"] = RTLIL::Const(new_sig_s.width);
+                       } else {
+                               cell->type = "$mux";
+                               cell->parameters.erase("\\S_WIDTH");
+                       }
+               }
+       }
+
+       OptReduceWorker(RTLIL::Design *design, RTLIL::Module *module) :
+                       design(design), module(module), assign_map(module)
+       {
+               log("  Optimizing cells in module %s.\n", module->name.c_str());
+
+               total_count = 0;
+               did_something = true;
+
+               while (did_something)
+               {
+                       did_something = false;
+
+                       // merge trees of reduce_* cells to one single cell and unify input vectors
+                       // (only handle recduce_and and reduce_or for various reasons)
+
+                       const char *type_list[] = { "$reduce_or", "$reduce_and" };
+                       for (auto type : type_list)
+                       {
+                               SigSet<RTLIL::Cell*> drivers;
+                               std::set<RTLIL::Cell*> cells;
+
+                               for (auto &cell_it : module->cells) {
+                                       RTLIL::Cell *cell = cell_it.second;
+                                       if (cell->type != type || !design->selected(module, cell))
+                                               continue;
+                                       drivers.insert(assign_map(cell->connections["\\Y"]), cell);
+                                       cells.insert(cell);
+                               }
+
+                               while (cells.size() > 0) {
+                                       RTLIL::Cell *cell = *cells.begin();
+                                       opt_reduce(cells, drivers, cell);
+                               }
+                       }
+
+                       // merge identical inputs on $mux and $pmux cells
+
+                       for (auto &cell_it : module->cells)
+                       {
+                               RTLIL::Cell *cell = cell_it.second;
+                               if ((cell->type != "$mux" && cell->type != "$pmux" && cell->type != "$safe_pmux") || !design->selected(module, cell))
+                                       continue;
+                               opt_mux(cell);
+                       }
+               }
+       }
+};
+
+struct OptReducePass : public Pass {
+       OptReducePass() : Pass("opt_reduce") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing OPT_REDUCE pass (consolidate $*mux and $reduce_* inputs).\n");
+               extra_args(args, 1, design);
+
+               int total_count = 0;
+               for (auto &mod_it : design->modules) {
+                       if (!design->selected(mod_it.second))
+                               continue;
+                       OptReduceWorker worker(design, mod_it.second);
+                       total_count += worker.total_count;
+               }
+
+               log("Performed a total of %d changes.\n", total_count);
+       }
+} OptReducePass;
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
new file mode 100644 (file)
index 0000000..384a4d8
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ *  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 "opt_status.h"
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+static SigMap assign_map;
+
+static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
+{
+       RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r;
+       RTLIL::Const val_cp, val_rp, val_rv;
+
+       if (dff->type == "$_DFF_N_" || dff->type == "$_DFF_P_") {
+               sig_d = dff->connections["\\D"];
+               sig_q = dff->connections["\\Q"];
+               sig_c = dff->connections["\\C"];
+               val_cp = RTLIL::Const(dff->type == "$_DFF_P_", 1);
+       }
+       else if (dff->type.substr(0,6) == "$_DFF_" && dff->type.substr(9) == "_" &&
+                       (dff->type[6] == 'N' || dff->type[6] == 'P') &&
+                       (dff->type[7] == 'N' || dff->type[7] == 'P') &&
+                       (dff->type[8] == '0' || dff->type[8] == '1')) {
+               sig_d = dff->connections["\\D"];
+               sig_q = dff->connections["\\Q"];
+               sig_c = dff->connections["\\C"];
+               sig_r = dff->connections["\\R"];
+               val_cp = RTLIL::Const(dff->type[6] == 'P', 1);
+               val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
+               val_rv = RTLIL::Const(dff->type[8] == '1', 1);
+       }
+       else if (dff->type == "$dff") {
+               sig_d = dff->connections["\\D"];
+               sig_q = dff->connections["\\Q"];
+               sig_c = dff->connections["\\CLK"];
+               val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
+       }
+       else if (dff->type == "$adff") {
+               sig_d = dff->connections["\\D"];
+               sig_q = dff->connections["\\Q"];
+               sig_c = dff->connections["\\CLK"];
+               sig_r = dff->connections["\\ARST"];
+               val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
+               val_rp = RTLIL::Const(dff->parameters["\\ARST_POLARITY"].as_bool(), 1);
+               val_rv = dff->parameters["\\ARST_VALUE"];
+       }
+       else
+               log_error("abort.");
+       
+       assign_map.apply(sig_d);
+       assign_map.apply(sig_q);
+       assign_map.apply(sig_c);
+       assign_map.apply(sig_r);
+
+       if (sig_d.is_fully_const() && sig_r.width == 0) {
+               RTLIL::SigSig conn(sig_q, sig_d);
+               mod->connections.push_back(conn);
+               goto delete_dff;
+       }
+
+       if (sig_d == sig_q && sig_r.width == 0) {
+               goto delete_dff;
+       }
+
+       return false;
+
+delete_dff:
+       log("Removing %s (%s) from module %s.\n", dff->name.c_str(), dff->type.c_str(), mod->name.c_str());
+       OPT_DID_SOMETHING = true;
+       mod->cells.erase(dff->name);
+       delete dff;
+       return true;
+}
+
+struct OptRmdffPass : public Pass {
+       OptRmdffPass() : Pass("opt_rmdff") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               int total_count = 0;
+               log_header("Executing OPT_RMDFF pass (remove dff with constant values).\n");
+
+               extra_args(args, 1, design);
+
+               for (auto &mod_it : design->modules)
+               {
+                       assign_map.set(mod_it.second);
+
+                       std::vector<std::string> dff_list;
+                       for (auto &it : mod_it.second->cells) {
+                               if (it.second->type == "$_DFF_N_") dff_list.push_back(it.first);
+                               if (it.second->type == "$_DFF_P_") dff_list.push_back(it.first);
+                               if (it.second->type == "$_DFF_NN0_") dff_list.push_back(it.first);
+                               if (it.second->type == "$_DFF_NN1_") dff_list.push_back(it.first);
+                               if (it.second->type == "$_DFF_NP0_") dff_list.push_back(it.first);
+                               if (it.second->type == "$_DFF_NP1_") dff_list.push_back(it.first);
+                               if (it.second->type == "$_DFF_PN0_") dff_list.push_back(it.first);
+                               if (it.second->type == "$_DFF_PN1_") dff_list.push_back(it.first);
+                               if (it.second->type == "$_DFF_PP0_") dff_list.push_back(it.first);
+                               if (it.second->type == "$_DFF_PP1_") dff_list.push_back(it.first);
+                               if (it.second->type == "$dff") dff_list.push_back(it.first);
+                               if (it.second->type == "$adff") dff_list.push_back(it.first);
+                       }
+
+                       for (auto &id : dff_list) {
+                               if (mod_it.second->cells.count(id) > 0 &&
+                                               handle_dff(mod_it.second, mod_it.second->cells[id]))
+                                       total_count++;
+                       }
+               }
+
+               assign_map.clear();
+               log("Replaced %d DFF cells.\n", total_count);
+       }
+} OptRmdffPass;
diff --git a/passes/opt/opt_rmunused.cc b/passes/opt/opt_rmunused.cc
new file mode 100644 (file)
index 0000000..29a6f2b
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ *  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 "opt_status.h"
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include "kernel/celltypes.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <set>
+
+static CellTypes ct;
+
+static void rmunused_module_cells(RTLIL::Module *module)
+{
+       SigMap assign_map(module);
+       std::set<RTLIL::Cell*> queue, unused;
+
+       SigSet<RTLIL::Cell*> wire2driver;
+       for (auto &it : module->cells) {
+               RTLIL::Cell *cell = it.second;
+               for (auto &it2 : cell->connections) {
+                       if (!ct.cell_input(cell->type, it2.first)) {
+                               RTLIL::SigSpec sig = it2.second;
+                               assign_map.apply(sig);
+                               wire2driver.insert(sig, cell);
+                       }
+               }
+               if (cell->type == "$memwr")
+                       queue.insert(cell);
+               unused.insert(cell);
+       }
+
+       for (auto &it : module->wires) {
+               RTLIL::Wire *wire = it.second;
+               if (wire->port_output) {
+                       std::set<RTLIL::Cell*> cell_list;
+                       RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
+                       assign_map.apply(sig);
+                       wire2driver.find(sig, cell_list);
+                       for (auto cell : cell_list)
+                               queue.insert(cell);
+               }
+       }
+
+       while (queue.size() > 0)
+       {
+               std::set<RTLIL::Cell*> new_queue;
+               for (auto cell : queue)
+                       unused.erase(cell);
+               for (auto cell : queue) {
+                       for (auto &it : cell->connections) {
+                               if (!ct.cell_output(cell->type, it.first)) {
+                                       std::set<RTLIL::Cell*> cell_list;
+                                       RTLIL::SigSpec sig = it.second;
+                                       assign_map.apply(sig);
+                                       wire2driver.find(sig, cell_list);
+                                       for (auto cell : cell_list) {
+                                               if (unused.count(cell) > 0)
+                                                       new_queue.insert(cell);
+                                       }
+                               }
+                       }
+               }
+               queue.swap(new_queue);
+       }
+
+       for (auto cell : unused) {
+               log("  removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str());
+               OPT_DID_SOMETHING = true;
+               module->cells.erase(cell->name);
+               delete cell;
+       }
+}
+
+static bool compare_signals(RTLIL::SigSpec &s1, RTLIL::SigSpec &s2)
+{
+       assert(s1.width == 1);
+       assert(s2.width == 1);
+       assert(s1.chunks.size() == 1);
+       assert(s2.chunks.size() == 1);
+
+       RTLIL::Wire *w1 = s1.chunks[0].wire;
+       RTLIL::Wire *w2 = s2.chunks[0].wire;
+
+       if (w1 == NULL || w2 == NULL)
+               return w2 == NULL;
+
+       if (w1->port_input != w2->port_input)
+               return w2->port_input;
+
+       if (w1->name[0] != w2->name[0])
+               return w2->name[0] == '\\';
+
+       if (w1->attributes.size() != w2->attributes.size())
+               return w2->attributes.size() > w1->attributes.size();
+
+       return w2->name < w1->name;
+}
+
+static void rmunused_module_signals(RTLIL::Module *module)
+{
+       SigMap assign_map(module);
+       for (auto &it : module->wires) {
+               RTLIL::Wire *wire = it.second;
+               for (int i = 0; i < wire->width; i++) {
+                       RTLIL::SigSpec s1 = RTLIL::SigSpec(wire, 1, i), s2 = assign_map(s1);
+                       if (!compare_signals(s1, s2))
+                               assign_map.add(s1);
+               }
+       }
+
+       module->connections.clear();
+
+       SigPool used_signals;
+       SigPool used_signals_nodrivers;
+       for (auto &it : module->cells) {
+               RTLIL::Cell *cell = it.second;
+               for (auto &it2 : cell->connections) {
+                       assign_map.apply(it2.second);
+                       used_signals.add(it2.second);
+                       if (!ct.cell_output(cell->type, it2.first))
+                               used_signals_nodrivers.add(it2.second);
+               }
+       }
+
+       std::vector<RTLIL::Wire*> del_wires;
+       for (auto &it : module->wires) {
+               RTLIL::Wire *wire = it.second;
+               if (wire->name[0] == '\\') {
+                       RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1;
+                       assign_map.apply(s2);
+                       if (!used_signals.check_any(s2) && wire->port_id == 0) {
+                               log("  removing unused non-port wire %s.\n", wire->name.c_str());
+                               del_wires.push_back(wire);
+                       } else {
+                               s1.expand();
+                               s2.expand();
+                               assert(s1.chunks.size() == s2.chunks.size());
+                               RTLIL::SigSig new_conn;
+                               for (size_t i = 0; i < s1.chunks.size(); i++)
+                                       if (s1.chunks[i] != s2.chunks[i]) {
+                                               new_conn.first.append(s1.chunks[i]);
+                                               new_conn.second.append(s2.chunks[i]);
+                                       }
+                               if (new_conn.first.width > 0) {
+                                       new_conn.first.optimize();
+                                       new_conn.second.optimize();
+                                       module->connections.push_back(new_conn);
+                               }
+                       }
+               } else {
+                       if (!used_signals.check_any(RTLIL::SigSpec(wire)))
+                               del_wires.push_back(wire);
+               }
+               RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire));
+               if (!used_signals_nodrivers.check_any(sig)) {
+                       std::string unused_bits;
+                       sig.expand();
+                       for (size_t i = 0; i < sig.chunks.size(); i++) {
+                               if (sig.chunks[i].wire == NULL)
+                                       continue;
+                               if (!used_signals_nodrivers.check_any(sig)) {
+                                       if (!unused_bits.empty())
+                                               unused_bits += " ";
+                                       unused_bits += stringf("%zd", i);
+                               }
+                       }
+                       if (unused_bits.empty() || wire->port_id != 0)
+                               wire->attributes.erase("\\unused_bits");
+                       else
+                               wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
+               } else {
+                       wire->attributes.erase("\\unused_bits");
+               }
+       }
+
+       for (auto wire : del_wires) {
+               module->wires.erase(wire->name);
+               delete wire;
+       }
+
+       if (del_wires.size() > 0)
+               log("  removed %zd unused temporary wires.\n", del_wires.size());
+}
+
+static void rmunused_module(RTLIL::Module *module)
+{
+       log("Finding unused cells or wires in module %s..\n", module->name.c_str());
+
+       rmunused_module_cells(module);
+       rmunused_module_signals(module);
+}
+
+struct OptRmUnusedPass : public Pass {
+       OptRmUnusedPass() : Pass("opt_rmunused") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing OPT_RMUNUSED pass (remove unused cells and wires).\n");
+               log_push();
+
+               extra_args(args, 1, design);
+
+               ct.setup_internals();
+               ct.setup_internals_mem();
+               ct.setup_stdcells();
+               ct.setup_stdcells_mem();
+
+               for (auto &mod_it : design->modules) {
+                       if (mod_it.second->processes.size() > 0) {
+                               log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
+                       } else {
+                               rmunused_module(mod_it.second);
+                       }
+               }
+
+               ct.clear();
+               log_pop();
+       }
+} OptRmUnusedPass;
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
new file mode 100644 (file)
index 0000000..ecad8b4
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ *  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 "opt_status.h"
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include "kernel/sha1.h"
+#include "kernel/celltypes.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <set>
+
+#define USE_CELL_HASH_CACHE
+
+struct OptShareWorker
+{
+       RTLIL::Design *design;
+       RTLIL::Module *module;
+       SigMap assign_map;
+
+       CellTypes ct;
+       int total_count;
+#ifdef USE_CELL_HASH_CACHE
+       std::map<const RTLIL::Cell*, std::string> cell_hash_cache;
+#endif
+
+#ifdef USE_CELL_HASH_CACHE
+       std::string int_to_hash_string(unsigned int v)
+       {
+               if (v == 0)
+                       return "0";
+               std::string str = "";
+               while (v > 0) {
+                       str += 'a' + (v & 15);
+                       v = v >> 4;
+               }
+               return str;
+       }
+
+       std::string hash_cell_parameters_and_connections(const RTLIL::Cell *cell)
+       {
+               if (cell_hash_cache.count(cell) > 0)
+                       return cell_hash_cache[cell];
+
+               std::string hash_string = cell->type + "\n";
+
+               for (auto &it : cell->parameters)
+                       hash_string += "P " + it.first + "=" + it.second.as_string() + "\n";
+
+               for (auto &it : cell->connections) {
+                       if (ct.cell_output(cell->type, it.first))
+                               continue;
+                       RTLIL::SigSpec sig = it.second;
+                       assign_map.apply(sig);
+                       hash_string += "C " + it.first + "=";
+                       for (auto &chunk : sig.chunks) {
+                               if (chunk.wire)
+                                       hash_string += "{" + chunk.wire->name + " " +
+                                                       int_to_hash_string(chunk.offset) + " " +
+                                                       int_to_hash_string(chunk.width) + "}";
+                               else
+                                       hash_string += chunk.data.as_string();
+                       }
+                       hash_string += "\n";
+               }
+
+               unsigned char hash[20];
+               char hash_hex_string[41];
+               sha1::calc(hash_string.c_str(), hash_string.size(), hash);
+               sha1::toHexString(hash, hash_hex_string);
+               cell_hash_cache[cell] = hash_hex_string;
+
+               return cell_hash_cache[cell];
+       }
+#endif
+
+       bool compare_cell_parameters_and_connections(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2, bool &lt)
+       {
+#ifdef USE_CELL_HASH_CACHE
+               std::string hash1 = hash_cell_parameters_and_connections(cell1);
+               std::string hash2 = hash_cell_parameters_and_connections(cell2);
+
+               if (hash1 != hash2) {
+                       lt = hash1 < hash2;
+                       return true;
+               }
+#endif
+
+               if (cell1->parameters != cell2->parameters) {
+                       lt = cell1->parameters < cell2->parameters;
+                       return true;
+               }
+
+               std::map<RTLIL::IdString, RTLIL::SigSpec> conn1 = cell1->connections;
+               std::map<RTLIL::IdString, RTLIL::SigSpec> conn2 = cell2->connections;
+
+               for (auto &it : conn1) {
+                       if (ct.cell_output(cell1->type, it.first))
+                               it.second = RTLIL::SigSpec();
+                       else
+                               assign_map.apply(it.second);
+               }
+
+               for (auto &it : conn2) {
+                       if (ct.cell_output(cell2->type, it.first))
+                               it.second = RTLIL::SigSpec();
+                       else
+                               assign_map.apply(it.second);
+               }
+
+               if (conn1 != conn2) {
+                       lt = conn1 < conn2;
+                       return true;
+               }
+
+               return false;
+       }
+
+       bool compare_cells(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2)
+       {
+               if (cell1->type != cell2->type)
+                       return cell1->type < cell2->type;
+
+               if (!ct.cell_known(cell1->type))
+                       return cell1 < cell2;
+
+               bool lt;
+               if (compare_cell_parameters_and_connections(cell1, cell2, lt))
+                       return lt;
+
+               return false;
+       }
+
+       struct CompareCells {
+               OptShareWorker *that;
+               CompareCells(OptShareWorker *that) : that(that) {}
+               bool operator()(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2) const {
+                       return that->compare_cells(cell1, cell2);
+               }
+       };
+
+       OptShareWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux) :
+               design(design), module(module), assign_map(module)
+       {
+               total_count = 0;
+               ct.setup_internals();
+               ct.setup_internals_mem();
+               ct.setup_stdcells();
+               ct.setup_stdcells_mem();
+
+               if (mode_nomux) {
+                       ct.cell_types.erase("$mux");
+                       ct.cell_types.erase("$pmux");
+                       ct.cell_types.erase("$safe_pmux");
+               }
+
+               log("Finding identical cells in module `%s'.\n", module->name.c_str());
+               assign_map.set(module);
+
+               bool did_something = true;
+               while (did_something)
+               {
+#ifdef USE_CELL_HASH_CACHE
+                       cell_hash_cache.clear();
+#endif
+                       std::vector<RTLIL::Cell*> cells;
+                       cells.reserve(module->cells.size());
+                       for (auto &it : module->cells) {
+                               if (ct.cell_known(it.second->type) && design->selected(module, it.second))
+                                       cells.push_back(it.second);
+                       }
+
+                       did_something = false;
+                       std::map<RTLIL::Cell*, RTLIL::Cell*, CompareCells> sharemap(CompareCells(this));
+                       for (auto cell : cells)
+                       {
+                               if (sharemap.count(cell) > 0) {
+                                       did_something = true;
+                                       log("  Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str());
+                                       for (auto &it : cell->connections) {
+                                               if (ct.cell_output(cell->type, it.first)) {
+                                                       RTLIL::SigSpec other_sig = sharemap[cell]->connections[it.first];
+                                                       log("    Redirecting output %s: %s = %s\n", it.first.c_str(),
+                                                                       log_signal(it.second), log_signal(other_sig));
+                                                       module->connections.push_back(RTLIL::SigSig(it.second, other_sig));
+                                                       assign_map.add(it.second, other_sig);
+                                               }
+                                       }
+                                       log("    Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str());
+                                       module->cells.erase(cell->name);
+                                       OPT_DID_SOMETHING = true;
+                                       total_count++;
+                                       delete cell;
+                               } else {
+                                       sharemap[cell] = cell;
+                               }
+                       }
+               }
+       }
+};
+
+struct OptSharePass : public Pass {
+       OptSharePass() : Pass("opt_share") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing OPT_SHARE pass (detect identical cells).\n");
+
+               bool mode_nomux = false;
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       std::string arg = args[argidx];
+                       if (arg == "-nomux") {
+                               mode_nomux = true;
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               int total_count = 0;
+               for (auto &mod_it : design->modules) {
+                       if (!design->selected(mod_it.second))
+                               continue;
+                       OptShareWorker worker(design, mod_it.second, mode_nomux);
+                       total_count += worker.total_count;
+               }
+
+               log("Removed a total of %d cells.\n", total_count);
+       }
+} OptSharePass;
diff --git a/passes/opt/opt_status.h b/passes/opt/opt_status.h
new file mode 100644 (file)
index 0000000..3d12baa
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *  
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef OPT_STATUS_H
+#define OPT_STATUS_H
+
+extern bool OPT_DID_SOMETHING;
+
+#endif
+
diff --git a/passes/proc/Makefile.inc b/passes/proc/Makefile.inc
new file mode 100644 (file)
index 0000000..68564e0
--- /dev/null
@@ -0,0 +1,8 @@
+
+OBJS += passes/proc/proc.o
+OBJS += passes/proc/proc_clean.o
+OBJS += passes/proc/proc_rmdead.o
+OBJS += passes/proc/proc_arst.o
+OBJS += passes/proc/proc_mux.o
+OBJS += passes/proc/proc_dff.o
+
diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc
new file mode 100644 (file)
index 0000000..c0f502c
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  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>
+
+struct ProcPass : public Pass {
+       ProcPass() : Pass("proc") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing PROC pass (convert processes to netlists).\n");
+               log_push();
+
+               extra_args(args, 1, design);
+
+               Pass::call(design, "proc_clean");
+               Pass::call(design, "proc_rmdead");
+               Pass::call(design, "proc_arst");
+               Pass::call(design, "proc_mux");
+               Pass::call(design, "proc_dff");
+               Pass::call(design, "proc_clean");
+
+               log_pop();
+       }
+} ProcPass;
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
new file mode 100644 (file)
index 0000000..8e57d0e
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *  
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+static bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSpec ref, bool &polarity)
+{
+       if (signal.width != 1)
+               return false;
+       if (signal == ref)
+               return true;
+
+       for (auto &cell_it : mod->cells) {
+               RTLIL::Cell *cell = cell_it.second;
+               if (cell->type == "$reduce_or" && cell->connections["\\Y"] == signal)
+                       return check_signal(mod, cell->connections["\\A"], ref, polarity);
+               if (cell->type == "$reduce_bool" && cell->connections["\\Y"] == signal)
+                       return check_signal(mod, cell->connections["\\A"], ref, polarity);
+               if (cell->type == "$logic_not" && cell->connections["\\Y"] == signal) {
+                       polarity = !polarity;
+                       return check_signal(mod, cell->connections["\\A"], ref, polarity);
+               }
+               if (cell->type == "$not" && cell->connections["\\Y"] == signal) {
+                       polarity = !polarity;
+                       return check_signal(mod, cell->connections["\\A"], ref, polarity);
+               }
+               if (cell->type == "$eq" && cell->connections["\\Y"] == signal) {
+                       if (cell->connections["\\A"].is_fully_const()) {
+                               if (!cell->connections["\\A"].as_bool())
+                                       polarity = !polarity;
+                               return check_signal(mod, cell->connections["\\B"], ref, polarity);
+                       }
+                       if (cell->connections["\\B"].is_fully_const()) {
+                               if (!cell->connections["\\B"].as_bool())
+                                       polarity = !polarity;
+                               return check_signal(mod, cell->connections["\\A"], ref, polarity);
+                       }
+               }
+               if (cell->type == "$ne" && cell->connections["\\Y"] == signal) {
+                       if (cell->connections["\\A"].is_fully_const()) {
+                               if (cell->connections["\\A"].as_bool())
+                                       polarity = !polarity;
+                               return check_signal(mod, cell->connections["\\B"], ref, polarity);
+                       }
+                       if (cell->connections["\\B"].is_fully_const()) {
+                               if (cell->connections["\\B"].as_bool())
+                                       polarity = !polarity;
+                               return check_signal(mod, cell->connections["\\A"], ref, polarity);
+                       }
+               }
+       }
+
+       return false;
+}
+
+static void apply_const(RTLIL::Module *mod, const RTLIL::SigSpec rspec, RTLIL::SigSpec &rval, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity, bool unknown)
+{
+       for (auto &action : cs->actions) {
+               if (unknown)
+                       rspec.replace(action.first, RTLIL::SigSpec(RTLIL::State::Sm, action.second.width), &rval);
+               else
+                       rspec.replace(action.first, action.second, &rval);
+       }
+
+       for (auto sw : cs->switches) {
+               if (sw->signal.width == 0) {
+                       for (auto cs2 : sw->cases)
+                               apply_const(mod, rspec, rval, cs2, const_sig, polarity, unknown);
+               }
+               bool this_polarity = polarity;
+               if (check_signal(mod, sw->signal, const_sig, this_polarity)) {
+                       for (auto cs2 : sw->cases) {
+                               for (auto comp : cs2->compare)
+                                       if (comp == RTLIL::SigSpec(this_polarity, 1))
+                                               goto matched_case;
+                               if (cs2->compare.size() == 0) {
+                       matched_case:
+                                       apply_const(mod, rspec, rval, cs2, const_sig, polarity, false);
+                                       break;
+                               }
+                       }
+               } else {
+                       for (auto cs2 : sw->cases)
+                               apply_const(mod, rspec, rval, cs2, const_sig, polarity, true);
+               }
+       }
+}
+
+static void eliminate_const(RTLIL::Module *mod, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity)
+{
+       for (auto sw : cs->switches) {
+               bool this_polarity = polarity;
+               if (check_signal(mod, sw->signal, const_sig, this_polarity)) {
+                       bool found_rem_path = false;
+                       for (size_t i = 0; i < sw->cases.size(); i++) {
+                               RTLIL::CaseRule *cs2 = sw->cases[i];
+                               for (auto comp : cs2->compare)
+                                       if (comp == RTLIL::SigSpec(this_polarity, 1))
+                                               goto matched_case;
+                               if (found_rem_path) {
+                       matched_case:
+                                       sw->cases.erase(sw->cases.begin() + (i--));
+                                       delete cs2;
+                                       continue;
+                               }
+                               found_rem_path = true;
+                               cs2->compare.clear();
+                       }
+                       sw->signal = RTLIL::SigSpec();
+               } else {
+                       for (auto cs2 : sw->cases)
+                               eliminate_const(mod, cs2, const_sig, polarity);
+               }
+       }
+}
+
+static void proc_arst(RTLIL::Module *mod, RTLIL::Process *proc, SigMap &assign_map)
+{
+       if (proc->root_case.switches.size() != 1)
+               return;
+
+       RTLIL::SigSpec root_sig = proc->root_case.switches[0]->signal;
+
+       for (auto &sync : proc->syncs) {
+               if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn) {
+                       bool polarity = sync->type == RTLIL::SyncType::STp;
+                       if (check_signal(mod, root_sig, sync->signal, polarity)) {
+                               log("Found async reset %s in `%s.%s'.\n", log_signal(sync->signal), mod->name.c_str(), proc->name.c_str());
+                               sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0;
+                               for (auto &action : sync->actions) {
+                                       RTLIL::SigSpec rspec = action.second;
+                                       RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.width);
+                                       RTLIL::SigSpec last_rval;
+                                       for (int count = 0; rval != last_rval; count++) {
+                                               last_rval = rval;
+                                               apply_const(mod, rspec, rval, &proc->root_case, root_sig, polarity, false);
+                                               assign_map.apply(rval);
+                                               if (rval.is_fully_const())
+                                                       break;
+                                               if (count > 100)
+                                                       log_error("Async reset %s yields endless loop at value %s for signal %s.\n",
+                                                                       log_signal(sync->signal), log_signal(rval), log_signal(action.first));
+                                               rspec = rval;
+                                       }
+                                       if (rval.has_marked_bits())
+                                               log_error("Async reset %s yields non-constant value %s for signal %s.\n",
+                                                               log_signal(sync->signal), log_signal(rval), log_signal(action.first));
+                                       action.second = rval;
+                               }
+                               eliminate_const(mod, &proc->root_case, root_sig, polarity);
+                       }
+               }
+       }
+}
+
+struct ProcArstPass : public Pass {
+       ProcArstPass() : Pass("proc_arst") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing PROC_ARST pass (detect async resets in processes).\n");
+
+               extra_args(args, 1, design);
+
+               for (auto &mod_it : design->modules) {
+                       SigMap assign_map(mod_it.second);
+                       for (auto &proc_it : mod_it.second->processes)
+                               proc_arst(mod_it.second, proc_it.second, assign_map);
+               }
+       }
+} ProcArstPass;
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
new file mode 100644 (file)
index 0000000..ec9fade
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ *  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>
+
+static void switch_clean(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did_something, int &count);
+static void case_clean(RTLIL::CaseRule *cs, bool &did_something, int &count);
+
+static void switch_clean(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did_something, int &count)
+{
+       if (sw->signal.width > 0 && sw->signal.is_fully_const())
+       {
+               int found_matching_case_idx = -1;
+               for (int i = 0; i < int(sw->cases.size()) && found_matching_case_idx < 0; i++)
+               {
+                       RTLIL::CaseRule *cs = sw->cases[i];
+                       if (cs->compare.size() == 0)
+                               break;
+                       for (int j = 0; j < int(cs->compare.size()); j++) {
+                               RTLIL::SigSpec &val = cs->compare[j];
+                               if (!val.is_fully_const())
+                                       continue;
+                               if (val == sw->signal) {
+                                       cs->compare.clear();
+                                       found_matching_case_idx = i;
+                                       break;
+                               } else
+                                       cs->compare.erase(cs->compare.begin()+(j--));
+                       }
+                       if (cs->compare.size() == 0 && found_matching_case_idx < 0) {
+                               sw->cases.erase(sw->cases.begin()+(i--));
+                               delete cs;
+                       }
+               }
+               while (found_matching_case_idx >= 0 && int(sw->cases.size()) > found_matching_case_idx+1) {
+                       delete sw->cases.back();
+                       sw->cases.pop_back();
+               }
+               if (found_matching_case_idx == 0)
+                       sw->signal = RTLIL::SigSpec();
+       }
+
+       if (sw->cases.size() == 1 && (sw->signal.width == 0 || sw->cases[0]->compare.empty()))
+       {
+               did_something = true;
+               for (auto &action : sw->cases[0]->actions)
+                       parent->actions.push_back(action);
+               for (auto sw2 : sw->cases[0]->switches)
+                       parent->switches.push_back(sw2);
+               sw->cases[0]->switches.clear();
+               delete sw->cases[0];
+               sw->cases.clear();
+       }
+       else
+       {
+               bool all_cases_are_empty = true;
+               for (auto cs : sw->cases) {
+                       if (cs->actions.size() != 0 || cs->switches.size() != 0)
+                               all_cases_are_empty = false;
+                       case_clean(cs, did_something, count);
+               }
+               if (all_cases_are_empty) {
+                       did_something = true;
+                       for (auto cs : sw->cases)
+                               delete cs;
+                       sw->cases.clear();
+               }
+       }
+}
+
+static void case_clean(RTLIL::CaseRule *cs, bool &did_something, int &count)
+{
+       for (size_t i = 0; i < cs->actions.size(); i++) {
+               if (cs->actions[i].first.width == 0) {
+                       did_something = true;
+                       cs->actions.erase(cs->actions.begin() + (i--));
+               }
+       }
+       for (size_t i = 0; i < cs->switches.size(); i++) {
+               RTLIL::SwitchRule *sw = cs->switches[i];
+               if (sw->cases.size() == 0) {
+                       cs->switches.erase(cs->switches.begin() + (i--));
+                       did_something = true;
+                       delete sw;
+                       count++;
+               } else
+                       switch_clean(sw, cs, did_something, count);
+       }
+}
+
+static void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count)
+{
+       int count = 0;
+       bool did_something = true;
+       for (size_t i = 0; i < proc->syncs.size(); i++) {
+               for (size_t j = 0; j < proc->syncs[i]->actions.size(); j++)
+                       if (proc->syncs[i]->actions[j].first.width == 0)
+                               proc->syncs[i]->actions.erase(proc->syncs[i]->actions.begin() + (j--));
+               if (proc->syncs[i]->actions.size() == 0) {
+                       delete proc->syncs[i];
+                       proc->syncs.erase(proc->syncs.begin() + (i--));
+               }
+       }
+       while (did_something) {
+               did_something = false;
+               case_clean(&proc->root_case, did_something, count);
+       }
+       if (count > 0)
+               log("Found and cleaned up %d empty switch%s in `%s.%s'.\n", count, count == 1 ? "" : "es", mod->name.c_str(), proc->name.c_str());
+       total_count += count;
+}
+
+struct ProcCleanPass : public Pass {
+       ProcCleanPass() : Pass("proc_clean") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               int total_count = 0;
+               log_header("Executing PROC_CLEAN pass (remove empty switches from decision trees).\n");
+
+               extra_args(args, 1, design);
+
+               for (auto &mod_it : design->modules) {
+                       std::vector<std::string> delme;
+                       for (auto &proc_it : mod_it.second->processes) {
+                               proc_clean(mod_it.second, proc_it.second, total_count);
+                               if (proc_it.second->syncs.size() == 0 && proc_it.second->root_case.switches.size() == 0 &&
+                                               proc_it.second->root_case.actions.size() == 0) {
+                                       log("Removing empty process `%s.%s'.\n", mod_it.first.c_str(), proc_it.second->name.c_str());
+                                       delme.push_back(proc_it.first);
+                               }
+                       }
+                       for (auto &id : delme) {
+                               delete mod_it.second->processes[id];
+                               mod_it.second->processes.erase(id);
+                       }
+               }
+
+               log("Cleaned up %d empty switch%s.\n", total_count, total_count == 1 ? "" : "es");
+       }
+} ProcCleanPass;
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
new file mode 100644 (file)
index 0000000..ccacc72
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *  
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/consteval.h"
+#include "kernel/log.h"
+#include <sstream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
+{
+       RTLIL::SigSpec lvalue;
+
+       for (auto sync : proc->syncs)
+       for (auto &action : sync->actions)
+               if (action.first.width > 0) {
+                       lvalue = action.first;
+                       lvalue.sort_and_unify();
+                       break;
+               }
+
+       for (auto sync : proc->syncs) {
+               RTLIL::SigSpec this_lvalue;
+               for (auto &action : sync->actions)
+                       this_lvalue.append(action.first);
+               this_lvalue.sort_and_unify();
+               RTLIL::SigSpec common_sig = this_lvalue.extract(lvalue);
+               if (common_sig.width > 0)
+                       lvalue = common_sig;
+       }
+
+       return lvalue;
+}
+
+static void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_rst, RTLIL::SigSpec sig_out,
+               bool clk_polarity, bool arst_polarity, RTLIL::SigSpec clk, RTLIL::SigSpec *arst, RTLIL::Process *proc)
+{
+       std::stringstream sstr;
+       sstr << "$procdff$" << (RTLIL::autoidx++);
+
+       RTLIL::Cell *cell = new RTLIL::Cell;
+       cell->name = sstr.str();
+       cell->type = arst ? "$adff" : "$dff";
+       cell->attributes = proc->attributes;
+       mod->cells[cell->name] = cell;
+
+       cell->parameters["\\WIDTH"] = RTLIL::Const(sig_in.width);
+       if (arst) {
+               cell->parameters["\\ARST_POLARITY"] = RTLIL::Const(arst_polarity, 1);
+               cell->parameters["\\ARST_VALUE"] = val_rst;
+       }
+       cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1);
+
+       cell->connections["\\D"] = sig_in;
+       cell->connections["\\Q"] = sig_out;
+       if (arst)
+               cell->connections["\\ARST"] = *arst;
+       cell->connections["\\CLK"] = clk;
+
+       log("  created %s cell `%s' with %s edge clock", cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative");
+       if (arst)
+               log("  and %s level reset", arst_polarity ? "positive" : "negative");
+       log(".\n");
+}
+
+static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
+{
+       while (1)
+       {
+               RTLIL::SigSpec sig = find_any_lvalue(proc);
+
+               if (sig.width == 0)
+                       break;
+
+               log("Creating register for signal `%s.%s' using process `%s.%s'.\n",
+                               mod->name.c_str(), log_signal(sig), mod->name.c_str(), proc->name.c_str());
+
+               RTLIL::SigSpec insig = RTLIL::SigSpec(RTLIL::State::Sz, sig.width);
+               RTLIL::SigSpec rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.width);
+               RTLIL::SyncRule *sync_level = NULL;
+               RTLIL::SyncRule *sync_edge = NULL;
+               RTLIL::SyncRule *sync_always = NULL;
+
+               for (auto sync : proc->syncs)
+               for (auto &action : sync->actions)
+               {
+                       if (action.first.extract(sig).width == 0)
+                               continue;
+
+                       if (sync->type == RTLIL::SyncType::ST0 || sync->type == RTLIL::SyncType::ST1) {
+                               if (sync_level != NULL && sync_level != sync)
+                                       log_error("Multiple level sensitive events found for this signal!\n");
+                               sig.replace(action.first, action.second, &rstval);
+                               sync_level = sync;
+                       }
+                       else if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn) {
+                               if (sync_edge != NULL && sync_edge != sync)
+                                       log_error("Multiple edge sensitive events found for this signal!\n");
+                               sig.replace(action.first, action.second, &insig);
+                               sync_edge = sync;
+                       }
+                       else if (sync->type == RTLIL::SyncType::STa) {
+                               if (sync_always != NULL && sync_always != sync)
+                                       log_error("Multiple always events found for this signal!\n");
+                               sig.replace(action.first, action.second, &insig);
+                               sync_always = sync;
+                       }
+                       else {
+                               log_error("Event with any-edge sensitivity found for this signal!\n");
+                       }
+
+                       action.first.remove2(sig, &action.second);
+               }
+
+               ce.assign_map.apply(insig);
+               ce.assign_map.apply(rstval);
+               ce.assign_map.apply(sig);
+
+               insig.optimize();
+               rstval.optimize();
+               sig.optimize();
+
+               if (sync_always) {
+                       if (sync_edge || sync_level)
+                               log_error("Mixed always event with edge and/or level sensitive events!\n");
+                       log("  created direct connection (no actual register cell created).\n");
+                       mod->connections.push_back(RTLIL::SigSig(sig, insig));
+                       continue;
+               }
+
+               if (!sync_edge)
+                       log_error("Missing edge-sensitive event for this signal!\n");
+
+               if (!rstval.is_fully_const() && !ce.eval(rstval))
+                       log_error("Async reset value `%s' is not constant!\n", log_signal(rstval));
+
+               gen_dff(mod, insig, rstval.chunks[0].data, sig,
+                               sync_edge->type == RTLIL::SyncType::STp,
+                               sync_level && sync_level->type == RTLIL::SyncType::ST1,
+                               sync_edge->signal, sync_level ? &sync_level->signal : NULL, proc);
+       }
+}
+
+struct ProcDffPass : public Pass {
+       ProcDffPass() : Pass("proc_dff") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing PROC_DFF pass (convert process syncs to FFs).\n");
+
+               extra_args(args, 1, design);
+
+               for (auto &mod_it : design->modules) {
+                       ConstEval ce(mod_it.second);
+                       for (auto &proc_it : mod_it.second->processes)
+                               proc_dff(mod_it.second, proc_it.second, ce);
+               }
+       }
+} ProcDffPass;
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
new file mode 100644 (file)
index 0000000..4d50597
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ *  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/bitpattern.h"
+#include "kernel/log.h"
+#include <sstream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+static RTLIL::SigSpec find_any_lvalue(const RTLIL::CaseRule *cs)
+{
+       for (auto &action : cs->actions) {
+               if (action.first.width)
+                       return action.first;
+       }
+
+       for (auto sw : cs->switches)
+       for (auto cs2 : sw->cases) {
+               RTLIL::SigSpec sig = find_any_lvalue(cs2);
+               if (sig.width)
+                       return sig;
+       }
+
+       return RTLIL::SigSpec();
+}
+
+static void extract_core_signal(const RTLIL::CaseRule *cs, RTLIL::SigSpec &sig)
+{
+       for (auto &action : cs->actions) {
+               RTLIL::SigSpec lvalue = action.first.extract(sig);
+               if (lvalue.width)
+                       sig = lvalue;
+       }
+
+       for (auto sw : cs->switches)
+       for (auto cs2 : sw->cases)
+               extract_core_signal(cs2, sig);
+}
+
+static RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw)
+{
+       std::stringstream sstr;
+       sstr << "$procmux$" << (RTLIL::autoidx++);
+
+       RTLIL::Wire *cmp_wire = new RTLIL::Wire;
+       cmp_wire->name = sstr.str() + "_CMP";
+       cmp_wire->width = 0;
+       mod->wires[cmp_wire->name] = cmp_wire;
+
+       for (auto comp : compare)
+       {
+               RTLIL::SigSpec sig = signal;
+               sig.expand();
+               comp.expand();
+
+               // get rid of don't-care bits
+               assert(sig.width == comp.width);
+               for (int i = 0; i < comp.width; i++)
+                       if (comp.chunks[i].wire == NULL && comp.chunks[i].data.bits[0] == RTLIL::State::Sa) {
+                               sig.remove(i, 1);
+                               comp.remove(i--, 1);
+                       }
+               if (comp.width == 0)
+                       return RTLIL::SigSpec();
+               sig.optimize();
+               comp.optimize();
+
+               if (sig.width == 1 && comp == RTLIL::SigSpec(1,1))
+               {
+                       mod->connections.push_back(RTLIL::SigSig(RTLIL::SigSpec(cmp_wire, 1, cmp_wire->width++), sig));
+               }
+               else
+               {
+                       // create compare cell
+                       RTLIL::Cell *eq_cell = new RTLIL::Cell;
+                       std::stringstream sstr2;
+                       sstr2 << sstr.str() << "_CMP" << cmp_wire->width;
+                       eq_cell->name = sstr2.str();
+                       eq_cell->type = "$eq";
+                       eq_cell->attributes = sw->attributes;
+                       mod->cells[eq_cell->name] = eq_cell;
+
+                       eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
+                       eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(0);
+
+                       eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig.width);
+                       eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(comp.width);
+                       eq_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+
+                       eq_cell->connections["\\A"] = sig;
+                       eq_cell->connections["\\B"] = comp;
+                       eq_cell->connections["\\Y"] = RTLIL::SigSpec(cmp_wire, 1, cmp_wire->width++);
+               }
+       }
+
+       RTLIL::Wire *ctrl_wire;
+       if (cmp_wire->width == 1)
+       {
+               ctrl_wire = cmp_wire;
+       }
+       else
+       {
+               ctrl_wire = new RTLIL::Wire;
+               ctrl_wire->name = sstr.str() + "_CTRL";
+               ctrl_wire->width = 1;
+               mod->wires[ctrl_wire->name] = ctrl_wire;
+
+               // reduce cmp vector to one logic signal
+               RTLIL::Cell *any_cell = new RTLIL::Cell;
+               any_cell->name = sstr.str() + "_ANY";
+               any_cell->type = "$reduce_or";
+               any_cell->attributes = sw->attributes;
+               mod->cells[any_cell->name] = any_cell;
+
+               any_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
+               any_cell->parameters["\\A_WIDTH"] = RTLIL::Const(cmp_wire->width);
+               any_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+
+               any_cell->connections["\\A"] = cmp_wire;
+               any_cell->connections["\\Y"] = RTLIL::SigSpec(ctrl_wire);
+       }
+
+       return RTLIL::SigSpec(ctrl_wire);
+}
+
+static RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw)
+{
+       assert(when_signal.width == else_signal.width);
+
+       std::stringstream sstr;
+       sstr << "$procmux$" << (RTLIL::autoidx++);
+
+       // the trivial cases
+       if (compare.size() == 0 || when_signal == else_signal)
+               return when_signal;
+
+       // compare results
+       RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw);
+       if (ctrl_sig.width == 0)
+               return when_signal;
+       assert(ctrl_sig.width == 1);
+
+       // prepare multiplexer output signal
+       RTLIL::Wire *result_wire = new RTLIL::Wire;
+       result_wire->name = sstr.str() + "_Y";
+       result_wire->width = when_signal.width;
+       mod->wires[result_wire->name] = result_wire;
+
+       // create the multiplexer itself
+       RTLIL::Cell *mux_cell = new RTLIL::Cell;
+       mux_cell->name = sstr.str();
+       mux_cell->type = "$mux";
+       mux_cell->attributes = sw->attributes;
+       mod->cells[mux_cell->name] = mux_cell;
+
+       mux_cell->parameters["\\WIDTH"] = RTLIL::Const(when_signal.width);
+       mux_cell->connections["\\A"] = else_signal;
+       mux_cell->connections["\\B"] = when_signal;
+       mux_cell->connections["\\S"] = ctrl_sig;
+       mux_cell->connections["\\Y"] = RTLIL::SigSpec(result_wire);
+
+       last_mux_cell = mux_cell;
+       return RTLIL::SigSpec(result_wire);
+}
+
+static void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw)
+{
+       assert(last_mux_cell != NULL);
+       assert(when_signal.width == last_mux_cell->connections["\\A"].width);
+
+       std::stringstream sstr;
+       sstr << "$procmux$" << (RTLIL::autoidx++);
+
+       RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw);
+       assert(ctrl_sig.width == 1);
+       last_mux_cell->type = "$pmux";
+       last_mux_cell->connections["\\S"].append(ctrl_sig);
+       last_mux_cell->connections["\\B"].append(when_signal);
+       last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->connections["\\S"].width;
+}
+
+static RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval)
+{
+       RTLIL::SigSpec result = defval;
+
+       for (auto &action : cs->actions) {
+               sig.replace(action.first, action.second, &result);
+               action.first.remove2(sig, &action.second);
+       }
+
+       for (auto sw : cs->switches)
+       {
+               // detect groups of parallel cases
+               std::vector<int> pgroups(sw->cases.size());
+               if (sw->attributes.count("\\parallel_case") == 0) {
+                       BitPatternPool pool(sw->signal.width);
+                       bool extra_group_for_next_case = false;
+                       for (size_t i = 0; i < sw->cases.size(); i++) {
+                               RTLIL::CaseRule *cs2 = sw->cases[i];
+                               if (i != 0) {
+                                       pgroups[i] = pgroups[i-1];
+                                       if (extra_group_for_next_case) {
+                                               pgroups[i] = pgroups[i-1]+1;
+                                               extra_group_for_next_case = false;
+                                       }
+                                       for (auto pat : cs2->compare)
+                                               if (!pat.is_fully_const() || !pool.has_all(pat))
+                                                       pgroups[i] = pgroups[i-1]+1;
+                                       if (cs2->compare.empty())
+                                               pgroups[i] = pgroups[i-1]+1;
+                                       if (pgroups[i] != pgroups[i-1])
+                                               pool = BitPatternPool(sw->signal.width);
+                               }
+                               for (auto pat : cs2->compare)
+                                       if (!pat.is_fully_const())
+                                               extra_group_for_next_case = true;
+                                       else
+                                               pool.take(pat);
+                       }
+               }
+
+               // evaluate in reverse order to give the first entry the top priority
+               RTLIL::SigSpec initial_val = result;
+               RTLIL::Cell *last_mux_cell = NULL;
+               for (size_t i = 0; i < sw->cases.size(); i++) {
+                       int case_idx = sw->cases.size() - i - 1;
+                       RTLIL::CaseRule *cs2 = sw->cases[case_idx];
+                       RTLIL::SigSpec value = signal_to_mux_tree(mod, cs2, sig, initial_val);
+                       if (last_mux_cell && pgroups[case_idx] == pgroups[case_idx+1])
+                               append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw);
+                       else
+                               result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw);
+               }
+       }
+
+       return result;
+}
+
+static void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
+{
+       bool first = true;
+       while (1)
+       {
+               RTLIL::SigSpec sig = find_any_lvalue(&proc->root_case);
+
+               if (sig.width == 0)
+                       break;
+
+               if (first) {
+                       log("Creating decoders for process `%s.%s'.\n", mod->name.c_str(), proc->name.c_str());
+                       first = false;
+               }
+
+               extract_core_signal(&proc->root_case, sig);
+
+               log("  creating decoder for signal `%s'.\n", log_signal(sig));
+
+               RTLIL::SigSpec value = signal_to_mux_tree(mod, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.width));
+               mod->connections.push_back(RTLIL::SigSig(sig, value));
+       }
+}
+
+struct ProcMuxPass : public Pass {
+       ProcMuxPass() : Pass("proc_mux") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing PROC_MUX pass (convert decision trees to multiplexers).\n");
+
+               extra_args(args, 1, design);
+
+               for (auto &mod_it : design->modules)
+               for (auto &proc_it : mod_it.second->processes)
+                       proc_mux(mod_it.second, proc_it.second);
+       }
+} ProcMuxPass;
diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc
new file mode 100644 (file)
index 0000000..ca2070c
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  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/bitpattern.h"
+#include "kernel/log.h"
+#include <sstream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <set>
+
+static void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
+{
+       BitPatternPool pool(sw->signal);
+
+       for (size_t i = 0; i < sw->cases.size(); i++)
+       {
+               bool is_default = sw->cases[i]->compare.size() == 0 && !pool.empty();
+
+               for (size_t j = 0; j < sw->cases[i]->compare.size(); j++) {
+                       RTLIL::SigSpec sig = sw->cases[i]->compare[j];
+                       if (!sig.is_fully_const())
+                               continue;
+                       if (!pool.take(sig))
+                               sw->cases[i]->compare.erase(sw->cases[i]->compare.begin() + (j--));
+               }
+
+               if (!is_default) {
+                       if (sw->cases[i]->compare.size() == 0) {
+                               delete sw->cases[i];
+                               sw->cases.erase(sw->cases.begin() + (i--));
+                               counter++;
+                               continue;
+                       }
+                       if (pool.empty())
+                               sw->cases[i]->compare.clear();
+               }
+
+               for (auto switch_it : sw->cases[i]->switches)
+                       proc_rmdead(switch_it, counter);
+
+               if (is_default)
+                       pool.take_all();
+       }
+}
+
+struct ProcRmdeadPass : public Pass {
+       ProcRmdeadPass() : Pass("proc_rmdead") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing PROC_RMDEAD pass (remove dead branches from decision trees).\n");
+
+               extra_args(args, 1, design);
+
+               int total_counter = 0;
+               for (auto &mod_it : design->modules)
+               for (auto &proc_it : mod_it.second->processes) {
+                       int counter = 0;
+                       for (auto switch_it : proc_it.second->root_case.switches)
+                               proc_rmdead(switch_it, counter);
+                       if (counter > 0)
+                               log("Removed %d dead cases from process %s in module %s.\n", counter,
+                                               proc_it.first.c_str(), mod_it.first.c_str());
+                       total_counter += counter;
+               }
+
+               log("Removed a total of %d dead cases.\n", total_counter);
+       }
+} ProcRmdeadPass;
diff --git a/passes/submod/Makefile.inc b/passes/submod/Makefile.inc
new file mode 100644 (file)
index 0000000..b0c00ea
--- /dev/null
@@ -0,0 +1,3 @@
+
+OBJS += passes/submod/submod.o
+
diff --git a/passes/submod/submod.cc b/passes/submod/submod.cc
new file mode 100644 (file)
index 0000000..ba1b4b0
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *  
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/log.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <set>
+
+struct SubmodWorker
+{
+       CellTypes ct;
+       RTLIL::Design *design;
+       RTLIL::Module *module;
+
+       struct SubModule
+       {
+               std::string name, full_name;
+               std::set<RTLIL::Cell*> cells;
+       };
+
+       std::map<std::string, SubModule> submodules;
+
+       struct wire_flags_t {
+               RTLIL::Wire *new_wire;
+               bool is_int_driven, is_int_used, is_ext_driven, is_ext_used;
+               wire_flags_t() : new_wire(NULL), is_int_driven(false), is_int_used(false), is_ext_driven(false), is_ext_used(false) { }
+       };
+       std::map<RTLIL::Wire*, wire_flags_t> wire_flags;
+       bool flag_found_something;
+
+       void flag_wire(RTLIL::Wire *wire, bool create, bool set_int_driven, bool set_int_used, bool set_ext_driven, bool set_ext_used)
+       {
+               if (wire_flags.count(wire) == 0) {
+                       if (!create)
+                               return;
+                       wire_flags[wire] = wire_flags_t();
+               }
+               if (set_int_driven)
+                       wire_flags[wire].is_int_driven = true;
+               if (set_int_used)
+                       wire_flags[wire].is_int_used = true;
+               if (set_ext_driven)
+                       wire_flags[wire].is_ext_driven = true;
+               if (set_ext_used)
+                       wire_flags[wire].is_ext_used = true;
+               flag_found_something = true;
+       }
+
+       void flag_signal(RTLIL::SigSpec &sig, bool create, bool set_int_driven, bool set_int_used, bool set_ext_driven, bool set_ext_used)
+       {
+               for (auto &c : sig.chunks)
+                       if (c.wire != NULL)
+                               flag_wire(c.wire, create, set_int_driven, set_int_used, set_ext_driven, set_ext_used);
+       }
+
+       void handle_submodule(SubModule &submod)
+       {
+               log("Creating submodule %s (%s) of module %s.\n", submod.name.c_str(), submod.full_name.c_str(), module->name.c_str());
+
+               wire_flags.clear();
+               for (RTLIL::Cell *cell : submod.cells) {
+                       if (ct.cell_known(cell->type)) {
+                               for (auto &conn : cell->connections)
+                                       flag_signal(conn.second, true, ct.cell_output(cell->type, conn.first), ct.cell_input(cell->type, conn.first), false, false);
+                       } else {
+                               log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
+                               for (auto &conn : cell->connections)
+                                       flag_signal(conn.second, true, true, true, false, false);
+                       }
+               }
+               for (auto &it : module->cells) {
+                       RTLIL::Cell *cell = it.second;
+                       if (submod.cells.count(cell) > 0)
+                               continue;
+                       if (ct.cell_known(cell->type)) {
+                               for (auto &conn : cell->connections)
+                                       flag_signal(conn.second, false, false, false, ct.cell_output(cell->type, conn.first), ct.cell_input(cell->type, conn.first));
+                       } else {
+                               flag_found_something = false;
+                               for (auto &conn : cell->connections)
+                                       flag_signal(conn.second, false, false, false, true, true);
+                               if (flag_found_something)
+                                       log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
+                       }
+               }
+
+               RTLIL::Module *new_mod = new RTLIL::Module;
+               new_mod->name = submod.full_name;
+               design->modules[new_mod->name] = new_mod;
+               int port_counter = 1, auto_name_counter = 1;
+
+               std::set<std::string> all_wire_names;
+               for (auto &it : wire_flags) {
+                       all_wire_names.insert(it.first->name);
+               }
+
+               for (auto &it : wire_flags)
+               {
+                       RTLIL::Wire *wire = it.first;
+                       wire_flags_t &flags = it.second;
+
+                       if (wire->port_input)
+                               flags.is_ext_driven = true;
+                       if (wire->port_output)
+                               flags.is_ext_used = true;
+
+                       RTLIL::Wire *new_wire = new RTLIL::Wire;
+                       new_wire->name = wire->name;
+                       new_wire->width = wire->width;
+                       new_wire->start_offset = wire->start_offset;
+                       new_wire->attributes = wire->attributes;
+
+                       if (flags.is_int_driven && flags.is_ext_used)
+                               new_wire->port_output = true;
+                       if (flags.is_ext_driven && flags.is_int_used)
+                               new_wire->port_input = true;
+
+                       if (flags.is_int_driven && flags.is_ext_driven)
+                               new_wire->port_input = true, new_wire->port_output = true;
+
+                       if (new_wire->port_input || new_wire->port_output) {
+                               new_wire->port_id = port_counter++;
+                               while (new_wire->name[0] == '$') {
+                                       std::string new_wire_name = stringf("\\n%d", auto_name_counter++);
+                                       if (all_wire_names.count(new_wire_name) == 0) {
+                                               all_wire_names.insert(new_wire_name);
+                                               new_wire->name = new_wire_name;
+                                       }
+                               }
+                       }
+
+                       if (new_wire->port_input && new_wire->port_output)
+                               log("  signal %s: inout %s\n", wire->name.c_str(), new_wire->name.c_str());
+                       else if (new_wire->port_input)
+                               log("  signal %s: input %s\n", wire->name.c_str(), new_wire->name.c_str());
+                       else if (new_wire->port_output)
+                               log("  signal %s: output %s\n", wire->name.c_str(), new_wire->name.c_str());
+                       else
+                               log("  signal %s: internal\n", wire->name.c_str());
+
+                       new_mod->wires[new_wire->name] = new_wire;
+                       flags.new_wire = new_wire;
+               }
+
+               for (RTLIL::Cell *cell : submod.cells) {
+                       RTLIL::Cell *new_cell = new RTLIL::Cell(*cell);
+                       for (auto &conn : new_cell->connections)
+                               for (auto &c : conn.second.chunks)
+                                       if (c.wire != NULL) {
+                                               assert(wire_flags.count(c.wire) > 0);
+                                               c.wire = wire_flags[c.wire].new_wire;
+                                       }
+                       log("  cell %s (%s)\n", new_cell->name.c_str(), new_cell->type.c_str());
+                       new_mod->cells[new_cell->name] = new_cell;
+                       module->cells.erase(cell->name);
+                       delete cell;
+               }
+               submod.cells.clear();
+
+               RTLIL::Cell *new_cell = new RTLIL::Cell;
+               new_cell->name = submod.full_name;
+               new_cell->type = submod.full_name;
+               for (auto &it : wire_flags)
+               {
+                       RTLIL::Wire *old_wire = it.first;
+                       RTLIL::Wire *new_wire = it.second.new_wire;
+                       if (new_wire->port_id > 0)
+                               new_cell->connections[new_wire->name] = RTLIL::SigSpec(old_wire);
+               }
+               module->cells[new_cell->name] = new_cell;
+       }
+
+       SubmodWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module)
+       {
+               if (!design->selected_whole_module(module->name))
+                       return;
+
+               if (module->processes.size() > 0) {
+                       log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
+                       return;
+               }
+
+               if (module->memories.size() > 0) {
+                       log("Skipping module %s as it contains memories (run 'memory' pass first).\n", module->name.c_str());
+                       return;
+               }
+
+               ct.setup_internals();
+               ct.setup_internals_mem();
+               ct.setup_stdcells();
+               ct.setup_stdcells_mem();
+
+               for (auto &it : module->wires)
+                       it.second->attributes.erase("\\submod");
+
+               for (auto &it : module->cells)
+               {
+                       RTLIL::Cell *cell = it.second;
+                       if (cell->attributes.count("\\submod") == 0 || cell->attributes["\\submod"].str.size() == 0) {
+                               cell->attributes.erase("\\submod");
+                               continue;
+                       }
+
+                       std::string submod_str = cell->attributes["\\submod"].str;
+                       cell->attributes.erase("\\submod");
+
+                       if (submodules.count(submod_str) == 0) {
+                               submodules[submod_str].name = submod_str;
+                               submodules[submod_str].full_name = module->name + "_" + submod_str;
+                               while (design->modules.count(submodules[submod_str].full_name) != 0 ||
+                                               module->count_id(submodules[submod_str].full_name) != 0)
+                                       submodules[submod_str].full_name += "_";
+                       }
+
+                       submodules[submod_str].cells.insert(cell);
+               }
+
+               for (auto &it : submodules)
+                       handle_submodule(it.second);
+       }
+};
+
+struct SubmodPass : public Pass {
+       SubmodPass() : Pass("submod") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing SUBMOD pass (moving cells to submodes as requested).\n");
+               log_push();
+
+               Pass::call(design, "opt_rmunused");
+               log_header("Continuing SUBMOD pass.\n");
+
+               extra_args(args, 1, design);
+
+               std::set<std::string> handled_modules;
+
+               bool did_something = true;
+               while (did_something) {
+                       did_something = false;
+                       std::vector<std::string> queued_modules;
+                       for (auto &mod_it : design->modules)
+                               if (handled_modules.count(mod_it.first) == 0)
+                                       queued_modules.push_back(mod_it.first);
+                       for (auto &modname : queued_modules)
+                               if (design->modules.count(modname) != 0) {
+                                       SubmodWorker worker(design, design->modules[modname]);
+                                       handled_modules.insert(modname);
+                                       did_something = true;
+                               }
+               }
+
+               Pass::call(design, "opt_rmunused");
+       }
+} SubmodPass;
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
new file mode 100644 (file)
index 0000000..ba36552
--- /dev/null
@@ -0,0 +1,11 @@
+
+GENFILES += passes/techmap/stdcells.inc
+OBJS += passes/techmap/techmap.o
+
+passes/techmap/stdcells.inc: techlibs/stdcells.v
+       od -v -td1 -w1 $< | awk 'BEGIN { print "static char stdcells_code[] = {"; } $$2 != "" { print $$2 ","; } \
+                       END { print 0 "};"; }' | fmt > $@.new
+       mv $@.new $@
+
+passes/techmap/techmap.o: passes/techmap/stdcells.inc
+
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
new file mode 100644 (file)
index 0000000..99fa15b
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ *  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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "passes/techmap/stdcells.inc"
+
+static void apply_prefix(std::string prefix, std::string &id)
+{
+       if (id[0] == '\\')
+               id = prefix + "." + id.substr(1);
+       else
+               id = prefix + "." + id;
+}
+
+static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
+{
+       for (size_t i = 0; i < sig.chunks.size(); i++) {
+               if (sig.chunks[i].wire == NULL)
+                       continue;
+               std::string wire_name = sig.chunks[i].wire->name;
+               apply_prefix(prefix, wire_name);
+               assert(module->wires.count(wire_name) > 0);
+               sig.chunks[i].wire = module->wires[wire_name];
+       }
+}
+
+std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
+
+static bool techmap_module(RTLIL::Module *module, RTLIL::Design *map)
+{
+       bool did_something = false;
+
+       std::vector<std::string> cell_names;
+
+       for (auto &cell_it : module->cells)
+               cell_names.push_back(cell_it.first);
+
+       for (auto &cell_name : cell_names)
+       {
+               if (module->cells.count(cell_name) == 0)
+                       continue;
+
+               RTLIL::Cell *cell = module->cells[cell_name];
+
+               if (map->modules.count(cell->type) == 0)
+                       continue;
+
+               RTLIL::Module *tpl = map->modules[cell->type];
+               std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(cell->type, cell->parameters);
+
+               if (techmap_cache.count(key) > 0) {
+                       tpl = techmap_cache[key];
+               } else {
+                       std::string derived_name = cell->type;
+                       if (cell->parameters.size() != 0) {
+                               derived_name = tpl->derive(map, cell->parameters);
+                               tpl = map->modules[derived_name];
+                               log_header("Continuing TECHMAP pass.\n");
+                       }
+                       for (auto &cit : tpl->cells)
+                               if (cit.second->type == "\\TECHMAP_FAILED") {
+                                       log("Not using module `%s' from techmap as it contains a TECHMAP_FAILED marker cell.\n", derived_name.c_str());
+                                       tpl = NULL;
+                                       break;
+                               }
+                       techmap_cache[key] = tpl;
+               }
+
+               if (tpl == NULL)
+                       goto next_cell;
+
+               log("Mapping `%s.%s' using `%s'.\n", module->name.c_str(), cell_name.c_str(), tpl->name.c_str());
+
+               if (tpl->memories.size() != 0)
+                       log_error("Technology map yielded memories -> this is not supported.");
+
+               if (tpl->processes.size() != 0)
+                       log_error("Technology map yielded processes -> this is not supported.");
+
+               for (auto &it : tpl->wires) {
+                       RTLIL::Wire *w = new RTLIL::Wire(*it.second);
+                       apply_prefix(cell_name, w->name);
+                       w->port_input = false;
+                       w->port_output = false;
+                       w->port_id = 0;
+                       module->wires[w->name] = w;
+               }
+
+               for (auto &it : tpl->cells) {
+                       RTLIL::Cell *c = new RTLIL::Cell(*it.second);
+                       if (c->type.substr(0, 2) == "\\$")
+                               c->type = c->type.substr(1);
+                       apply_prefix(cell_name, c->name);
+                       for (auto &it2 : c->connections)
+                               apply_prefix(cell_name, it2.second, module);
+                       module->cells[c->name] = c;
+               }
+
+               for (auto &it : tpl->connections) {
+                       RTLIL::SigSig c = it;
+                       apply_prefix(cell_name, c.first, module);
+                       apply_prefix(cell_name, c.second, module);
+                       module->connections.push_back(c);
+               }
+
+               for (auto &it : cell->connections) {
+                       assert(tpl->wires.count(it.first));
+                       assert(tpl->wires[it.first]->port_id > 0);
+                       RTLIL::Wire *w = tpl->wires[it.first];
+                       RTLIL::SigSig c;
+                       if (w->port_output) {
+                               c.first = it.second;
+                               c.second = RTLIL::SigSpec(w);
+                               apply_prefix(cell_name, c.second, module);
+                       } else {
+                               c.first = RTLIL::SigSpec(w);
+                               c.second = it.second;
+                               apply_prefix(cell_name, c.first, module);
+                       }
+                       if (c.second.width > c.first.width)
+                               c.second.remove(c.first.width, c.second.width - c.first.width);
+                       if (c.second.width < c.first.width)
+                               c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.width - c.second.width));
+                       assert(c.first.width == c.second.width);
+                       module->connections.push_back(c);
+               }
+
+               delete cell;
+               module->cells.erase(cell_name);
+               did_something = true;
+       next_cell:;
+       }
+
+       return did_something;
+}
+
+struct TechmapPass : public Pass {
+       TechmapPass() : Pass("techmap") { }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing TECHMAP pass (map to technology primitives).\n");
+               log_push();
+
+               std::string filename;
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       if (args[argidx] == "-map" && argidx+1 < args.size()) {
+                               filename = args[++argidx];
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               RTLIL::Design *map = new RTLIL::Design;
+               FILE *f = filename.empty() ? fmemopen(stdcells_code, strlen(stdcells_code), "rt") : fopen(filename.c_str(), "rt");
+               if (f == NULL)
+                       log_error("Can't open map file `%s'\n", filename.c_str());
+               Frontend::frontend_call(map, f, filename.empty() ? "<stdcells.v>" : filename, "verilog");
+               fclose(f);
+
+               std::map<RTLIL::IdString, RTLIL::Module*> modules_new;
+               for (auto &it : map->modules) {
+                       if (it.first.substr(0, 2) == "\\$")
+                               it.second->name = it.first.substr(1);
+                       modules_new[it.second->name] = it.second;
+               }
+               map->modules.swap(modules_new);
+
+               bool did_something = true;
+               while (did_something) {
+                       did_something = false;
+                       for (auto &mod_it : design->modules)
+                               if (techmap_module(mod_it.second, map))
+                                       did_something = true;
+               }
+
+               log("No more expansions possible.\n");
+               techmap_cache.clear();
+               delete map;
+               log_pop();
+       }
+} TechmapPass;
diff --git a/techlibs/Makefile.inc b/techlibs/Makefile.inc
new file mode 100644 (file)
index 0000000..031a4ad
--- /dev/null
@@ -0,0 +1,7 @@
+
+TARGETS += techlibs/blackbox.v
+
+techlibs/blackbox.v: techlibs/blackbox.sed techlibs/simlib.v techlibs/stdcells_sim.v
+       cat techlibs/simlib.v techlibs/stdcells_sim.v | sed -rf techlibs/blackbox.sed > techlibs/blackbox.v.new
+       mv techlibs/blackbox.v.new techlibs/blackbox.v
+
diff --git a/techlibs/blackbox.sed b/techlibs/blackbox.sed
new file mode 100644 (file)
index 0000000..4e9a3a7
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sed -r
+/^(wire|assign|reg)/ d;
+/^(genvar|always|initial)/,/^end/ d;
+s/ reg / /;
diff --git a/techlibs/simlib.v b/techlibs/simlib.v
new file mode 100644 (file)
index 0000000..1792425
--- /dev/null
@@ -0,0 +1,892 @@
+/*
+ *  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 Simulation Library.
+ *
+ *  This verilog library contains simple simulation models for the internal
+ *  cells ($not, ...) generated by the frontends and used in most passes.
+ *
+ *  This library can be used to verify the internal netlists as generated
+ *  by the different frontends and passes.
+ *
+ *  Note that memory can only be simulated when all $memrd and $memwr cells
+ *  have been merged to stand-alone $mem cells (this is what the "memory_collect"
+ *  pass is doing).
+ *
+ */
+
+`define INPUT_A \
+input [A_WIDTH-1:0] A; \
+generate if (A_SIGNED) begin:A_BUF wire signed [A_WIDTH-1:0] val = A; end else begin:A_BUF wire [A_WIDTH-1:0] val = A; end endgenerate
+
+`define INPUT_B \
+input [B_WIDTH-1:0] B; \
+generate if (B_SIGNED) begin:B_BUF wire signed [B_WIDTH-1:0] val = B; end else begin:B_BUF wire [B_WIDTH-1:0] val = B; end endgenerate
+
+// --------------------------------------------------------
+
+module \$not (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+output [Y_WIDTH-1:0] Y;
+
+assign Y = ~A_BUF.val;
+
+endmodule
+
+
+// --------------------------------------------------------
+
+module \$pos (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+output [Y_WIDTH-1:0] Y;
+
+assign Y = +A_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$neg (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+output [Y_WIDTH-1:0] Y;
+
+assign Y = -A_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$and (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val & B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$or (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val | B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$xor (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val ^ B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$xnor (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val ~^ B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$reduce_and (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+output Y;
+
+assign Y = &A_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$reduce_or (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+output Y;
+
+assign Y = |A_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$reduce_xor (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+output Y;
+
+assign Y = ^A_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$reduce_xnor (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+output Y;
+
+assign Y = ~^A_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$reduce_bool (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+output Y;
+
+assign Y = A_BUF.val != 0;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$shl (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val << B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$shr (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val >> B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$sshl (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val <<< B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$sshr (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val >>> B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$lt (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val < B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$le (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val <= B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$eq (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val == B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$ne (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val != B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$ge (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val >= B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$gt (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val > B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$add (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val + B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$sub (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val - B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$mul (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val * B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$div (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val / B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$mod (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val % B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$pow (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val ** B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$logic_not (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+output [Y_WIDTH-1:0] Y;
+
+assign Y = !A_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$logic_and (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val && B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$logic_or (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+`INPUT_A
+`INPUT_B
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val || B_BUF.val;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$mux (A, B, S, Y);
+
+parameter WIDTH = 0;
+
+input [WIDTH-1:0] A, B;
+input S;
+output reg [WIDTH-1:0] Y;
+
+always @* begin
+       if (S)
+               Y = B;
+       else
+               Y = A;
+end
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$pmux (A, B, S, Y);
+
+parameter WIDTH = 0;
+parameter S_WIDTH = 0;
+
+input [WIDTH-1:0] A;
+input [WIDTH*S_WIDTH-1:0] B;
+input [S_WIDTH-1:0] S;
+output reg [WIDTH-1:0] Y;
+
+integer i;
+
+always @* begin
+       Y = A;
+       for (i = 0; i < S_WIDTH; i = i+1)
+               if (S[i])
+                       Y = B >> (WIDTH*i);
+end
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$safe_pmux (A, B, S, Y);
+
+parameter WIDTH = 0;
+parameter S_WIDTH = 0;
+
+input [WIDTH-1:0] A;
+input [WIDTH*S_WIDTH-1:0] B;
+input [S_WIDTH-1:0] S;
+output reg [WIDTH-1:0] Y;
+
+integer i, j;
+
+always @* begin
+       j = 0;
+       for (i = 0; i < S_WIDTH; i = i+1)
+               if (S[i]) begin
+                       Y = B >> (WIDTH*i);
+                       j = j + 1;
+               end
+       if (j != 1)
+               Y = A;
+end
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$dff (CLK, D, Q);
+
+parameter WIDTH = 0;
+parameter CLK_POLARITY = 1'b1;
+
+input CLK;
+input [WIDTH-1:0] D;
+output reg [WIDTH-1:0] Q;
+wire pos_clk = CLK == CLK_POLARITY;
+
+always @(posedge pos_clk) begin
+       Q <= D;
+end
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$adff (CLK, ARST, D, Q);
+
+parameter WIDTH = 0;
+parameter CLK_POLARITY = 1'b1;
+parameter ARST_POLARITY = 1'b1;
+parameter ARST_VALUE = 0;
+
+input CLK, ARST;
+input [WIDTH-1:0] D;
+output reg [WIDTH-1:0] Q;
+wire pos_clk = CLK == CLK_POLARITY;
+wire pos_arst = ARST == ARST_POLARITY;
+
+always @(posedge pos_clk, posedge pos_arst) begin
+       if (pos_arst)
+               Q <= ARST_VALUE;
+       else
+               Q <= D;
+end
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$fsm (CLK, ARST, CTRL_IN, CTRL_OUT);
+
+parameter NAME = "";
+
+parameter CLK_POLARITY = 1'b1;
+parameter ARST_POLARITY = 1'b1;
+
+parameter CTRL_IN_WIDTH = 1;
+parameter CTRL_OUT_WIDTH = 1;
+
+parameter STATE_BITS = 1;
+parameter STATE_NUM = 1;
+parameter STATE_NUM_LOG2 = 1;
+parameter STATE_RST = 0;
+parameter STATE_TABLE = 1'b0;
+
+parameter TRANS_NUM = 1;
+parameter TRANS_TABLE = 4'b0x0x;
+
+input CLK, ARST;
+input [CTRL_IN_WIDTH-1:0] CTRL_IN;
+output reg [CTRL_OUT_WIDTH-1:0] CTRL_OUT;
+
+wire pos_clk = CLK == CLK_POLARITY;
+wire pos_arst = ARST == ARST_POLARITY;
+
+reg [STATE_BITS-1:0] state;
+reg [STATE_BITS-1:0] state_tmp;
+reg [STATE_BITS-1:0] next_state;
+
+reg [STATE_BITS-1:0] tr_state_in;
+reg [STATE_BITS-1:0] tr_state_out;
+reg [CTRL_IN_WIDTH-1:0] tr_ctrl_in;
+reg [CTRL_OUT_WIDTH-1:0] tr_ctrl_out;
+
+integer i;
+
+task tr_fetch;
+       input [31:0] tr_num;
+       reg [31:0] tr_pos;
+       reg [STATE_NUM_LOG2-1:0] state_num;
+       begin
+               tr_pos = (2*STATE_NUM_LOG2+CTRL_IN_WIDTH+CTRL_OUT_WIDTH)*tr_num;
+               tr_ctrl_out = TRANS_TABLE >> tr_pos;
+               tr_pos = tr_pos + CTRL_OUT_WIDTH;
+               state_num = TRANS_TABLE >> tr_pos;
+               tr_state_out = STATE_TABLE >> (STATE_BITS*state_num);
+               tr_pos = tr_pos + STATE_NUM_LOG2;
+               tr_ctrl_in = TRANS_TABLE >> tr_pos;
+               tr_pos = tr_pos + CTRL_IN_WIDTH;
+               state_num = TRANS_TABLE >> tr_pos;
+               tr_state_in = STATE_TABLE >> (STATE_BITS*state_num);
+               tr_pos = tr_pos + STATE_NUM_LOG2;
+       end
+endtask
+
+always @(posedge pos_clk, posedge pos_arst) begin
+       if (pos_arst)
+               state_tmp = STATE_TABLE[STATE_BITS*(STATE_RST+1)-1:STATE_BITS*STATE_RST];
+       else
+               state_tmp = next_state;
+       for (i = 0; i < STATE_BITS; i = i+1)
+               if (state_tmp[i] === 1'bz)
+                       state_tmp[i] = 0;
+       state <= state_tmp;
+end
+
+always @(state, CTRL_IN) begin
+       next_state <= STATE_TABLE[STATE_BITS*(STATE_RST+1)-1:STATE_BITS*STATE_RST];
+       CTRL_OUT <= 'bx;
+       // $display("---");
+       // $display("Q: %b %b", state, CTRL_IN);
+       for (i = 0; i < TRANS_NUM; i = i+1) begin
+               tr_fetch(i);
+               // $display("T: %b %b -> %b %b [%d]", tr_state_in, tr_ctrl_in, tr_state_out, tr_ctrl_out, i);
+               casez ({state, CTRL_IN})
+                       {tr_state_in, tr_ctrl_in}: begin
+                               // $display("-> %b %b <-   MATCH", state, CTRL_IN);
+                               {next_state, CTRL_OUT} <= {tr_state_out, tr_ctrl_out};
+                       end
+               endcase
+       end
+end
+
+endmodule
+
+// --------------------------------------------------------
+`ifndef SIMLIB_NOMEM
+
+module \$memrd (CLK, ADDR, DATA);
+
+parameter MEMID = "";
+parameter ABITS = 8;
+parameter WIDTH = 8;
+
+parameter RD_CLK_ENABLE = 0;
+parameter RD_CLK_POLARITY = 0;
+
+input CLK;
+input [ABITS-1:0] ADDR;
+output [WIDTH-1:0] DATA;
+
+initial begin
+       $display("ERROR: Found non-simulatable instance of $memrd!");
+       $finish;
+end
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$memwr (CLK, EN, ADDR, DATA);
+
+parameter MEMID = "";
+parameter ABITS = 8;
+parameter WIDTH = 8;
+
+parameter RD_CLK_ENABLE = 0;
+parameter RD_CLK_POLARITY = 0;
+
+input CLK, EN;
+input [ABITS-1:0] ADDR;
+input [WIDTH-1:0] DATA;
+
+initial begin
+       $display("ERROR: Found non-simulatable instance of $memwr!");
+       $finish;
+end
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
+
+parameter MEMID = "";
+parameter SIZE = 256;
+parameter ABITS = 8;
+parameter WIDTH = 8;
+
+parameter RD_PORTS = 1;
+parameter RD_CLK_ENABLE = 1'b1;
+parameter RD_CLK_POLARITY = 1'b1;
+
+parameter WR_PORTS = 1;
+parameter WR_CLK_ENABLE = 1'b1;
+parameter WR_CLK_POLARITY = 1'b1;
+
+input [RD_PORTS-1:0] RD_CLK;
+input [RD_PORTS*ABITS-1:0] RD_ADDR;
+output reg [RD_PORTS*WIDTH-1:0] RD_DATA;
+
+input [WR_PORTS-1:0] WR_CLK, WR_EN;
+input [WR_PORTS*ABITS-1:0] WR_ADDR;
+input [WR_PORTS*WIDTH-1:0] WR_DATA;
+
+reg [WIDTH-1:0] data [SIZE-1:0];
+event update_async_rd;
+
+genvar i;
+generate
+
+       for (i = 0; i < RD_PORTS; i = i+1) begin:rd
+               if (RD_CLK_ENABLE[i] == 0) begin:rd_noclk
+                       always @(RD_ADDR or update_async_rd)
+                               RD_DATA[ (i+1)*WIDTH-1 : i*WIDTH ] <= data[ RD_ADDR[ (i+1)*ABITS-1 : i*ABITS ] ];
+               end else
+               if (RD_CLK_POLARITY[i] == 1) begin:rd_posclk
+                       always @(posedge RD_CLK[i])
+                               RD_DATA[ (i+1)*WIDTH-1 : i*WIDTH ] <= data[ RD_ADDR[ (i+1)*ABITS-1 : i*ABITS ] ];
+               end else begin:rd_negclk
+                       always @(negedge RD_CLK[i])
+                               RD_DATA[ (i+1)*WIDTH-1 : i*WIDTH ] <= data[ RD_ADDR[ (i+1)*ABITS-1 : i*ABITS ] ];
+               end
+       end
+
+       for (i = 0; i < WR_PORTS; i = i+1) begin:wr
+               if (WR_CLK_ENABLE[i] == 0) begin:wr_noclk
+                       always @(WR_ADDR or WR_DATA or WR_EN) begin
+                               if (WR_EN[i]) begin
+                                       data[ WR_ADDR[ (i+1)*ABITS-1 : i*ABITS ] ] <= WR_DATA[ (i+1)*WIDTH-1 : i*WIDTH ];
+                                       #1 -> update_async_rd;
+                               end
+                       end
+               end else
+               if (RD_CLK_POLARITY[i] == 1) begin:rd_posclk
+                       always @(posedge WR_CLK[i])
+                               if (WR_EN[i]) begin
+                                       data[ WR_ADDR[ (i+1)*ABITS-1 : i*ABITS ] ] <= WR_DATA[ (i+1)*WIDTH-1 : i*WIDTH ];
+                                       #1 -> update_async_rd;
+                               end
+               end else begin:rd_negclk
+                       always @(negedge WR_CLK[i])
+                               if (WR_EN[i]) begin
+                                       data[ WR_ADDR[ (i+1)*ABITS-1 : i*ABITS ] ] <= WR_DATA[ (i+1)*WIDTH-1 : i*WIDTH ];
+                                       #1 -> update_async_rd;
+                               end
+               end
+       end
+
+endgenerate
+
+endmodule
+
+`endif
+// --------------------------------------------------------
diff --git a/techlibs/stdcells.v b/techlibs/stdcells.v
new file mode 100644 (file)
index 0000000..9733c37
--- /dev/null
@@ -0,0 +1,1378 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *  
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *  ---
+ *
+ *  The internal logic cell technology mapper.
+ *
+ *  This verilog library contains the mapping of internal cells (e.g. $not with
+ *  variable bit width) to the internal logic cells (such as the single bit $_INV_ 
+ *  gate). Usually this logic network is then mapped to the actual technology
+ *  using e.g. the "abc" pass.
+ *
+ *  Note that this library does not map $mem cells. They must be mapped to logic
+ *  and $dff cells using the "memory_map" pass first. (Or map it to custom cells,
+ *  which is of course highly recommended for larger memories.)
+ *
+ */
+
+// --------------------------------------------------------
+
+module \$not (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+output [Y_WIDTH-1:0] Y;
+
+genvar i;
+generate
+       for (i = 0; i < Y_WIDTH; i = i + 1) begin:V
+               if (i < A_WIDTH) begin
+                        \$_INV_ gate (
+                               .A(A[i]),
+                               .Y(Y[i])
+                       );
+               end else begin
+                       assign Y[i] = 0;
+               end
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$pos (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+output [Y_WIDTH-1:0] Y;
+
+genvar i;
+generate
+       for (i = 0; i < Y_WIDTH; i = i + 1) begin:V
+               if (i < A_WIDTH) begin
+                       assign Y[i] = A[i];
+               end else if (A_SIGNED) begin
+                       assign Y[i] = A[A_WIDTH-1];
+               end else begin
+                       assign Y[i] = 0;
+               end
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$neg (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+output [Y_WIDTH-1:0] Y;
+
+\$sub #(
+       .A_SIGNED(A_SIGNED),
+       .B_SIGNED(A_SIGNED),
+       .A_WIDTH(1),
+       .B_WIDTH(A_WIDTH),
+       .Y_WIDTH(Y_WIDTH)
+) sub (
+       .A(0),
+       .B(A),
+       .Y(Y)
+);
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$and (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire [Y_WIDTH-1:0] A_buf, B_buf;
+\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+genvar i;
+generate
+       for (i = 0; i < Y_WIDTH; i = i + 1) begin:V
+                \$_AND_ gate (
+                       .A(A_buf[i]),
+                       .B(B_buf[i]),
+                       .Y(Y[i])
+               );
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$or (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire [Y_WIDTH-1:0] A_buf, B_buf;
+\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+genvar i;
+generate
+       for (i = 0; i < Y_WIDTH; i = i + 1) begin:V
+                \$_OR_ gate (
+                       .A(A_buf[i]),
+                       .B(B_buf[i]),
+                       .Y(Y[i])
+               );
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$xor (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire [Y_WIDTH-1:0] A_buf, B_buf;
+\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+genvar i;
+generate
+       for (i = 0; i < Y_WIDTH; i = i + 1) begin:V
+                \$_XOR_ gate (
+                       .A(A_buf[i]),
+                       .B(B_buf[i]),
+                       .Y(Y[i])
+               );
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$xnor (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire [Y_WIDTH-1:0] A_buf, B_buf;
+\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+genvar i;
+generate
+       for (i = 0; i < Y_WIDTH; i = i + 1) begin:V
+               wire tmp;
+                \$_XOR_ gate1 (
+                       .A(A_buf[i]),
+                       .B(B_buf[i]),
+                       .Y(tmp)
+               );
+                \$_INV_ gate2 (
+                       .A(tmp),
+                       .Y(Y[i])
+               );
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$reduce_and (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+output Y;
+
+wire [A_WIDTH-1:0] buffer;
+
+genvar i;
+generate
+       for (i = 1; i < A_WIDTH; i = i + 1) begin:V
+                \$_AND_ gate (
+                       .A(A[i]),
+                       .B(buffer[i-1]),
+                       .Y(buffer[i])
+               );
+       end
+endgenerate
+
+assign buffer[0] = A[0];
+assign Y = buffer[A_WIDTH-1];
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$reduce_or (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+output Y;
+
+wire [A_WIDTH-1:0] buffer;
+
+genvar i;
+generate
+       for (i = 1; i < A_WIDTH; i = i + 1) begin:V
+                \$_OR_ gate (
+                       .A(A[i]),
+                       .B(buffer[i-1]),
+                       .Y(buffer[i])
+               );
+       end
+endgenerate
+
+assign buffer[0] = A[0];
+assign Y = buffer[A_WIDTH-1];
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$reduce_xor (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+output Y;
+
+wire [A_WIDTH-1:0] buffer;
+
+genvar i;
+generate
+       for (i = 1; i < A_WIDTH; i = i + 1) begin:V
+                \$_XOR_ gate (
+                       .A(A[i]),
+                       .B(buffer[i-1]),
+                       .Y(buffer[i])
+               );
+       end
+endgenerate
+
+assign buffer[0] = A[0];
+assign Y = buffer[A_WIDTH-1];
+
+endmodule
+
+
+// --------------------------------------------------------
+
+module \$reduce_xnor (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+output Y;
+
+wire [A_WIDTH-1:0] buffer;
+
+genvar i;
+generate
+       for (i = 1; i < A_WIDTH; i = i + 1) begin:V
+                \$_XOR_ gate (
+                       .A(A[i]),
+                       .B(buffer[i-1]),
+                       .Y(buffer[i])
+               );
+       end
+endgenerate
+
+assign buffer[0] = A[0];
+ \$_INV_ gate_inv (
+       .A(buffer[A_WIDTH-1]),
+       .Y(Y)
+);
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$reduce_bool (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+output Y;
+
+wire [A_WIDTH-1:0] buffer;
+
+genvar i;
+generate
+       for (i = 1; i < A_WIDTH; i = i + 1) begin:V
+                \$_OR_ gate (
+                       .A(A[i]),
+                       .B(buffer[i-1]),
+                       .Y(buffer[i])
+               );
+       end
+endgenerate
+
+assign buffer[0] = A[0];
+assign Y = buffer[A_WIDTH-1];
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$shift (X, A, Y);
+
+parameter WIDTH = 1;
+parameter SHIFT = 0;
+
+input X;
+input [WIDTH-1:0] A;
+output [WIDTH-1:0] Y;
+
+genvar i;
+generate
+       for (i = 0; i < WIDTH; i = i + 1) begin:V
+               if (i+SHIFT < 0) begin
+                       assign Y[i] = 0;
+               end else
+               if (i+SHIFT < WIDTH) begin
+                       assign Y[i] = A[i+SHIFT];
+               end else begin
+                       assign Y[i] = X;
+               end
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$shl (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+parameter WIDTH = Y_WIDTH;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+genvar i;
+generate
+       wire [WIDTH*(B_WIDTH+1)-1:0] chain;
+       \$pos #(
+               .A_SIGNED(A_SIGNED),
+               .A_WIDTH(A_WIDTH),
+               .Y_WIDTH(WIDTH)
+       ) expand (
+               .A(A),
+               .Y(chain[WIDTH-1:0])
+       );
+       assign Y = chain[WIDTH*(B_WIDTH+1)-1 : WIDTH*B_WIDTH];
+       for (i = 0; i < B_WIDTH; i = i + 1) begin:V
+               wire [WIDTH-1:0] unshifted, shifted, result;
+               assign unshifted = chain[WIDTH*i + WIDTH-1 : WIDTH*i];
+               assign chain[WIDTH*(i+1) + WIDTH-1 : WIDTH*(i+1)] = result;
+               \$shift #(
+                       .WIDTH(WIDTH),
+                       .SHIFT(0 - (2 ** i))
+               ) sh (
+                       .X(0),
+                       .A(unshifted),
+                       .Y(shifted)
+               );
+               \$mux #(
+                       .WIDTH(WIDTH)
+               ) mux (
+                       .A(unshifted),
+                       .B(shifted),
+                       .Y(result),
+                       .S(B[i])
+               );
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$shr (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+parameter WIDTH = A_WIDTH > Y_WIDTH ? A_WIDTH : Y_WIDTH;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+genvar i;
+generate
+       wire [WIDTH*(B_WIDTH+1)-1:0] chain;
+       \$pos #(
+               .A_SIGNED(A_SIGNED),
+               .A_WIDTH(A_WIDTH),
+               .Y_WIDTH(WIDTH)
+       ) expand (
+               .A(A),
+               .Y(chain[WIDTH-1:0])
+       );
+       assign Y = chain[WIDTH*(B_WIDTH+1)-1 : WIDTH*B_WIDTH];
+       for (i = 0; i < B_WIDTH; i = i + 1) begin:V
+               wire [WIDTH-1:0] unshifted, shifted, result;
+               assign unshifted = chain[WIDTH*i + WIDTH-1 : WIDTH*i];
+               assign chain[WIDTH*(i+1) + WIDTH-1 : WIDTH*(i+1)] = result;
+               \$shift #(
+                       .WIDTH(WIDTH),
+                       .SHIFT(2 ** i)
+               ) sh (
+                       .X(0),
+                       .A(unshifted),
+                       .Y(shifted)
+               );
+               \$mux #(
+                       .WIDTH(WIDTH)
+               ) mux (
+                       .A(unshifted),
+                       .B(shifted),
+                       .Y(result),
+                       .S(B[i])
+               );
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$sshl (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+parameter WIDTH = Y_WIDTH;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+genvar i;
+generate
+       wire [WIDTH*(B_WIDTH+1)-1:0] chain;
+       \$pos #(
+               .A_SIGNED(A_SIGNED),
+               .A_WIDTH(A_WIDTH),
+               .Y_WIDTH(WIDTH)
+       ) expand (
+               .A(A),
+               .Y(chain[WIDTH-1:0])
+       );
+       assign Y = chain[WIDTH*(B_WIDTH+1)-1 : WIDTH*B_WIDTH];
+       for (i = 0; i < B_WIDTH; i = i + 1) begin:V
+               wire [WIDTH-1:0] unshifted, shifted, result;
+               assign unshifted = chain[WIDTH*i + WIDTH-1 : WIDTH*i];
+               assign chain[WIDTH*(i+1) + WIDTH-1 : WIDTH*(i+1)] = result;
+               \$shift #(
+                       .WIDTH(WIDTH),
+                       .SHIFT(0 - (2 ** i))
+               ) sh (
+                       .X(0),
+                       .A(unshifted),
+                       .Y(shifted)
+               );
+               \$mux #(
+                       .WIDTH(WIDTH)
+               ) mux (
+                       .A(unshifted),
+                       .B(shifted),
+                       .Y(result),
+                       .S(B[i])
+               );
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$sshr (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+parameter WIDTH = A_WIDTH > Y_WIDTH ? A_WIDTH : Y_WIDTH;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+genvar i;
+generate
+       wire [WIDTH*(B_WIDTH+1)-1:0] chain;
+       \$pos #(
+               .A_SIGNED(A_SIGNED),
+               .A_WIDTH(A_WIDTH),
+               .Y_WIDTH(WIDTH)
+       ) expand (
+               .A(A),
+               .Y(chain[WIDTH-1:0])
+       );
+       for (i = 0; i < Y_WIDTH; i = i + 1) begin:Y
+               if (i < WIDTH) begin
+                       assign Y[i] = chain[WIDTH*B_WIDTH + i];
+               end else
+               if (A_SIGNED) begin
+                       assign Y[i] = chain[WIDTH*B_WIDTH + WIDTH-1];
+               end else begin
+                       assign Y[i] = 0;
+               end
+       end
+       for (i = 0; i < B_WIDTH; i = i + 1) begin:V
+               wire [WIDTH-1:0] unshifted, shifted, result;
+               assign unshifted = chain[WIDTH*i + WIDTH-1 : WIDTH*i];
+               assign chain[WIDTH*(i+1) + WIDTH-1 : WIDTH*(i+1)] = result;
+               \$shift #(
+                       .WIDTH(WIDTH),
+                       .SHIFT(2 ** i)
+               ) sh (
+                       .X(A_SIGNED && A[A_WIDTH-1]),
+                       .A(unshifted),
+                       .Y(shifted)
+               );
+               \$mux #(
+                       .WIDTH(WIDTH)
+               ) mux (
+                       .A(unshifted),
+                       .B(shifted),
+                       .Y(result),
+                       .S(B[i])
+               );
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$fulladd (A, B, C, X, Y);
+
+// {X, Y} = A + B + C
+input A, B, C;
+output X, Y;
+
+// {t1, t2} = A + B
+wire t1, t2, t3;
+
+ \$_AND_ gate1 ( .A(A),  .B(B),  .Y(t1) );
+ \$_XOR_ gate2 ( .A(A),  .B(B),  .Y(t2) );
+ \$_AND_ gate3 ( .A(t2), .B(C),  .Y(t3) ); 
+ \$_XOR_ gate4 ( .A(t2), .B(C),  .Y(Y)  );
+ \$_OR_  gate5 ( .A(t1), .B(t3), .Y(X)  );
+
+endmodule
+
+
+// --------------------------------------------------------
+
+module \$alu (A, B, Cin, Y, Cout, Csign);
+
+parameter WIDTH = 1;
+
+input [WIDTH-1:0] A, B;
+input Cin;
+
+output [WIDTH-1:0] Y;
+output Cout, Csign;
+
+wire [WIDTH:0] carry;
+assign carry[0] = Cin;
+assign Cout = carry[WIDTH];
+assign Csign = carry[WIDTH-1];
+
+genvar i;
+generate
+       for (i = 0; i < WIDTH; i = i + 1) begin:V
+               \$fulladd adder (
+                       .A(A[i]),
+                       .B(B[i]),
+                       .C(carry[i]),
+                       .X(carry[i+1]),
+                       .Y(Y[i])
+               );
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$lt (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+parameter WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output Y;
+
+wire carry, carry_sign;
+wire [WIDTH-1:0] A_buf, B_buf, Y_buf;
+\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
+\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+\$alu #(
+       .WIDTH(WIDTH)
+) alu (
+       .A(A_buf),
+       .B(~B_buf),
+       .Cin(1'b1),
+       .Y(Y_buf),
+       .Cout(carry),
+       .Csign(carry_sign),
+);
+
+// ALU flags
+wire cf, of, zf, sf;
+assign cf = !carry;
+assign of = carry ^ carry_sign;
+assign zf = ~|Y_buf;
+assign sf = Y_buf[WIDTH-1];
+
+generate
+       if (A_SIGNED && B_SIGNED) begin
+               assign Y = of != sf;
+       end else begin
+               assign Y = cf;
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$le (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+parameter WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output Y;
+
+wire carry, carry_sign;
+wire [WIDTH-1:0] A_buf, B_buf, Y_buf;
+\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
+\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+\$alu #(
+       .WIDTH(WIDTH)
+) alu (
+       .A(A_buf),
+       .B(~B_buf),
+       .Cin(1'b1),
+       .Y(Y_buf),
+       .Cout(carry),
+       .Csign(carry_sign),
+);
+
+// ALU flags
+wire cf, of, zf, sf;
+assign cf = !carry;
+assign of = carry ^ carry_sign;
+assign zf = ~|Y_buf;
+assign sf = Y_buf[WIDTH-1];
+
+generate
+       if (A_SIGNED && B_SIGNED) begin
+               assign Y = zf || (of != sf);
+       end else begin
+               assign Y = zf || cf;
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$eq (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+parameter WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output Y;
+
+wire carry, carry_sign;
+wire [WIDTH-1:0] A_buf, B_buf, Y_buf;
+\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
+\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+assign Y = ~|(A_buf ^ B_buf);
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$ne (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+parameter WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output Y;
+
+wire carry, carry_sign;
+wire [WIDTH-1:0] A_buf, B_buf, Y_buf;
+\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
+\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+assign Y = |(A_buf ^ B_buf);
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$ge (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output Y;
+
+\$le #(
+       .A_SIGNED(B_SIGNED),
+       .B_SIGNED(A_SIGNED),
+       .A_WIDTH(B_WIDTH),
+       .B_WIDTH(A_WIDTH)
+) ge_via_le (
+       .A(B),
+       .B(A),
+       .Y(Y)
+);
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$gt (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output Y;
+
+\$lt #(
+       .A_SIGNED(B_SIGNED),
+       .B_SIGNED(A_SIGNED),
+       .A_WIDTH(B_WIDTH),
+       .B_WIDTH(A_WIDTH)
+) gt_via_lt (
+       .A(B),
+       .B(A),
+       .Y(Y)
+);
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$add (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire [Y_WIDTH-1:0] A_buf, B_buf;
+\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+\$alu #(
+       .WIDTH(Y_WIDTH)
+) alu (
+       .A(A_buf),
+       .B(B_buf),
+       .Cin(1'b0),
+       .Y(Y)
+);
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$sub (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire [Y_WIDTH-1:0] A_buf, B_buf;
+\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+\$alu #(
+       .WIDTH(Y_WIDTH)
+) alu (
+       .A(A_buf),
+       .B(~B_buf),
+       .Cin(1'b1),
+       .Y(Y)
+);
+
+endmodule
+
+/****
+// --------------------------------------------------------
+
+module \$mul (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire signed [A_WIDTH:0] buffer_a = A_SIGNED ? $signed(A) : A;
+wire signed [B_WIDTH:0] buffer_b = B_SIGNED ? $signed(B) : B;
+
+assign Y = buffer_a * buffer_b;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$div (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire signed [A_WIDTH:0] buffer_a = A_SIGNED ? $signed(A) : A;
+wire signed [B_WIDTH:0] buffer_b = B_SIGNED ? $signed(B) : B;
+
+assign Y = buffer_a / buffer_b;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$mod (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire signed [A_WIDTH:0] buffer_a = A_SIGNED ? $signed(A) : A;
+wire signed [B_WIDTH:0] buffer_b = B_SIGNED ? $signed(B) : B;
+
+assign Y = buffer_a % buffer_b;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$pow (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire signed [A_WIDTH:0] buffer_a = A_SIGNED ? $signed(A) : A;
+wire signed [B_WIDTH:0] buffer_b = B_SIGNED ? $signed(B) : B;
+
+assign Y = buffer_a ** buffer_b;
+
+endmodule
+
+// --------------------------------------------------------
+****/
+
+module \$logic_not (A, Y);
+
+parameter A_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+output [Y_WIDTH-1:0] Y;
+
+wire A_buf;
+
+\$reduce_bool #(
+       .A_SIGNED(A_SIGNED),
+       .A_WIDTH(A_WIDTH)
+) A_logic (
+       .A(A), 
+       .Y(A_buf)
+);
+
+ \$_INV_ gate (
+       .A(A_buf),
+       .Y(Y[0])
+);
+
+generate
+       if (Y_WIDTH > 1) begin:V
+               assign Y[Y_WIDTH-1:1] = 0;
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$logic_and (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire A_buf, B_buf;
+
+\$reduce_bool #(
+       .A_SIGNED(A_SIGNED),
+       .A_WIDTH(A_WIDTH)
+) A_logic (
+       .A(A), 
+       .Y(A_buf)
+);
+
+\$reduce_bool #(
+       .A_SIGNED(B_SIGNED),
+       .A_WIDTH(B_WIDTH)
+) B_logic (
+       .A(B), 
+       .Y(B_buf)
+);
+
+ \$_AND_ gate (
+       .A(A_buf),
+       .B(B_buf),
+       .Y(Y[0])
+);
+
+generate
+       if (Y_WIDTH > 1) begin:V
+               assign Y[Y_WIDTH-1:1] = 0;
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$logic_or (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+wire A_buf, B_buf;
+
+\$reduce_bool #(
+       .A_SIGNED(A_SIGNED),
+       .A_WIDTH(A_WIDTH)
+) A_logic (
+       .A(A), 
+       .Y(A_buf)
+);
+
+\$reduce_bool #(
+       .A_SIGNED(B_SIGNED),
+       .A_WIDTH(B_WIDTH)
+) B_logic (
+       .A(B), 
+       .Y(B_buf)
+);
+
+ \$_OR_ gate (
+       .A(A_buf),
+       .B(B_buf),
+       .Y(Y[0])
+);
+
+generate
+       if (Y_WIDTH > 1) begin:V
+               assign Y[Y_WIDTH-1:1] = 0;
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$mux (A, B, S, Y);
+
+parameter WIDTH = 1;
+
+input [WIDTH-1:0] A, B;
+input S;
+output [WIDTH-1:0] Y;
+
+genvar i;
+generate
+       for (i = 0; i < WIDTH; i = i + 1) begin:V
+               \$_MUX_ gate (
+                       .A(A[i]),
+                       .B(B[i]),
+                       .S(S),
+                       .Y(Y[i])
+               );
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$pmux (A, B, S, Y);
+
+parameter WIDTH = 1;
+parameter S_WIDTH = 1;
+
+input [WIDTH-1:0] A;
+input [WIDTH*S_WIDTH-1:0] B;
+input [S_WIDTH-1:0] S;
+output [WIDTH-1:0] Y;
+
+wire [WIDTH-1:0] Y_B;
+
+genvar i, j;
+generate
+       wire [WIDTH*S_WIDTH-1:0] B_AND_S;
+        for (i = 0; i < S_WIDTH; i = i + 1) begin:B_AND
+                assign B_AND_S[WIDTH*(i+1)-1:WIDTH*i] = B[WIDTH*(i+1)-1:WIDTH*i] & {WIDTH{S[i]}};
+        end:B_AND
+        for (i = 0; i < WIDTH; i = i + 1) begin:B_OR
+                wire [S_WIDTH-1:0] B_AND_BITS;
+                for (j = 0; j < S_WIDTH; j = j + 1) begin:B_AND_BITS_COLLECT
+                        assign B_AND_BITS[j] = B_AND_S[WIDTH*j+i];
+                end:B_AND_BITS_COLLECT
+                assign Y_B[i] = |B_AND_BITS;
+        end:B_OR
+endgenerate
+
+assign Y = |S ? Y_B : A;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$safe_pmux (A, B, S, Y);
+
+parameter WIDTH = 1;
+parameter S_WIDTH = 1;
+
+input [WIDTH-1:0] A;
+input [WIDTH*S_WIDTH-1:0] B;
+input [S_WIDTH-1:0] S;
+output [WIDTH-1:0] Y;
+
+wire [S_WIDTH-1:0] status_found_first;
+wire [S_WIDTH-1:0] status_found_second;
+
+genvar i;
+generate
+       for (i = 0; i < S_WIDTH; i = i + 1) begin:GEN1
+               wire pre_first;
+               if (i > 0) begin:GEN2
+                       assign pre_first = status_found_first[i-1];
+               end:GEN2 else begin:GEN3
+                       assign pre_first = 0;
+               end:GEN3
+               assign status_found_first[i] = pre_first | S[i];
+               assign status_found_second[i] = pre_first & S[i];
+       end:GEN1
+endgenerate
+
+\$pmux #(
+       .WIDTH(WIDTH),
+       .S_WIDTH(S_WIDTH)
+) pmux_cell (
+       .A(A),
+       .B(B),
+       .S(S & {S_WIDTH{~|status_found_second}}),
+       .Y(Y)
+);
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$dff (CLK, D, Q);
+
+parameter WIDTH = 1;
+parameter CLK_POLARITY = 1'b1;
+
+input CLK;
+input [WIDTH-1:0] D;
+output [WIDTH-1:0] Q;
+
+genvar i;
+generate
+       if (CLK_POLARITY == 0)
+               for (i = 0; i < WIDTH; i = i + 1) begin:V
+                        \$_DFF_N_ ff (
+                               .D(D[i]),
+                               .Q(Q[i]),
+                               .C(CLK)
+                       );
+               end
+       if (CLK_POLARITY != 0)
+               for (i = 0; i < WIDTH; i = i + 1) begin:V
+                        \$_DFF_P_ ff (
+                               .D(D[i]),
+                               .Q(Q[i]),
+                               .C(CLK)
+                       );
+               end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$adff (CLK, ARST, D, Q);
+
+parameter WIDTH = 1;
+parameter CLK_POLARITY = 1'b1;
+parameter ARST_POLARITY = 1'b1;
+parameter ARST_VALUE = 0;
+
+input CLK, ARST;
+input [WIDTH-1:0] D;
+output [WIDTH-1:0] Q;
+
+genvar i;
+generate
+       for (i = 0; i < WIDTH; i = i + 1) begin:V
+               if (CLK_POLARITY == 0 && ARST_POLARITY == 0 && ARST_VALUE[i] == 0) begin:NN0
+                        \$_DFF_NN0_ ff (
+                               .D(D[i]),
+                               .Q(Q[i]),
+                               .C(CLK),
+                               .R(ARST)
+                       );
+               end
+               if (CLK_POLARITY == 0 && ARST_POLARITY == 0 && ARST_VALUE[i] != 0) begin:NN1
+                        \$_DFF_NN1_ ff (
+                               .D(D[i]),
+                               .Q(Q[i]),
+                               .C(CLK),
+                               .R(ARST)
+                       );
+               end
+               if (CLK_POLARITY == 0 && ARST_POLARITY != 0 && ARST_VALUE[i] == 0) begin:NP0
+                        \$_DFF_NP0_ ff (
+                               .D(D[i]),
+                               .Q(Q[i]),
+                               .C(CLK),
+                               .R(ARST)
+                       );
+               end
+               if (CLK_POLARITY == 0 && ARST_POLARITY != 0 && ARST_VALUE[i] != 0) begin:NP1
+                        \$_DFF_NP1_ ff (
+                               .D(D[i]),
+                               .Q(Q[i]),
+                               .C(CLK),
+                               .R(ARST)
+                       );
+               end
+               if (CLK_POLARITY != 0 && ARST_POLARITY == 0 && ARST_VALUE[i] == 0) begin:PN0
+                        \$_DFF_PN0_ ff (
+                               .D(D[i]),
+                               .Q(Q[i]),
+                               .C(CLK),
+                               .R(ARST)
+                       );
+               end
+               if (CLK_POLARITY != 0 && ARST_POLARITY == 0 && ARST_VALUE[i] != 0) begin:PN1
+                        \$_DFF_PN1_ ff (
+                               .D(D[i]),
+                               .Q(Q[i]),
+                               .C(CLK),
+                               .R(ARST)
+                       );
+               end
+               if (CLK_POLARITY != 0 && ARST_POLARITY != 0 && ARST_VALUE[i] == 0) begin:PP0
+                        \$_DFF_PP0_ ff (
+                               .D(D[i]),
+                               .Q(Q[i]),
+                               .C(CLK),
+                               .R(ARST)
+                       );
+               end
+               if (CLK_POLARITY != 0 && ARST_POLARITY != 0 && ARST_VALUE[i] != 0) begin:PP1
+                        \$_DFF_PP1_ ff (
+                               .D(D[i]),
+                               .Q(Q[i]),
+                               .C(CLK),
+                               .R(ARST)
+                       );
+               end
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
diff --git a/techlibs/stdcells_sim.v b/techlibs/stdcells_sim.v
new file mode 100644 (file)
index 0000000..6e5d271
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *  
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *  ---
+ *
+ *  The internal logic cell simulation library.
+ *
+ *  This verilog library contains simple simulation models for the internal
+ *  logic cells ($_INV_ , $_AND_ , ...) that are generated by the default technology
+ *  mapper (see "stdcells.v" in this directory) and expected by the "abc" pass.
+ *
+ */
+
+module  \$_INV_ (A, Y);
+input A;
+output Y;
+assign Y = ~A;
+endmodule
+
+module  \$_AND_ (A, B, Y);
+input A, B;
+output Y;
+assign Y = A & B;
+endmodule
+
+module  \$_OR_ (A, B, Y);
+input A, B;
+output Y;
+assign Y = A | B;
+endmodule
+
+module  \$_XOR_ (A, B, Y);
+input A, B;
+output Y;
+assign Y = A ^ B;
+endmodule
+
+module \$_MUX_ (A, B, S, Y);
+input A, B, S;
+output reg Y;
+always @* begin
+       if (S)
+               Y = B;
+       else
+               Y = A;
+end
+endmodule
+
+module  \$_DFF_N_ (D, Q, C);
+input D, C;
+output reg Q;
+always @(negedge C) begin
+       Q <= D;
+end
+endmodule
+
+module  \$_DFF_P_ (D, Q, C);
+input D, C;
+output reg Q;
+always @(posedge C) begin
+       Q <= D;
+end
+endmodule
+
+module  \$_DFF_NN0_ (D, Q, C, R);
+input D, C, R;
+output reg Q;
+always @(negedge C or negedge R) begin
+       if (R == 0)
+               Q <= 0;
+       else
+               Q <= D;
+end
+endmodule
+
+module  \$_DFF_NN1_ (D, Q, C, R);
+input D, C, R;
+output reg Q;
+always @(negedge C or negedge R) begin
+       if (R == 0)
+               Q <= 1;
+       else
+               Q <= D;
+end
+endmodule
+
+module  \$_DFF_NP0_ (D, Q, C, R);
+input D, C, R;
+output reg Q;
+always @(negedge C or posedge R) begin
+       if (R == 1)
+               Q <= 0;
+       else
+               Q <= D;
+end
+endmodule
+
+module  \$_DFF_NP1_ (D, Q, C, R);
+input D, C, R;
+output reg Q;
+always @(negedge C or posedge R) begin
+       if (R == 1)
+               Q <= 1;
+       else
+               Q <= D;
+end
+endmodule
+
+module  \$_DFF_PN0_ (D, Q, C, R);
+input D, C, R;
+output reg Q;
+always @(posedge C or negedge R) begin
+       if (R == 0)
+               Q <= 0;
+       else
+               Q <= D;
+end
+endmodule
+
+module  \$_DFF_PN1_ (D, Q, C, R);
+input D, C, R;
+output reg Q;
+always @(posedge C or negedge R) begin
+       if (R == 0)
+               Q <= 1;
+       else
+               Q <= D;
+end
+endmodule
+
+module  \$_DFF_PP0_ (D, Q, C, R);
+input D, C, R;
+output reg Q;
+always @(posedge C or posedge R) begin
+       if (R == 1)
+               Q <= 0;
+       else
+               Q <= D;
+end
+endmodule
+
+module  \$_DFF_PP1_ (D, Q, C, R);
+input D, C, R;
+output reg Q;
+always @(posedge C or posedge R) begin
+       if (R == 1)
+               Q <= 1;
+       else
+               Q <= D;
+end
+endmodule
+
diff --git a/tests/asicworld/README b/tests/asicworld/README
new file mode 100644 (file)
index 0000000..0e96edb
--- /dev/null
@@ -0,0 +1 @@
+Borrowed verilog examples from http://www.asic-world.com/.
diff --git a/tests/asicworld/code_hdl_models_GrayCounter.v b/tests/asicworld/code_hdl_models_GrayCounter.v
new file mode 100644 (file)
index 0000000..23f0da0
--- /dev/null
@@ -0,0 +1,33 @@
+//==========================================
+// Function : Code Gray counter.
+// Coder    : Alex Claros F.
+// Date     : 15/May/2005.
+//=======================================
+
+module GrayCounter
+   #(parameter   COUNTER_WIDTH = 4)
+   
+    (output reg  [COUNTER_WIDTH-1:0]    GrayCount_out,  //'Gray' code count output.
+    
+     input wire                         Enable_in,  //Count enable.
+     input wire                         Clear_in,   //Count reset.
+    
+     input wire                         Clk);
+
+    /////////Internal connections & variables///////
+    reg    [COUNTER_WIDTH-1:0]         BinaryCount;
+
+    /////////Code///////////////////////
+    
+    always @ (posedge Clk)
+        if (Clear_in) begin
+            BinaryCount   <= {COUNTER_WIDTH{1'b 0}} + 1;  //Gray count begins @ '1' with
+            GrayCount_out <= {COUNTER_WIDTH{1'b 0}};      // first 'Enable_in'.
+        end
+        else if (Enable_in) begin
+            BinaryCount   <= BinaryCount + 1;
+            GrayCount_out <= {BinaryCount[COUNTER_WIDTH-1],
+                              BinaryCount[COUNTER_WIDTH-2:0] ^ BinaryCount[COUNTER_WIDTH-1:1]};
+        end
+    
+endmodule
diff --git a/tests/asicworld/code_hdl_models_arbiter.v b/tests/asicworld/code_hdl_models_arbiter.v
new file mode 100644 (file)
index 0000000..978e198
--- /dev/null
@@ -0,0 +1,123 @@
+//----------------------------------------------------\r
+// A four level, round-robin arbiter. This was\r
+// orginally coded by WD Peterson in VHDL.\r
+//----------------------------------------------------\r
+module arbiter (\r
+  clk,    \r
+  rst,    \r
+  req3,   \r
+  req2,   \r
+  req1,   \r
+  req0,   \r
+  gnt3,   \r
+  gnt2,   \r
+  gnt1,   \r
+  gnt0   \r
+);\r
+// --------------Port Declaration----------------------- \r
+input           clk;    \r
+input           rst;    \r
+input           req3;   \r
+input           req2;   \r
+input           req1;   \r
+input           req0;   \r
+output          gnt3;   \r
+output          gnt2;   \r
+output          gnt1;   \r
+output          gnt0;   \r
+\r
+//--------------Internal Registers----------------------\r
+wire    [1:0]   gnt       ;   \r
+wire            comreq    ; \r
+wire            beg       ;\r
+wire   [1:0]    lgnt      ;\r
+wire            lcomreq   ;\r
+reg             lgnt0     ;\r
+reg             lgnt1     ;\r
+reg             lgnt2     ;\r
+reg             lgnt3     ;\r
+reg             lasmask   ;\r
+reg             lmask0    ;\r
+reg             lmask1    ;\r
+reg             ledge     ;\r
+\r
+//--------------Code Starts Here----------------------- \r
+always @ (posedge clk)\r
+if (rst) begin\r
+  lgnt0 <= 0;\r
+  lgnt1 <= 0;\r
+  lgnt2 <= 0;\r
+  lgnt3 <= 0;\r
+end else begin                                     \r
+  lgnt0 <=(~lcomreq & ~lmask1 & ~lmask0 & ~req3 & ~req2 & ~req1 & req0)\r
+        | (~lcomreq & ~lmask1 &  lmask0 & ~req3 & ~req2 &  req0)\r
+        | (~lcomreq &  lmask1 & ~lmask0 & ~req3 &  req0)\r
+        | (~lcomreq &  lmask1 &  lmask0 & req0  )\r
+        | ( lcomreq & lgnt0 );\r
+  lgnt1 <=(~lcomreq & ~lmask1 & ~lmask0 &  req1)\r
+        | (~lcomreq & ~lmask1 &  lmask0 & ~req3 & ~req2 &  req1 & ~req0)\r
+        | (~lcomreq &  lmask1 & ~lmask0 & ~req3 &  req1 & ~req0)\r
+        | (~lcomreq &  lmask1 &  lmask0 &  req1 & ~req0)\r
+        | ( lcomreq &  lgnt1);\r
+  lgnt2 <=(~lcomreq & ~lmask1 & ~lmask0 &  req2  & ~req1)\r
+        | (~lcomreq & ~lmask1 &  lmask0 &  req2)\r
+        | (~lcomreq &  lmask1 & ~lmask0 & ~req3 &  req2  & ~req1 & ~req0)\r
+        | (~lcomreq &  lmask1 &  lmask0 &  req2 & ~req1 & ~req0)\r
+        | ( lcomreq &  lgnt2);\r
+  lgnt3 <=(~lcomreq & ~lmask1 & ~lmask0 & req3  & ~req2 & ~req1)\r
+        | (~lcomreq & ~lmask1 &  lmask0 & req3  & ~req2)\r
+        | (~lcomreq &  lmask1 & ~lmask0 & req3)\r
+        | (~lcomreq &  lmask1 &  lmask0 & req3  & ~req2 & ~req1 & ~req0)\r
+        | ( lcomreq & lgnt3);\r
+end \r
+\r
+//----------------------------------------------------\r
+// lasmask state machine.\r
+//----------------------------------------------------\r
+assign beg = (req3 | req2 | req1 | req0) & ~lcomreq;\r
+always @ (posedge clk)\r
+begin                                     \r
+  lasmask <= (beg & ~ledge & ~lasmask);\r
+  ledge   <= (beg & ~ledge &  lasmask) \r
+          |  (beg &  ledge & ~lasmask);\r
+end \r
+\r
+//----------------------------------------------------\r
+// comreq logic.\r
+//----------------------------------------------------\r
+assign lcomreq = ( req3 & lgnt3 )\r
+                | ( req2 & lgnt2 )\r
+                | ( req1 & lgnt1 )\r
+                | ( req0 & lgnt0 );\r
+\r
+//----------------------------------------------------\r
+// Encoder logic.\r
+//----------------------------------------------------\r
+assign  lgnt =  {(lgnt3 | lgnt2),(lgnt3 | lgnt1)};\r
+\r
+//----------------------------------------------------\r
+// lmask register.\r
+//----------------------------------------------------\r
+always @ (posedge clk )\r
+if( rst ) begin\r
+  lmask1 <= 0;\r
+  lmask0 <= 0;\r
+end else if(lasmask) begin\r
+  lmask1 <= lgnt[1];\r
+  lmask0 <= lgnt[0];\r
+end else begin\r
+  lmask1 <= lmask1;\r
+  lmask0 <= lmask0;\r
+end \r
+\r
+assign comreq = lcomreq;\r
+assign gnt    = lgnt;\r
+//----------------------------------------------------\r
+// Drive the outputs\r
+//----------------------------------------------------\r
+assign gnt3   = lgnt3;\r
+assign gnt2   = lgnt2;\r
+assign gnt1   = lgnt1;\r
+assign gnt0   = lgnt0;\r
+\r
+endmodule\r
diff --git a/tests/asicworld/code_hdl_models_arbiter_tb.v b/tests/asicworld/code_hdl_models_arbiter_tb.v
new file mode 100644 (file)
index 0000000..5e7bf46
--- /dev/null
@@ -0,0 +1,62 @@
+module testbench ();
+
+reg             clk;    
+reg             rst;    
+reg             req3;   
+reg             req2;   
+reg             req1;   
+reg             req0;   
+wire            gnt3;   
+wire            gnt2;   
+wire            gnt1;   
+wire            gnt0;  
+
+// Clock generator
+always #1 clk = ~clk;
+
+initial begin
+  $dumpfile ("arbiter.vcd");
+  $dumpvars();
+  clk = 0;
+  rst = 1;
+  req0 = 0;
+  req1 = 0;
+  req2 = 0;
+  req3 = 0;
+  #10 rst = 0;
+  repeat (1) @ (posedge clk);
+  req0 <= 1;
+  repeat (1) @ (posedge clk);
+  req0 <= 0;
+  repeat (1) @ (posedge clk);
+  req0 <= 1;
+  req1 <= 1;
+  repeat (1) @ (posedge clk);
+  req2 <= 1;
+  req1 <= 0;
+  repeat (1) @ (posedge clk);
+  req3 <= 1;
+  req2 <= 0;
+  repeat (1) @ (posedge clk);
+  req3 <= 0;
+  repeat (1) @ (posedge clk);
+  req0 <= 0;
+  repeat (1) @ (posedge clk);
+  #10 $finish;
+end 
+
+// Connect the DUT
+arbiter U (
+ clk,    
+ rst,    
+ req3,   
+ req2,   
+ req1,   
+ req0,   
+ gnt3,   
+ gnt2,   
+ gnt1,   
+ gnt0   
+);
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_cam.v b/tests/asicworld/code_hdl_models_cam.v
new file mode 100644 (file)
index 0000000..0cebc07
--- /dev/null
@@ -0,0 +1,60 @@
+//-----------------------------------------------------
+// Design Name : cam
+// File Name   : cam.v
+// Function    : CAM
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module cam (
+clk         , // Cam clock
+cam_enable  , // Cam enable
+cam_data_in , // Cam data to match
+cam_hit_out , // Cam match has happened
+cam_addr_out  // Cam output address 
+);
+
+parameter ADDR_WIDTH  = 8;
+parameter DEPTH       = 1 << ADDR_WIDTH;
+//------------Input Ports--------------
+input                    clk;      
+input                    cam_enable;   
+input  [DEPTH-1:0]       cam_data_in;  
+//----------Output Ports--------------
+output                   cam_hit_out;  
+output [ADDR_WIDTH-1:0]  cam_addr_out;  
+//------------Internal Variables--------
+reg [ADDR_WIDTH-1:0]  cam_addr_out;
+reg                   cam_hit_out;
+reg [ADDR_WIDTH-1:0]  cam_addr_combo;
+reg                   cam_hit_combo;
+reg                   found_match;
+integer               i;
+//-------------Code Starts Here-------
+always @(cam_data_in) begin
+  cam_addr_combo   = {ADDR_WIDTH{1'b0}};
+  found_match      = 1'b0;
+  cam_hit_combo    = 1'b0;
+  for (i=0; i<DEPTH; i=i+1) begin
+    if (cam_data_in[i] && !found_match) begin
+      found_match     = 1'b1;
+      cam_hit_combo   = 1'b1;
+      cam_addr_combo  = i;
+    end else begin
+      found_match     = found_match;
+      cam_hit_combo   = cam_hit_combo;
+      cam_addr_combo  = cam_addr_combo;
+    end
+  end
+end
+
+// Register the outputs 
+always @(posedge clk) begin
+  if (cam_enable) begin
+    cam_hit_out  <=  cam_hit_combo;
+    cam_addr_out <=  cam_addr_combo;
+  end else begin
+    cam_hit_out  <=  1'b0;
+    cam_addr_out <=  {ADDR_WIDTH{1'b0}};
+  end
+end
+
+endmodule 
diff --git a/tests/asicworld/code_hdl_models_clk_div.v b/tests/asicworld/code_hdl_models_clk_div.v
new file mode 100644 (file)
index 0000000..c48ab0d
--- /dev/null
@@ -0,0 +1,27 @@
+//-----------------------------------------------------
+// Design Name : clk_div
+// File Name   : clk_div.v
+// Function    : Divide by two counter
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+
+module clk_div (clk_in, enable,reset, clk_out);
+ // --------------Port Declaration----------------------- 
+ input               clk_in                   ;
+ input               reset                    ;
+ input               enable                   ;
+ output              clk_out                  ;
+ //--------------Port data type declaration-------------
+ wire                 clk_in                  ;
+ wire                 enable                  ;
+//--------------Internal Registers----------------------
+reg                   clk_out                 ;
+//--------------Code Starts Here----------------------- 
+always @ (posedge clk_in) 
+if (reset) begin 
+  clk_out <= 1'b0;
+end else if (enable) begin
+  clk_out <= !clk_out ; 
+end
+
+endmodule  
diff --git a/tests/asicworld/code_hdl_models_clk_div_45.v b/tests/asicworld/code_hdl_models_clk_div_45.v
new file mode 100644 (file)
index 0000000..d9d2896
--- /dev/null
@@ -0,0 +1,54 @@
+//-----------------------------------------------------
+// Design Name : clk_div_45
+// File Name   : clk_div_45.v
+// Function    : Divide by 4.5
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module clk_div_45 (
+clk_in, // Input Clock
+enable, // Enable is sync with falling edge of clk_in
+clk_out // Output Clock
+);
+
+// --------------Port Declaration-----------------------
+input      clk_in     ;
+input      enable     ;
+output     clk_out    ;
+
+//--------------Port data type declaration-------------
+wire       clk_in     ;
+wire       enable     ;
+wire       clk_out    ;
+
+//--------------Internal Registers----------------------
+reg   [3:0] counter1   ;
+reg   [3:0] counter2   ;
+reg         toggle1    ;
+reg         toggle2    ;
+
+//--------------Code Starts Here-----------------------
+always @ (posedge clk_in)
+if (enable == 1'b0) begin 
+   counter1 <= 4'b0;
+   toggle1  <= 0;
+end else if ((counter1 == 3 && toggle2) || (~toggle1 && counter1 == 4))  begin
+   counter1 <= 4'b0;
+   toggle1  <= ~toggle1;
+end else   begin
+   counter1 <= counter1 + 1;
+end
+   
+always @ (negedge clk_in)
+if (enable == 1'b0) begin
+  counter2 <= 4'b0;
+  toggle2  <= 0;
+end else if ((counter2 == 3 && ~toggle2) || (toggle2 && counter2 == 4))  begin
+  counter2 <= 4'b0;
+  toggle2  <= ~toggle2;
+end  else   begin
+  counter2 <= counter2 + 1;
+end
+
+assign  clk_out = (counter1 <3 && counter2 < 3) & enable;
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_d_ff_gates.v b/tests/asicworld/code_hdl_models_d_ff_gates.v
new file mode 100644 (file)
index 0000000..8706f15
--- /dev/null
@@ -0,0 +1,29 @@
+module d_ff_gates(d,clk,q,q_bar);
+input d,clk;
+output q, q_bar;
+
+wire n1,n2,n3,q_bar_n;
+wire cn,dn,n4,n5,n6;
+
+// First Latch
+not (n1,d);
+
+nand (n2,d,clk);
+nand (n3,n1,clk);
+
+nand (dn,q_bar_n,n2);
+nand (q_bar_n,dn,n3);
+
+// Second Latch
+not (cn,clk);
+
+not (n4,dn);
+
+nand (n5,dn,cn);
+nand (n6,n4,cn);
+
+nand (q,q_bar,n5);
+nand (q_bar,q,n6);
+
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_d_latch_gates.v b/tests/asicworld/code_hdl_models_d_latch_gates.v
new file mode 100644 (file)
index 0000000..3f5f6b2
--- /dev/null
@@ -0,0 +1,15 @@
+module d_latch_gates(d,clk,q,q_bar);
+input d,clk;
+output q, q_bar;
+
+wire n1,n2,n3;
+
+not (n1,d);
+
+nand (n2,d,clk);
+nand (n3,n1,clk);
+
+nand (q,q_bar,n2);
+nand (q_bar,q,n3);
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_decoder_2to4_gates.v b/tests/asicworld/code_hdl_models_decoder_2to4_gates.v
new file mode 100644 (file)
index 0000000..810003a
--- /dev/null
@@ -0,0 +1,14 @@
+module decoder_2to4_gates (x,y,f0,f1,f2,f3);
+input x,y;
+output f0,f1,f2,f3;
+
+wire n1,n2;
+
+not i1 (n1,x);
+not i2 (n2,y);
+and a1 (f0,n1,n2);
+and a2 (f1,n1,y);
+and a3 (f2,x,n2);
+and a4 (f3,x,y);
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_decoder_using_assign.v b/tests/asicworld/code_hdl_models_decoder_using_assign.v
new file mode 100644 (file)
index 0000000..ec0dc95
--- /dev/null
@@ -0,0 +1,20 @@
+//-----------------------------------------------------
+// Design Name : decoder_using_assign
+// File Name   : decoder_using_assign.v
+// Function    : decoder using assign
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module decoder_using_assign (
+binary_in   , //  4 bit binary input
+decoder_out , //  16-bit out 
+enable        //  Enable for the decoder
+);
+input [3:0] binary_in  ;
+input  enable ; 
+output [15:0] decoder_out ; 
+        
+wire [15:0] decoder_out ; 
+
+assign decoder_out = (enable) ? (1 << binary_in) : 16'b0 ;
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_decoder_using_case.v b/tests/asicworld/code_hdl_models_decoder_using_case.v
new file mode 100644 (file)
index 0000000..ad42acd
--- /dev/null
@@ -0,0 +1,43 @@
+//-----------------------------------------------------
+// Design Name : decoder_using_case
+// File Name   : decoder_using_case.v
+// Function    : decoder using case
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module decoder_using_case (
+binary_in   , //  4 bit binary input
+decoder_out , //  16-bit  out
+enable        //  Enable for the decoder
+);
+input [3:0] binary_in  ;
+input  enable ;
+output [15:0] decoder_out ;
+
+reg [15:0] decoder_out ;
+
+always @ (enable or binary_in)
+begin
+  decoder_out = 0;
+  if (enable) begin
+    case (binary_in)
+      4'h0 : decoder_out = 16'h0001;
+      4'h1 : decoder_out = 16'h0002;
+      4'h2 : decoder_out = 16'h0004;
+      4'h3 : decoder_out = 16'h0008;
+      4'h4 : decoder_out = 16'h0010;
+      4'h5 : decoder_out = 16'h0020;
+      4'h6 : decoder_out = 16'h0040;
+      4'h7 : decoder_out = 16'h0080;
+      4'h8 : decoder_out = 16'h0100;
+      4'h9 : decoder_out = 16'h0200;
+      4'hA : decoder_out = 16'h0400;
+      4'hB : decoder_out = 16'h0800;
+      4'hC : decoder_out = 16'h1000;
+      4'hD : decoder_out = 16'h2000;
+      4'hE : decoder_out = 16'h4000;
+      4'hF : decoder_out = 16'h8000;
+    endcase
+  end
+end
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_dff_async_reset.v b/tests/asicworld/code_hdl_models_dff_async_reset.v
new file mode 100644 (file)
index 0000000..a156082
--- /dev/null
@@ -0,0 +1,30 @@
+//-----------------------------------------------------
+// Design Name : dff_async_reset
+// File Name   : dff_async_reset.v
+// Function    : D flip-flop async reset
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module dff_async_reset (
+data  , // Data Input
+clk    , // Clock Input
+reset , // Reset input 
+q         // Q output
+);
+//-----------Input Ports---------------
+input data, clk, reset ; 
+
+//-----------Output Ports---------------
+output q;
+
+//------------Internal Variables--------
+reg q;
+
+//-------------Code Starts Here---------
+always @ ( posedge clk or negedge reset)
+if (~reset) begin
+  q <= 1'b0;
+end  else begin
+  q <= data;
+end
+
+endmodule //End Of Module dff_async_reset
diff --git a/tests/asicworld/code_hdl_models_dff_sync_reset.v b/tests/asicworld/code_hdl_models_dff_sync_reset.v
new file mode 100644 (file)
index 0000000..7ef4045
--- /dev/null
@@ -0,0 +1,30 @@
+//-----------------------------------------------------
+// Design Name : dff_sync_reset
+// File Name   : dff_sync_reset.v
+// Function    : D flip-flop sync reset
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module dff_sync_reset (
+data   , // Data Input
+clk    , // Clock Input
+reset  , // Reset input
+q        // Q output
+);
+//-----------Input Ports---------------
+input data, clk, reset ; 
+
+//-----------Output Ports---------------
+output q;
+
+//------------Internal Variables--------
+reg q;
+
+//-------------Code Starts Here---------
+always @ ( posedge clk)
+if (~reset) begin
+  q <= 1'b0;
+end  else begin
+  q <= data;
+end
+
+endmodule //End Of Module dff_sync_reset
diff --git a/tests/asicworld/code_hdl_models_dlatch_reset.v b/tests/asicworld/code_hdl_models_dlatch_reset.v
new file mode 100644 (file)
index 0000000..2cfc6fb
--- /dev/null
@@ -0,0 +1,30 @@
+//-----------------------------------------------------
+// Design Name : dlatch_reset
+// File Name   : dlatch_reset.v
+// Function    : DLATCH async reset
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module dlatch_reset (
+data   , // Data Input
+en     , // LatchInput
+reset  , // Reset input
+q        // Q output
+);
+//-----------Input Ports---------------
+input data, en, reset ; 
+
+//-----------Output Ports---------------
+output q;
+
+//------------Internal Variables--------
+reg q;
+
+//-------------Code Starts Here---------
+always @ ( en or reset or data)
+if (~reset) begin
+  q <= 1'b0;
+end else if (en) begin
+  q <= data;
+end
+
+endmodule //End Of Module dlatch_reset
diff --git a/tests/asicworld/code_hdl_models_encoder_4to2_gates.v b/tests/asicworld/code_hdl_models_encoder_4to2_gates.v
new file mode 100644 (file)
index 0000000..0bfdc28
--- /dev/null
@@ -0,0 +1,8 @@
+module encoder_4to2_gates (i0,i1,i2,i3,y);
+input i0,i1,i2,i3;
+output [1:0] y;
+
+or o1 (y[0],i1,i3);
+or o2 (y[1],i2,i3);
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_encoder_using_case.v b/tests/asicworld/code_hdl_models_encoder_using_case.v
new file mode 100644 (file)
index 0000000..32e1b72
--- /dev/null
@@ -0,0 +1,42 @@
+//-----------------------------------------------------
+// Design Name : encoder_using_case
+// File Name   : encoder_using_case.v
+// Function    : Encoder using Case
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module encoder_using_case(
+binary_out , //  4 bit binary Output
+encoder_in , //  16-bit Input
+enable       //  Enable for the encoder
+);
+output [3:0] binary_out  ;
+input  enable ; 
+input [15:0] encoder_in ; 
+     
+reg [3:0] binary_out ;
+      
+always @ (enable or encoder_in)
+begin
+  binary_out = 0;
+  if (enable) begin
+    case (encoder_in) 
+      16'h0002 : binary_out = 1; 
+      16'h0004 : binary_out = 2; 
+      16'h0008 : binary_out = 3; 
+      16'h0010 : binary_out = 4;
+      16'h0020 : binary_out = 5; 
+      16'h0040 : binary_out = 6; 
+      16'h0080 : binary_out = 7; 
+      16'h0100 : binary_out = 8;
+      16'h0200 : binary_out = 9;
+      16'h0400 : binary_out = 10; 
+      16'h0800 : binary_out = 11; 
+      16'h1000 : binary_out = 12; 
+      16'h2000 : binary_out = 13; 
+      16'h4000 : binary_out = 14; 
+      16'h8000 : binary_out = 15; 
+   endcase
+  end
+end
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_encoder_using_if.v b/tests/asicworld/code_hdl_models_encoder_using_if.v
new file mode 100644 (file)
index 0000000..2c97ddb
--- /dev/null
@@ -0,0 +1,58 @@
+//-----------------------------------------------------
+// Design Name : encoder_using_if
+// File Name   : encoder_using_if.v
+// Function    : Encoder using If
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module encoder_using_if(
+binary_out , //  4 bit binary output
+encoder_in , //  16-bit input
+enable       //  Enable for the encoder
+); 
+//-----------Output Ports---------------
+output [3:0] binary_out  ;
+//-----------Input Ports---------------
+input  enable ; 
+input [15:0] encoder_in ; 
+//------------Internal Variables--------
+reg [3:0] binary_out ;  
+//-------------Code Start-----------------
+always @ (enable or encoder_in)
+ begin 
+   binary_out = 0; 
+   if (enable) begin
+     if (encoder_in == 16'h0002) begin
+      binary_out = 1;
+     end  if (encoder_in == 16'h0004) begin 
+      binary_out = 2; 
+     end  if (encoder_in == 16'h0008) begin 
+      binary_out = 3; 
+     end  if (encoder_in == 16'h0010) begin 
+      binary_out = 4; 
+     end  if (encoder_in == 16'h0020) begin 
+      binary_out = 5; 
+     end  if (encoder_in == 16'h0040) begin 
+      binary_out = 6; 
+     end  if (encoder_in == 16'h0080) begin 
+      binary_out = 7; 
+     end  if (encoder_in == 16'h0100) begin 
+      binary_out = 8; 
+     end  if (encoder_in == 16'h0200) begin 
+      binary_out = 9; 
+     end if (encoder_in == 16'h0400) begin 
+      binary_out = 10; 
+     end  if (encoder_in == 16'h0800) begin 
+      binary_out = 11; 
+     end  if (encoder_in == 16'h1000) begin
+      binary_out = 12; 
+     end  if (encoder_in == 16'h2000) begin 
+      binary_out = 13;
+     end  if (encoder_in == 16'h4000) begin 
+      binary_out = 14; 
+     end if (encoder_in == 16'h8000) begin 
+      binary_out = 15; 
+     end
+  end
+end
+      
+endmodule
diff --git a/tests/asicworld/code_hdl_models_full_adder_gates.v b/tests/asicworld/code_hdl_models_full_adder_gates.v
new file mode 100644 (file)
index 0000000..1ddc4c5
--- /dev/null
@@ -0,0 +1,18 @@
+//-----------------------------------------------------
+// Design Name : full_adder_gates
+// File Name   : full_adder_gates.v
+// Function    : Full Adder Using Gates
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module full_adder_gates(x,y,z,sum,carry);
+input x,y,z;
+output sum,carry;
+wire and1,and2,and3,sum1;
+
+and U_and1 (and1,x,y),
+    U_and2 (and2,x,z),
+    U_and3 (and3,y,z);
+or  U_or   (carry,and1,and2,and3);
+xor U_sum (sum,x,y,z);
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_full_subtracter_gates.v b/tests/asicworld/code_hdl_models_full_subtracter_gates.v
new file mode 100644 (file)
index 0000000..c24588e
--- /dev/null
@@ -0,0 +1,20 @@
+//-----------------------------------------------------
+// Design Name : full_subtracter_gates
+// File Name   : full_subtracter_gates.v
+// Function    : Full Subtracter Using Gates
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module full_subtracter_gates(x,y,z,difference,borrow);
+input x,y,z;
+output difference,borrow;
+
+wire inv_x,borrow1,borrow2,borrow3;
+
+not (inv_x,x);
+and U_borrow1 (borrow1,inv_x,y),
+    U_borrow2 (borrow2,inv_x,z),
+    U_borrow3 (borrow3,y,z);
+
+xor U_diff (difference,borrow1,borrow2,borrows);
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_gray_counter.v b/tests/asicworld/code_hdl_models_gray_counter.v
new file mode 100644 (file)
index 0000000..bc1e740
--- /dev/null
@@ -0,0 +1,33 @@
+//-----------------------------------------------------
+// Design Name : gray_counter
+// File Name   : gray_counter.v
+// Function    : 8 bit gray counterS
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module gray_counter (
+  out    , // counter out
+  enable , // enable for counter
+  clk    , // clock
+  rst      // active hight reset
+  );
+  
+  //------------Input Ports--------------
+  input clk, rst, enable; 
+  //----------Output Ports----------------
+  output [ 7:0] out;
+  //------------Internal Variables--------
+  wire [7:0] out;
+  reg [7:0] count;
+  //-------------Code Starts Here---------
+  always @ (posedge clk) 
+  if (rst) 
+    count <= 0; 
+  else if (enable) 
+    count <= count + 1; 
+    
+  assign out = { count[7], (count[7] ^ count[6]),(count[6] ^ 
+               count[5]),(count[5] ^ count[4]), (count[4] ^ 
+               count[3]),(count[3] ^ count[2]), (count[2] ^ 
+               count[1]),(count[1] ^ count[0]) };
+    
+endmodule 
diff --git a/tests/asicworld/code_hdl_models_half_adder_gates.v b/tests/asicworld/code_hdl_models_half_adder_gates.v
new file mode 100644 (file)
index 0000000..6acf243
--- /dev/null
@@ -0,0 +1,14 @@
+//-----------------------------------------------------
+// Design Name : half_adder_gates
+// File Name   : half_adder_gates.v
+// Function    : CCITT Serial CRC
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module half_adder_gates(x,y,sum,carry);
+input x,y;
+output sum,carry;
+
+and U_carry (carry,x,y);
+xor U_sum (sum,x,y);
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_lfsr.v b/tests/asicworld/code_hdl_models_lfsr.v
new file mode 100644 (file)
index 0000000..6397808
--- /dev/null
@@ -0,0 +1,35 @@
+//-----------------------------------------------------
+// Design Name : lfsr
+// File Name   : lfsr.v
+// Function    : Linear feedback shift register
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module lfsr    (
+out             ,  // Output of the counter
+enable          ,  // Enable  for counter
+clk             ,  // clock input
+reset              // reset input
+);
+
+//----------Output Ports--------------
+output [7:0] out;
+//------------Input Ports--------------
+input enable, clk, reset;
+//------------Internal Variables--------
+reg [7:0] out;
+wire        linear_feedback;
+
+//-------------Code Starts Here-------
+assign linear_feedback = !(out[7] ^ out[3]);
+
+always @(posedge clk)
+if (reset) begin // active high reset
+  out <= 8'b0 ;
+end else if (enable) begin
+  out <= {out[6],out[5],
+          out[4],out[3],
+          out[2],out[1],
+          out[0], linear_feedback};
+end 
+
+endmodule // End Of Module counter
diff --git a/tests/asicworld/code_hdl_models_lfsr_updown.v b/tests/asicworld/code_hdl_models_lfsr_updown.v
new file mode 100644 (file)
index 0000000..0bd29b8
--- /dev/null
@@ -0,0 +1,35 @@
+`define WIDTH 8 
+module lfsr_updown (
+clk       ,   // Clock input
+reset     ,   // Reset input
+enable    ,   // Enable input
+up_down   ,   // Up Down input
+count     ,   // Count output
+overflow      // Overflow output
+);
+
+ input clk;
+ input reset;
+ input enable; 
+ input up_down;
+
+ output [`WIDTH-1 : 0] count;
+ output overflow;
+
+ reg [`WIDTH-1 : 0] count;
+
+ assign overflow = (up_down) ? (count == {{`WIDTH-1{1'b0}}, 1'b1}) : 
+                               (count == {1'b1, {`WIDTH-1{1'b0}}}) ;
+
+ always @(posedge clk)
+ if (reset) 
+    count <= {`WIDTH{1'b0}};
+ else if (enable) begin
+    if (up_down) begin
+      count <= {~(^(count & `WIDTH'b01100011)),count[`WIDTH-1:1]};
+    end else begin
+      count <= {count[`WIDTH-2:0],~(^(count &  `WIDTH'b10110001))};
+    end
+ end
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_misc1.v b/tests/asicworld/code_hdl_models_misc1.v
new file mode 100644 (file)
index 0000000..e3d9d5d
--- /dev/null
@@ -0,0 +1,22 @@
+module misc1 (a,b,c,d,y);
+input a, b,c,d;
+output y;
+
+wire net1,net2,net3;
+
+supply1 vdd;
+supply0 vss;
+
+// y = !((a+b+c).d)
+
+pmos p1 (vdd,net1,a);
+pmos p2 (net1,net2,b);
+pmos p3 (net2,y,c);
+pmos p4 (vdd,y,d);
+
+nmos n1 (vss,net3,a);
+nmos n2 (vss,net3,b);
+nmos n3 (vss,net3,c);
+nmos n4 (net3,y,d);
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_mux21_switch.v b/tests/asicworld/code_hdl_models_mux21_switch.v
new file mode 100644 (file)
index 0000000..519c07f
--- /dev/null
@@ -0,0 +1,22 @@
+//-----------------------------------------------------
+// Design Name : mux21_switch
+// File Name   : mux21_switch.v
+// Function    : 2:1 Mux using Switch Primitives
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module mux21_switch (out, ctrl, in1, in2);
+   
+   output out;                    
+   input  ctrl, in1, in2;         
+   wire          w;            
+
+   supply1 power;             
+   supply0 ground;      
+   
+   pmos N1 (w, power, ctrl);     
+   nmos N2 (w, ground, ctrl);   
+   
+   cmos C1 (out, in1, w, ctrl);   
+   cmos C2 (out, in2, ctrl, w);
+   
+endmodule
diff --git a/tests/asicworld/code_hdl_models_mux_2to1_gates.v b/tests/asicworld/code_hdl_models_mux_2to1_gates.v
new file mode 100644 (file)
index 0000000..fc76215
--- /dev/null
@@ -0,0 +1,18 @@
+//-----------------------------------------------------
+// Design Name : mux_2to1_gates
+// File Name   : mux_2to1_gates.v
+// Function    : 2:1 Mux using Gate Primitives
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module mux_2to1_gates(a,b,sel,y);
+input a,b,sel;
+output y;
+
+wire sel,a_sel,b_sel;
+
+not U_inv (inv_sel,sel);
+and U_anda (asel,a,inv_sel),
+    U_andb (bsel,b,sel);
+or U_or (y,asel,bsel);
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_mux_using_assign.v b/tests/asicworld/code_hdl_models_mux_using_assign.v
new file mode 100644 (file)
index 0000000..4284f10
--- /dev/null
@@ -0,0 +1,22 @@
+//-----------------------------------------------------
+// Design Name : mux_using_assign
+// File Name   : mux_using_assign.v
+// Function    : 2:1 Mux using Assign
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module  mux_using_assign(
+din_0      , // Mux first input
+din_1      , // Mux Second input
+sel        , // Select input
+mux_out      // Mux output
+);
+//-----------Input Ports---------------
+input din_0, din_1, sel ;
+//-----------Output Ports---------------
+output mux_out;
+//------------Internal Variables--------
+wire  mux_out;
+//-------------Code Start-----------------
+assign mux_out = (sel) ? din_1 : din_0;
+
+endmodule //End Of Module mux
diff --git a/tests/asicworld/code_hdl_models_mux_using_case.v b/tests/asicworld/code_hdl_models_mux_using_case.v
new file mode 100644 (file)
index 0000000..123da44
--- /dev/null
@@ -0,0 +1,28 @@
+//-----------------------------------------------------
+// Design Name : mux_using_case
+// File Name   : mux_using_case.v
+// Function    : 2:1 Mux using Case
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module  mux_using_case(
+din_0      , // Mux first input
+din_1      , // Mux Second input
+sel           , // Select input
+mux_out   // Mux output
+);
+//-----------Input Ports---------------
+input din_0, din_1, sel ;
+//-----------Output Ports---------------
+output mux_out;
+//------------Internal Variables--------
+reg  mux_out;
+//-------------Code Starts Here---------
+always @ (sel or din_0 or din_1)
+begin : MUX
+ case(sel ) 
+    1'b0 : mux_out = din_0;
+    1'b1 : mux_out = din_1;
+ endcase 
+end
+
+endmodule //End Of Module mux
diff --git a/tests/asicworld/code_hdl_models_mux_using_if.v b/tests/asicworld/code_hdl_models_mux_using_if.v
new file mode 100644 (file)
index 0000000..4d42e20
--- /dev/null
@@ -0,0 +1,29 @@
+//-----------------------------------------------------
+// Design Name : mux_using_if
+// File Name   : mux_using_if.v
+// Function    : 2:1 Mux using If
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module  mux_using_if(
+din_0      , // Mux first input
+din_1      , // Mux Second input
+sel        , // Select input
+mux_out      // Mux output
+);
+//-----------Input Ports---------------
+input din_0, din_1, sel ;
+//-----------Output Ports---------------
+output mux_out;
+//------------Internal Variables--------
+reg  mux_out;
+//-------------Code Starts Here---------
+always @ (sel or din_0 or din_1)
+begin : MUX
+  if (sel == 1'b0) begin
+      mux_out = din_0;
+  end else begin
+      mux_out = din_1 ;
+  end
+end
+
+endmodule //End Of Module mux
diff --git a/tests/asicworld/code_hdl_models_nand_switch.v b/tests/asicworld/code_hdl_models_nand_switch.v
new file mode 100644 (file)
index 0000000..1ccdd3a
--- /dev/null
@@ -0,0 +1,14 @@
+module nand_switch(a,b,out);
+input a,b;
+output out;
+
+supply0 vss;
+supply1 vdd;
+wire net1;
+
+pmos p1 (vdd,out,a);
+pmos p2 (vdd,out,b);
+nmos n1 (vss,net1,a);
+nmos n2 (net1,out,b);
+
+endmodule
\ No newline at end of file
diff --git a/tests/asicworld/code_hdl_models_one_hot_cnt.v b/tests/asicworld/code_hdl_models_one_hot_cnt.v
new file mode 100644 (file)
index 0000000..f6b84c6
--- /dev/null
@@ -0,0 +1,31 @@
+//-----------------------------------------------------
+// Design Name : one_hot_cnt
+// File Name   : one_hot_cnt.v
+// Function    : 8 bit one hot counter
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module one_hot_cnt (
+out        ,  // Output of the counter
+enable     ,  // enable for counter
+clk        ,  // clock input
+reset         // reset input
+);
+//----------Output Ports--------------
+output [7:0] out;
+
+//------------Input Ports--------------
+input enable, clk, reset;
+
+//------------Internal Variables--------
+reg [7:0] out;  
+
+//-------------Code Starts Here-------
+always @ (posedge clk)
+if (reset) begin
+  out <= 8'b0000_0001 ;
+end else if (enable) begin
+  out <= {out[6],out[5],out[4],out[3],
+          out[2],out[1],out[0],out[7]};
+end
+
+endmodule  
diff --git a/tests/asicworld/code_hdl_models_parallel_crc.v b/tests/asicworld/code_hdl_models_parallel_crc.v
new file mode 100644 (file)
index 0000000..d8d0bf1
--- /dev/null
@@ -0,0 +1,53 @@
+//-----------------------------------------------------
+// Design Name : parallel_crc_ccitt
+// File Name   : parallel_crc.v
+// Function    : CCITT Parallel CRC
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module parallel_crc_ccitt (
+clk     ,
+reset   ,
+enable  ,
+init    , 
+data_in , 
+crc_out
+);
+//-----------Input Ports---------------
+input clk     ;
+input reset   ;
+input enable  ;
+input init    ;
+input [7:0] data_in ;
+//-----------Output Ports---------------
+output [15:0] crc_out;
+//------------Internal Variables--------
+reg [15:0]   crc_reg;
+wire [15:0]  next_crc;
+//-------------Code Start-----------------
+assign crc_out = crc_reg;
+// CRC Control logic
+always @ (posedge clk)
+if (reset) begin
+  crc_reg <= 16'hFFFF;
+end else if (enable) begin
+  if (init) begin
+     crc_reg <= 16'hFFFF;
+  end else begin
+     crc_reg <= next_crc;
+  end
+end
+// Parallel CRC calculation
+assign next_crc[0] = data_in[7] ^ data_in[0] ^ crc_reg[4] ^ crc_reg[11];
+assign next_crc[1] = data_in[1] ^ crc_reg[5];
+assign next_crc[2] = data_in[2] ^ crc_reg[6];
+assign next_crc[3] = data_in[3] ^ crc_reg[7];
+assign next_crc[4] = data_in[4] ^ crc_reg[8];
+assign next_crc[5] = data_in[7] ^ data_in[5] ^ data_in[0] ^ crc_reg[4] ^ crc_reg[9] ^ crc_reg[11];
+assign next_crc[6] = data_in[6] ^ data_in[1] ^ crc_reg[5] ^ crc_reg[10];
+assign next_crc[7] = data_in[7] ^ data_in[2] ^ crc_reg[6] ^ crc_reg[11];
+assign next_crc[8] = data_in[3] ^ crc_reg[0] ^ crc_reg[7];
+assign next_crc[9] = data_in[4] ^ crc_reg[1] ^ crc_reg[8];
+assign next_crc[10] = data_in[5] ^ crc_reg[2] ^ crc_reg[9];
+assign next_crc[11] = data_in[6] ^ crc_reg[3] ^ crc_reg[10];
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_parity_using_assign.v b/tests/asicworld/code_hdl_models_parity_using_assign.v
new file mode 100644 (file)
index 0000000..b0282e8
--- /dev/null
@@ -0,0 +1,21 @@
+//-----------------------------------------------------
+// Design Name : parity_using_assign
+// File Name   : parity_using_assign.v
+// Function    : Parity using assign
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module parity_using_assign (
+data_in    , //  8 bit data in
+parity_out   //  1 bit parity out
+);
+output  parity_out ;
+input [7:0] data_in ; 
+     
+wire parity_out ;
+      
+assign parity_out =  (data_in[0] ^ data_in[1]) ^  
+                     (data_in[2] ^ data_in[3]) ^ 
+                     (data_in[4] ^ data_in[5]) ^  
+                     (data_in[6] ^ data_in[7]);
+
+endmodule 
diff --git a/tests/asicworld/code_hdl_models_parity_using_bitwise.v b/tests/asicworld/code_hdl_models_parity_using_bitwise.v
new file mode 100644 (file)
index 0000000..0046fb1
--- /dev/null
@@ -0,0 +1,16 @@
+//-----------------------------------------------------
+// Design Name : parity_using_bitwise
+// File Name   : parity_using_bitwise.v
+// Function    : Parity using bitwise xor
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module parity_using_bitwise (
+data_in    , //  8 bit data in
+parity_out   //  1 bit parity out
+);
+output  parity_out ;
+input [7:0] data_in ; 
+     
+assign parity_out = ^data_in; 
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_parity_using_function.v b/tests/asicworld/code_hdl_models_parity_using_function.v
new file mode 100644 (file)
index 0000000..0d07aae
--- /dev/null
@@ -0,0 +1,29 @@
+//-----------------------------------------------------
+// Design Name : parity_using_function
+// File Name   : parity_using_function.v
+// Function    : Parity using function
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module parity_using_function (
+data_in    , //  8 bit data in
+parity_out   //  1 bit parity out
+);
+output  parity_out ;
+input [7:0] data_in ; 
+     
+wire parity_out ; 
+
+function parity;
+  input [31:0] data; 
+  begin
+    parity =  (data_in[0] ^ data_in[1]) ^  
+              (data_in[2] ^ data_in[3]) ^ 
+              (data_in[4] ^ data_in[5]) ^  
+              (data_in[6] ^ data_in[7]);
+  end 
+endfunction 
+      
+assign parity_out = parity(data_in);
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_pri_encoder_using_assign.v b/tests/asicworld/code_hdl_models_pri_encoder_using_assign.v
new file mode 100644 (file)
index 0000000..c1ce960
--- /dev/null
@@ -0,0 +1,36 @@
+//-----------------------------------------------------
+// Design Name : pri_encoder_using_assign
+// File Name   : pri_encoder_using_assign.v
+// Function    : Pri Encoder using assign
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module pri_encoder_using_assign (
+binary_out , //  4 bit binary output
+encoder_in , //  16-bit input 
+enable       //  Enable for the encoder
+);
+
+output [3:0] binary_out ;
+input  enable ; 
+input [15:0] encoder_in ; 
+
+wire [3:0] binary_out ;
+      
+assign  binary_out  = (!enable) ? 0 : (
+    (encoder_in == 16'bxxxx_xxxx_xxxx_xxx1) ? 0 : 
+    (encoder_in == 16'bxxxx_xxxx_xxxx_xx10) ? 1 : 
+    (encoder_in == 16'bxxxx_xxxx_xxxx_x100) ? 2 : 
+    (encoder_in == 16'bxxxx_xxxx_xxxx_1000) ? 3 : 
+    (encoder_in == 16'bxxxx_xxxx_xxx1_0000) ? 4 : 
+    (encoder_in == 16'bxxxx_xxxx_xx10_0000) ? 5 : 
+    (encoder_in == 16'bxxxx_xxxx_x100_0000) ? 6 : 
+    (encoder_in == 16'bxxxx_xxxx_1000_0000) ? 7 : 
+    (encoder_in == 16'bxxxx_xxx1_0000_0000) ? 8 : 
+    (encoder_in == 16'bxxxx_xx10_0000_0000) ? 9 : 
+    (encoder_in == 16'bxxxx_x100_0000_0000) ? 10 : 
+    (encoder_in == 16'bxxxx_1000_0000_0000) ? 11 : 
+    (encoder_in == 16'bxxx1_0000_0000_0000) ? 12 : 
+    (encoder_in == 16'bxx10_0000_0000_0000) ? 13 : 
+    (encoder_in == 16'bx100_0000_0000_0000) ? 14 : 15); 
+
+endmodule 
diff --git a/tests/asicworld/code_hdl_models_ram_sp_ar_sw.v b/tests/asicworld/code_hdl_models_ram_sp_ar_sw.v
new file mode 100644 (file)
index 0000000..d3338f7
--- /dev/null
@@ -0,0 +1,58 @@
+//-----------------------------------------------------
+// Design Name : ram_sp_ar_sw
+// File Name   : ram_sp_ar_sw.v
+// Function    : Asynchronous read write RAM 
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module ram_sp_ar_sw (
+clk         , // Clock Input
+address     , // Address Input
+data        , // Data bi-directional
+cs          , // Chip Select
+we          , // Write Enable/Read Enable
+oe            // Output Enable
+); 
+
+parameter DATA_WIDTH = 8 ;
+parameter ADDR_WIDTH = 8 ;
+parameter RAM_DEPTH = 1 << ADDR_WIDTH;
+
+//--------------Input Ports----------------------- 
+input                                     clk          ;
+input [ADDR_WIDTH-1:0] address ;
+input                                     cs           ;
+input                                     we          ;
+input                                     oe           ; 
+
+//--------------Inout Ports----------------------- 
+inout [DATA_WIDTH-1:0]  data       ;
+
+//--------------Internal variables---------------- 
+reg [DATA_WIDTH-1:0]   data_out ;
+reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
+
+//--------------Code Starts Here------------------ 
+
+// Tri-State Buffer control 
+// output : When we = 0, oe = 1, cs = 1
+assign data = (cs && oe && !we) ? data_out : 8'bz; 
+
+// Memory Write Block 
+// Write Operation : When we = 1, cs = 1
+always @ (posedge clk)
+begin : MEM_WRITE
+   if ( cs && we ) begin
+       mem[address] = data;
+   end
+end
+
+// Memory Read Block 
+// Read Operation : When we = 0, oe = 1, cs = 1
+always @ (address or cs or we or oe)
+begin : MEM_READ
+    if (cs && !we && oe) begin
+         data_out = mem[address];
+    end
+end
+
+endmodule // End of Module ram_sp_ar_sw
diff --git a/tests/asicworld/code_hdl_models_ram_sp_sr_sw.v b/tests/asicworld/code_hdl_models_ram_sp_sr_sw.v
new file mode 100644 (file)
index 0000000..c7fd955
--- /dev/null
@@ -0,0 +1,62 @@
+//-----------------------------------------------------
+// Design Name : ram_sp_sr_sw
+// File Name   : ram_sp_sr_sw.v
+// Function    : Synchronous read write RAM 
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module ram_sp_sr_sw (
+clk         , // Clock Input
+address     , // Address Input
+data        , // Data bi-directional
+cs          , // Chip Select
+we          , // Write Enable/Read Enable
+oe            // Output Enable
+); 
+
+parameter DATA_WIDTH = 8 ;
+parameter ADDR_WIDTH = 8 ;
+parameter RAM_DEPTH = 1 << ADDR_WIDTH;
+
+//--------------Input Ports----------------------- 
+input                  clk         ;
+input [ADDR_WIDTH-1:0] address     ;
+input                  cs          ;
+input                  we          ;
+input                  oe          ; 
+
+//--------------Inout Ports----------------------- 
+inout [DATA_WIDTH-1:0]  data       ;
+
+//--------------Internal variables---------------- 
+reg [DATA_WIDTH-1:0] data_out ;
+reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
+reg                  oe_r;
+
+//--------------Code Starts Here------------------ 
+
+// Tri-State Buffer control 
+// output : When we = 0, oe = 1, cs = 1
+assign data = (cs && oe && !we) ? data_out : 8'bz; 
+
+// Memory Write Block 
+// Write Operation : When we = 1, cs = 1
+always @ (posedge clk)
+begin : MEM_WRITE
+   if ( cs && we ) begin
+       mem[address] = data;
+   end
+end
+
+// Memory Read Block 
+// Read Operation : When we = 0, oe = 1, cs = 1
+always @ (posedge clk)
+begin : MEM_READ
+  if (cs && !we && oe) begin
+    data_out = mem[address];
+    oe_r = 1;
+  end else begin
+    oe_r = 0;
+  end
+end
+
+endmodule // End of Module ram_sp_sr_sw
diff --git a/tests/asicworld/code_hdl_models_rom_using_case.v b/tests/asicworld/code_hdl_models_rom_using_case.v
new file mode 100644 (file)
index 0000000..6b70099
--- /dev/null
@@ -0,0 +1,42 @@
+//-----------------------------------------------------
+// Design Name : rom_using_case
+// File Name   : rom_using_case.v
+// Function    : ROM using case
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module rom_using_case (
+address , // Address input
+data    , // Data output
+read_en , // Read Enable 
+ce        // Chip Enable
+);
+input [3:0] address;
+output [7:0] data;
+input read_en;
+input ce;
+
+reg [7:0] data ;
+       
+always @ (ce or read_en or address)
+begin
+  case (address)
+    0 : data = 10;
+    1 : data = 55;
+    2 : data = 244;
+    3 : data = 0;
+    4 : data = 1;
+    5 : data = 8'hff;
+    6 : data = 8'h11;
+    7 : data = 8'h1;
+    8 : data = 8'h10;
+    9 : data = 8'h0;
+    10 : data = 8'h10;
+    11 : data = 8'h15;
+    12 : data = 8'h60;
+    13 : data = 8'h90;
+    14 : data = 8'h70;
+    15 : data = 8'h90;
+  endcase
+end
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_serial_crc.v b/tests/asicworld/code_hdl_models_serial_crc.v
new file mode 100644 (file)
index 0000000..a4a63a2
--- /dev/null
@@ -0,0 +1,54 @@
+//-----------------------------------------------------
+// Design Name : serial_crc_ccitt
+// File Name   : serial_crc.v
+// Function    : CCITT Serial CRC
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module serial_crc_ccitt (
+clk     ,
+reset   ,
+enable  ,
+init    , 
+data_in , 
+crc_out
+);
+//-----------Input Ports---------------
+input clk     ;
+input reset   ;
+input enable  ;
+input init    ;
+input data_in ;
+//-----------Output Ports---------------
+output [15:0] crc_out;
+//------------Internal Variables--------
+reg   [15:0] lfsr;
+//-------------Code Start-----------------
+assign crc_out = lfsr;
+// Logic to CRC Calculation
+always @ (posedge clk)
+if (reset) begin
+  lfsr <= 16'hFFFF;
+end else if (enable) begin
+  if (init) begin
+    lfsr <=  16'hFFFF;
+  end else begin
+    lfsr[0]  <= data_in ^ lfsr[15];
+    lfsr[1]  <= lfsr[0];
+    lfsr[2]  <= lfsr[1];
+    lfsr[3]  <= lfsr[2];
+    lfsr[4]  <= lfsr[3];
+    lfsr[5]  <= lfsr[4] ^ data_in ^ lfsr[15];
+    lfsr[6]  <= lfsr[5];
+    lfsr[7]  <= lfsr[6];
+    lfsr[8]  <= lfsr[7];
+    lfsr[9]  <= lfsr[8];
+    lfsr[10] <= lfsr[9];
+    lfsr[11] <= lfsr[10];
+    lfsr[12] <= lfsr[11] ^ data_in ^ lfsr[15];
+    lfsr[13] <= lfsr[12];
+    lfsr[14] <= lfsr[13];
+    lfsr[15] <= lfsr[14];
+  end
+end 
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_t_gate_switch.v b/tests/asicworld/code_hdl_models_t_gate_switch.v
new file mode 100644 (file)
index 0000000..1bff66a
--- /dev/null
@@ -0,0 +1,11 @@
+module t_gate_switch (L,R,nC,C);\r
+ inout L;\r
+ inout R;\r
+ input nC;\r
+ input C;\r
+\r
+ //Syntax: keyword unique_name (drain. source, gate);\r
+ pmos p1 (L,R,nC);\r
+ nmos p2 (L,R,C);\r
+\r
+endmodule\r
diff --git a/tests/asicworld/code_hdl_models_tff_async_reset.v b/tests/asicworld/code_hdl_models_tff_async_reset.v
new file mode 100644 (file)
index 0000000..4c5a1fa
--- /dev/null
@@ -0,0 +1,27 @@
+//-----------------------------------------------------
+// Design Name : tff_async_reset
+// File Name   : tff_async_reset.v
+// Function    : T flip-flop async reset
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module tff_async_reset (
+data  , // Data Input
+clk   , // Clock Input
+reset , // Reset input
+q       // Q output
+);
+//-----------Input Ports---------------
+input data, clk, reset ; 
+//-----------Output Ports---------------
+output q;
+//------------Internal Variables--------
+reg q;
+//-------------Code Starts Here---------
+always @ ( posedge clk or negedge reset)
+if (~reset) begin
+  q <= 1'b0;
+end else if (data) begin
+  q <= !q;
+end
+
+endmodule //End Of Module tff_async_reset
diff --git a/tests/asicworld/code_hdl_models_tff_sync_reset.v b/tests/asicworld/code_hdl_models_tff_sync_reset.v
new file mode 100644 (file)
index 0000000..a962d53
--- /dev/null
@@ -0,0 +1,27 @@
+//-----------------------------------------------------
+// Design Name : tff_sync_reset
+// File Name   : tff_sync_reset.v
+// Function    : T flip-flop sync reset
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module tff_sync_reset (
+data  , // Data Input
+clk   , // Clock Input
+reset , // Reset input
+q       // Q output
+);
+//-----------Input Ports---------------
+input data, clk, reset ; 
+//-----------Output Ports---------------
+output q;
+//------------Internal Variables--------
+reg q;
+//-------------Code Starts Here---------
+always @ ( posedge clk)
+if (~reset) begin
+  q <= 1'b0;
+end else if (data) begin
+  q <= !q;
+end
+
+endmodule //End Of Module tff_async_reset
diff --git a/tests/asicworld/code_hdl_models_uart.v b/tests/asicworld/code_hdl_models_uart.v
new file mode 100644 (file)
index 0000000..4020525
--- /dev/null
@@ -0,0 +1,154 @@
+//-----------------------------------------------------
+// Design Name : uart 
+// File Name   : uart.v
+// Function    : Simple UART
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module uart (
+reset          ,
+txclk          ,
+ld_tx_data     ,
+tx_data        ,
+tx_enable      ,
+tx_out         ,
+tx_empty       ,
+rxclk          ,
+uld_rx_data    ,
+rx_data        ,
+rx_enable      ,
+rx_in          ,
+rx_empty
+);
+// Port declarations
+input        reset          ;
+input        txclk          ;
+input        ld_tx_data     ;
+input  [7:0] tx_data        ;
+input        tx_enable      ;
+output       tx_out         ;
+output       tx_empty       ;
+input        rxclk          ;
+input        uld_rx_data    ;
+output [7:0] rx_data        ;
+input        rx_enable      ;
+input        rx_in          ;
+output       rx_empty       ;
+
+// Internal Variables 
+reg [7:0]    tx_reg         ;
+reg          tx_empty       ;
+reg          tx_over_run    ;
+reg [3:0]    tx_cnt         ;
+reg          tx_out         ;
+reg [7:0]    rx_reg         ;
+reg [7:0]    rx_data        ;
+reg [3:0]    rx_sample_cnt  ;
+reg [3:0]    rx_cnt         ;  
+reg          rx_frame_err   ;
+reg          rx_over_run    ;
+reg          rx_empty       ;
+reg          rx_d1          ;
+reg          rx_d2          ;
+reg          rx_busy        ;
+
+// UART RX Logic
+always @ (posedge rxclk or posedge reset)
+if (reset) begin
+  rx_reg        <= 0; 
+  rx_data       <= 0;
+  rx_sample_cnt <= 0;
+  rx_cnt        <= 0;
+  rx_frame_err  <= 0;
+  rx_over_run   <= 0;
+  rx_empty      <= 1;
+  rx_d1         <= 1;
+  rx_d2         <= 1;
+  rx_busy       <= 0;
+end else begin
+  // Synchronize the asynch signal
+  rx_d1 <= rx_in;
+  rx_d2 <= rx_d1;
+  // Uload the rx data
+  if (uld_rx_data) begin
+    rx_data  <= rx_reg;
+    rx_empty <= 1;
+  end
+  // Receive data only when rx is enabled
+  if (rx_enable) begin
+    // Check if just received start of frame
+    if (!rx_busy && !rx_d2) begin
+      rx_busy       <= 1;
+      rx_sample_cnt <= 1;
+      rx_cnt        <= 0;
+    end
+    // Start of frame detected, Proceed with rest of data
+    if (rx_busy) begin
+       rx_sample_cnt <= rx_sample_cnt + 1;
+       // Logic to sample at middle of data
+       if (rx_sample_cnt == 7) begin
+          if ((rx_d2 == 1) && (rx_cnt == 0)) begin
+            rx_busy <= 0;
+          end else begin
+            rx_cnt <= rx_cnt + 1; 
+            // Start storing the rx data
+            if (rx_cnt > 0 && rx_cnt < 9) begin
+              rx_reg[rx_cnt - 1] <= rx_d2;
+            end
+            if (rx_cnt == 9) begin
+               rx_busy <= 0;
+               // Check if End of frame received correctly
+               if (rx_d2 == 0) begin
+                 rx_frame_err <= 1;
+               end else begin
+                 rx_empty     <= 0;
+                 rx_frame_err <= 0;
+                 // Check if last rx data was not unloaded,
+                 rx_over_run  <= (rx_empty) ? 0 : 1;
+               end
+            end
+          end
+       end 
+    end 
+  end
+  if (!rx_enable) begin
+    rx_busy <= 0;
+  end
+end
+
+// UART TX Logic
+always @ (posedge txclk or posedge reset)
+if (reset) begin
+  tx_reg        <= 0;
+  tx_empty      <= 1;
+  tx_over_run   <= 0;
+  tx_out        <= 1;
+  tx_cnt        <= 0;
+end else begin
+   if (ld_tx_data) begin
+      if (!tx_empty) begin
+        tx_over_run <= 0;
+      end else begin
+        tx_reg   <= tx_data;
+        tx_empty <= 0;
+      end
+   end
+   if (tx_enable && !tx_empty) begin
+     tx_cnt <= tx_cnt + 1;
+     if (tx_cnt == 0) begin
+       tx_out <= 0;
+     end
+     if (tx_cnt > 0 && tx_cnt < 9) begin
+        tx_out <= tx_reg[tx_cnt -1];
+     end
+     if (tx_cnt == 9) begin
+       tx_out <= 1;
+       tx_cnt <= 0;
+       tx_empty <= 1;
+     end
+   end
+   if (!tx_enable) begin
+     tx_cnt <= 0;
+   end
+end
+
+endmodule
diff --git a/tests/asicworld/code_hdl_models_up_counter.v b/tests/asicworld/code_hdl_models_up_counter.v
new file mode 100644 (file)
index 0000000..ffe6709
--- /dev/null
@@ -0,0 +1,29 @@
+//-----------------------------------------------------
+// Design Name : up_counter
+// File Name   : up_counter.v
+// Function    : Up counter
+// Coder      : Deepak
+//-----------------------------------------------------
+module up_counter    (
+out     ,  // Output of the counter
+enable  ,  // enable for counter
+clk     ,  // clock Input
+reset      // reset Input
+);
+//----------Output Ports--------------
+    output [7:0] out;
+//------------Input Ports--------------
+     input enable, clk, reset;
+//------------Internal Variables--------
+    reg [7:0] out;
+//-------------Code Starts Here-------
+always @(posedge clk)
+if (reset) begin
+  out <= 8'b0 ;
+end else if (enable) begin
+  out <= out + 1;
+end
+
+
+endmodule 
+
diff --git a/tests/asicworld/code_hdl_models_up_counter_load.v b/tests/asicworld/code_hdl_models_up_counter_load.v
new file mode 100644 (file)
index 0000000..92ad895
--- /dev/null
@@ -0,0 +1,32 @@
+//-----------------------------------------------------
+// Design Name : up_counter_load
+// File Name   : up_counter_load.v
+// Function    : Up counter with load
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module up_counter_load    (
+out      ,  // Output of the counter
+data     ,  // Parallel load for the counter
+load     ,  // Parallel load enable
+enable   ,  // Enable counting
+clk      ,  // clock input
+reset       // reset input
+);
+//----------Output Ports--------------
+output [7:0] out;
+//------------Input Ports-------------- 
+input [7:0] data;
+input load, enable, clk, reset;
+//------------Internal Variables--------
+reg [7:0] out;
+//-------------Code Starts Here-------
+always @(posedge clk)
+if (reset) begin
+  out <= 8'b0 ;
+end else if (load) begin
+  out <= data;
+end else if (enable) begin
+  out <= out + 1;
+end
+    
+endmodule  
diff --git a/tests/asicworld/code_hdl_models_up_down_counter.v b/tests/asicworld/code_hdl_models_up_down_counter.v
new file mode 100644 (file)
index 0000000..fff2982
--- /dev/null
@@ -0,0 +1,29 @@
+//-----------------------------------------------------
+// Design Name : up_down_counter
+// File Name   : up_down_counter.v
+// Function    : Up down counter
+// Coder       : Deepak Kumar Tala
+//-----------------------------------------------------
+module up_down_counter    (
+out      ,  // Output of the counter
+up_down  ,  // up_down control for counter
+clk      ,  // clock input
+reset       // reset input
+);
+//----------Output Ports--------------
+output [7:0] out;
+//------------Input Ports-------------- 
+input up_down, clk, reset;
+//------------Internal Variables--------
+reg [7:0] out;
+//-------------Code Starts Here-------
+always @(posedge clk)
+if (reset) begin // active high reset
+  out <= 8'b0 ;
+end else if (up_down) begin
+  out <= out + 1;
+end else begin
+  out <= out - 1;
+end
+
+endmodule 
diff --git a/tests/asicworld/code_specman_switch_fabric.v b/tests/asicworld/code_specman_switch_fabric.v
new file mode 100644 (file)
index 0000000..1ac7ee7
--- /dev/null
@@ -0,0 +1,82 @@
+module switch_fabric(
+  clk, reset, data_in0, data_in1, data_in2,
+  data_in3, data_in4, data_in5, data_in_valid0,
+  data_in_valid1, data_in_valid2, data_in_valid3,
+  data_in_valid4, data_in_valid5, data_out0,
+  data_out1, data_out2, data_out3, data_out4,
+  data_out5, data_out_ack0, data_out_ack1,
+  data_out_ack2, data_out_ack3, data_out_ack4,
+  data_out_ack5
+);
+
+input           clk, reset;
+input  [7:0]    data_in0, data_in1, data_in2, data_in3;
+input  [7:0]    data_in4, data_in5;
+input           data_in_valid0, data_in_valid1, data_in_valid2;
+input  [7:0]    data_in_valid3, data_in_valid4, data_in_valid5;
+output [7:0]    data_out0, data_out1, data_out2, data_out3;
+output [7:0]    data_out4, data_out5;
+output          data_out_ack0, data_out_ack1, data_out_ack2;
+output [7:0]    data_out_ack3, data_out_ack4, data_out_ack5;
+
+(* gentb_clock *)
+wire clk;
+
+switch port_0 ( .clk(clk), .reset(reset), .data_in(data_in0), 
+  .data_in_valid(data_in_valid0), .data_out(data_out0), 
+  .data_out_ack(data_out_ack0));
+
+switch port_1 ( .clk(clk), .reset(reset), .data_in(data_in1), 
+  .data_in_valid(data_in_valid1), .data_out(data_out1), 
+  .data_out_ack(data_out_ack1));
+
+switch port_2 ( .clk(clk), .reset(reset), .data_in(data_in2), 
+  .data_in_valid(data_in_valid2), .data_out(data_out2), .
+  data_out_ack(data_out_ack2));
+
+switch port_3 ( .clk(clk), .reset(reset), .data_in(data_in3), 
+  .data_in_valid(data_in_valid3), .data_out(data_out3), 
+  .data_out_ack(data_out_ack3));
+
+switch port_4 ( .clk(clk), .reset(reset), .data_in(data_in4), 
+  .data_in_valid(data_in_valid4), .data_out(data_out4), 
+  .data_out_ack(data_out_ack4));
+
+switch port_5 ( .clk(clk), .reset(reset), .data_in(data_in5), 
+  .data_in_valid(data_in_valid5), .data_out(data_out5), 
+  .data_out_ack(data_out_ack5));
+
+endmodule
+
+module switch (
+  clk,
+  reset,
+  data_in,
+  data_in_valid,
+  data_out,
+  data_out_ack
+);
+
+input   clk;
+input   reset;
+input [7:0]  data_in;
+input   data_in_valid;
+output [7:0]  data_out;
+output  data_out_ack;
+
+reg [7:0]  data_out;
+reg   data_out_ack;
+
+always @ (posedge clk)
+if (reset) begin
+   data_out <= 0;
+   data_out_ack <= 0;
+end else if (data_in_valid) begin
+   data_out <= data_in;
+   data_out_ack <= 1;
+end else begin
+   data_out <= 0;
+   data_out_ack <= 0;
+end
+
+endmodule
diff --git a/tests/asicworld/code_tidbits_asyn_reset.v b/tests/asicworld/code_tidbits_asyn_reset.v
new file mode 100644 (file)
index 0000000..58e47c5
--- /dev/null
@@ -0,0 +1,18 @@
+module  asyn_reset(clk,reset,a,c);
+     input clk;
+     input reset;
+     input a;
+     output c; 
+
+   wire clk;
+   wire reset;   
+   wire a;    
+   reg c;
+        
+always @ (posedge clk or posedge reset)
+ if ( reset == 1'b1) begin
+   c <= 0;
+ end else begin
+   c <= a;
+ end
+endmodule
diff --git a/tests/asicworld/code_tidbits_blocking.v b/tests/asicworld/code_tidbits_blocking.v
new file mode 100644 (file)
index 0000000..e13b72c
--- /dev/null
@@ -0,0 +1,17 @@
+module blocking (clk,a,c);
+input clk;
+input a;
+output c;
+wire clk;
+wire a;
+reg c;
+reg b;
+  
+always @ (posedge clk )
+begin
+ b = a;
+ c = b;
+end
+   
+endmodule
diff --git a/tests/asicworld/code_tidbits_fsm_using_always.v b/tests/asicworld/code_tidbits_fsm_using_always.v
new file mode 100644 (file)
index 0000000..8a8775b
--- /dev/null
@@ -0,0 +1,91 @@
+//-----------------------------------------------------
+// This is FSM demo program using always block
+// Design Name : fsm_using_always
+// File Name   : fsm_using_always.v
+//-----------------------------------------------------
+module fsm_using_always (
+clock      , // clock
+reset      , // Active high, syn reset
+req_0      , // Request 0
+req_1      , // Request 1
+gnt_0      , // Grant 0
+gnt_1      
+);
+//-------------Input Ports-----------------------------
+input   clock,reset,req_0,req_1;
+ //-------------Output Ports----------------------------
+output  gnt_0,gnt_1;
+//-------------Input ports Data Type-------------------
+wire    clock,reset,req_0,req_1;
+//-------------Output Ports Data Type------------------
+reg     gnt_0,gnt_1;
+//-------------Internal Constants--------------------------
+parameter SIZE = 3           ;
+parameter IDLE  = 3'b001,GNT0 = 3'b010,GNT1 = 3'b100 ;
+//-------------Internal Variables---------------------------
+reg   [SIZE-1:0]          state        ;// Seq part of the FSM
+reg   [SIZE-1:0]          next_state   ;// combo part of FSM
+//----------Code startes Here------------------------
+always @ (state or req_0 or req_1)
+begin : FSM_COMBO
+ next_state = 3'b000;
+ case(state)
+   IDLE : if (req_0 == 1'b1) begin
+                next_state = GNT0;
+              end else if (req_1 == 1'b1) begin
+                next_state= GNT1;
+              end else begin
+                next_state = IDLE;
+              end
+   GNT0 : if (req_0 == 1'b1) begin
+                next_state = GNT0;
+              end else begin
+                next_state = IDLE;
+              end
+   GNT1 : if (req_1 == 1'b1) begin
+                next_state = GNT1;
+              end else begin
+                next_state = IDLE;
+              end
+   default : next_state = IDLE;
+  endcase
+end
+//----------Seq Logic-----------------------------
+always @ (posedge clock)
+begin : FSM_SEQ
+  if (reset == 1'b1) begin
+    state <= #1 IDLE;
+  end else begin
+    state <= #1 next_state;
+  end
+end
+//----------Output Logic-----------------------------
+always @ (posedge clock)
+begin : OUTPUT_LOGIC
+if (reset == 1'b1) begin
+  gnt_0 <= #1 1'b0;
+  gnt_1 <= #1 1'b0;
+end
+else begin
+  case(state)
+    IDLE : begin
+                  gnt_0 <= #1 1'b0;
+                  gnt_1 <= #1 1'b0;
+               end
+   GNT0 : begin
+                   gnt_0 <= #1 1'b1;
+                   gnt_1 <= #1 1'b0;
+                end
+   GNT1 : begin
+                   gnt_0 <= #1 1'b0;
+                   gnt_1 <= #1 1'b1;
+                end
+   default : begin
+                    gnt_0 <= #1 1'b0;
+                    gnt_1 <= #1 1'b0;
+                  end
+  endcase
+end
+end // End Of Block OUTPUT_LOGIC
+
+endmodule // End of Module arbiter
diff --git a/tests/asicworld/code_tidbits_fsm_using_function.v b/tests/asicworld/code_tidbits_fsm_using_function.v
new file mode 100644 (file)
index 0000000..404498a
--- /dev/null
@@ -0,0 +1,94 @@
+//-----------------------------------------------------
+// This is FSM demo program using function
+// Design Name : fsm_using_function
+// File Name   : fsm_using_function.v
+//-----------------------------------------------------
+module fsm_using_function (
+clock      , // clock
+reset      , // Active high, syn reset
+req_0      , // Request 0
+req_1      , // Request 1
+gnt_0      , // Grant 0
+gnt_1      
+);
+//-------------Input Ports-----------------------------
+input   clock,reset,req_0,req_1;
+ //-------------Output Ports----------------------------
+output  gnt_0,gnt_1;
+//-------------Input ports Data Type-------------------
+wire    clock,reset,req_0,req_1;
+//-------------Output Ports Data Type------------------
+reg     gnt_0,gnt_1;
+//-------------Internal Constants--------------------------
+parameter SIZE = 3           ;
+parameter IDLE  = 3'b001,GNT0 = 3'b010,GNT1 = 3'b100 ;
+//-------------Internal Variables---------------------------
+reg   [SIZE-1:0]          state        ;// Seq part of the FSM
+wire  [SIZE-1:0]          next_state   ;// combo part of FSM
+//----------Code startes Here------------------------
+assign next_state = fsm_function(state, req_0, req_1);
+//----------Function for Combo Logic-----------------
+function [SIZE-1:0] fsm_function;
+  input  [SIZE-1:0]  state ;   
+  input    req_0 ;
+  input    req_1 ;
+  case(state)
+   IDLE : if (req_0 == 1'b1) begin
+                fsm_function = GNT0;
+              end else if (req_1 == 1'b1) begin
+                fsm_function= GNT1;
+              end else begin
+                fsm_function = IDLE;
+              end
+   GNT0 : if (req_0 == 1'b1) begin
+                fsm_function = GNT0;
+              end else begin
+                fsm_function = IDLE;
+              end
+   GNT1 : if (req_1 == 1'b1) begin
+                fsm_function = GNT1;
+          end else begin
+                fsm_function = IDLE;
+              end
+   default : fsm_function = IDLE;
+  endcase
+endfunction
+//----------Seq Logic-----------------------------
+always @ (posedge clock)
+begin : FSM_SEQ
+  if (reset == 1'b1) begin
+    state <= #1 IDLE;
+  end else begin
+    state <= #1 next_state;
+  end
+end
+//----------Output Logic-----------------------------
+always @ (posedge clock)
+begin : OUTPUT_LOGIC
+if (reset == 1'b1) begin
+  gnt_0 <= #1 1'b0;
+  gnt_1 <= #1 1'b0;
+end
+else begin
+  case(state)
+    IDLE : begin
+                  gnt_0 <= #1 1'b0;
+                  gnt_1 <= #1 1'b0;
+               end
+   GNT0 : begin
+                   gnt_0 <= #1 1'b1;
+                   gnt_1 <= #1 1'b0;
+                end
+   GNT1 : begin
+                   gnt_0 <= #1 1'b0;
+                   gnt_1 <= #1 1'b1;
+                end
+   default : begin
+                    gnt_0 <= #1 1'b0;
+                    gnt_1 <= #1 1'b0;
+                  end
+  endcase
+end
+end // End Of Block OUTPUT_LOGIC
+
+endmodule // End of Module arbiter
diff --git a/tests/asicworld/code_tidbits_fsm_using_single_always.v b/tests/asicworld/code_tidbits_fsm_using_single_always.v
new file mode 100644 (file)
index 0000000..67cc088
--- /dev/null
@@ -0,0 +1,63 @@
+//====================================================
+// This is FSM demo program using single always
+// for both seq and combo logic
+// Design Name : fsm_using_single_always
+// File Name   : fsm_using_single_always.v
+//=====================================================
+module fsm_using_single_always (
+clock      , // clock
+reset      , // Active high, syn reset
+req_0      , // Request 0
+req_1      , // Request 1
+gnt_0      , // Grant 0
+gnt_1      
+);
+//=============Input Ports=============================
+input   clock,reset,req_0,req_1;
+ //=============Output Ports===========================
+output  gnt_0,gnt_1;
+//=============Input ports Data Type===================
+wire    clock,reset,req_0,req_1;
+//=============Output Ports Data Type==================
+reg     gnt_0,gnt_1;
+//=============Internal Constants======================
+parameter SIZE = 3           ;
+parameter IDLE  = 3'b001,GNT0 = 3'b010,GNT1 = 3'b100 ;
+//=============Internal Variables======================
+reg   [SIZE-1:0]          state        ;// Seq part of the FSM
+reg   [SIZE-1:0]          next_state   ;// combo part of FSM
+//==========Code startes Here==========================
+always @ (posedge clock)
+begin : FSM
+if (reset == 1'b1) begin
+  state <= #1 IDLE;
+  gnt_0 <= 0;
+  gnt_1 <= 0;
+end else
+ case(state)
+   IDLE : if (req_0 == 1'b1) begin
+                state <= #1 GNT0;
+                gnt_0 <= 1;
+              end else if (req_1 == 1'b1) begin
+                gnt_1 <= 1;
+                state <= #1 GNT1;
+              end else begin
+                state <= #1 IDLE;
+              end
+   GNT0 : if (req_0 == 1'b1) begin
+                state <= #1 GNT0;
+              end else begin
+                gnt_0 <= 0;
+                state <= #1 IDLE;
+              end
+   GNT1 : if (req_1 == 1'b1) begin
+                state <= #1 GNT1;
+              end else begin
+                gnt_1 <= 0;
+                state <= #1 IDLE;
+              end
+   default : state <= #1 IDLE;
+endcase
+end
+
+endmodule // End of Module arbiter
diff --git a/tests/asicworld/code_tidbits_nonblocking.v b/tests/asicworld/code_tidbits_nonblocking.v
new file mode 100644 (file)
index 0000000..4a0d365
--- /dev/null
@@ -0,0 +1,17 @@
+module nonblocking (clk,a,c);
+input clk;
+input a;
+output c;
+wire clk;
+wire a;
+reg c;
+reg b;
+  
+always @ (posedge clk )
+begin
+  b <= a;
+  c <= b;
+end
+   
+endmodule
diff --git a/tests/asicworld/code_tidbits_reg_combo_example.v b/tests/asicworld/code_tidbits_reg_combo_example.v
new file mode 100644 (file)
index 0000000..9689788
--- /dev/null
@@ -0,0 +1,13 @@
+module reg_combo_example( a, b, y);
+input a, b;
+output y;
+
+reg   y;
+wire a, b;
+
+always @ ( a or b)
+begin  
+  y = a & b;
+end
+
+endmodule
diff --git a/tests/asicworld/code_tidbits_reg_seq_example.v b/tests/asicworld/code_tidbits_reg_seq_example.v
new file mode 100644 (file)
index 0000000..458c879
--- /dev/null
@@ -0,0 +1,15 @@
+module reg_seq_example( clk, reset, d, q);
+input clk, reset, d;
+output q;
+  
+reg   q;
+wire clk, reset, d;
+
+always @ (posedge clk or posedge reset)
+if (reset) begin
+  q <= 1'b0;
+end else begin
+  q <= d;
+end
+
+endmodule
diff --git a/tests/asicworld/code_tidbits_syn_reset.v b/tests/asicworld/code_tidbits_syn_reset.v
new file mode 100644 (file)
index 0000000..994771b
--- /dev/null
@@ -0,0 +1,19 @@
+module syn_reset (clk,reset,a,c);
+   input clk;
+   input reset;
+   input a; 
+   output c; 
+
+   wire clk;
+   wire reset;   
+   wire a;   
+   reg c;
+  
+always @ (posedge clk )
+  if ( reset == 1'b1) begin
+    c <= 0;
+  end else begin
+    c <= a;
+  end
+endmodule 
diff --git a/tests/asicworld/code_tidbits_wire_example.v b/tests/asicworld/code_tidbits_wire_example.v
new file mode 100644 (file)
index 0000000..577a535
--- /dev/null
@@ -0,0 +1,9 @@
+module wire_example( a, b, y);
+  input a, b;
+  output y;
+
+  wire a, b, y;
+
+  assign y = a & b;
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_addbit.v b/tests/asicworld/code_verilog_tutorial_addbit.v
new file mode 100644 (file)
index 0000000..22063b0
--- /dev/null
@@ -0,0 +1,24 @@
+module addbit (
+a      , // first input
+b      , // Second input
+ci     , // Carry input
+sum    , // sum output
+co       // carry output
+);
+//Input declaration
+input a;
+input b;
+input ci;
+//Ouput declaration
+output sum;
+output co;
+//Port Data types
+wire  a;
+wire  b;
+wire  ci;
+wire  sum;
+wire  co;
+//Code starts here
+assign {co,sum} = a + b + ci;
+
+endmodule // End of Module addbit
diff --git a/tests/asicworld/code_verilog_tutorial_always_example.v b/tests/asicworld/code_verilog_tutorial_always_example.v
new file mode 100644 (file)
index 0000000..8b0fc20
--- /dev/null
@@ -0,0 +1,11 @@
+module always_example();
+reg clk,reset,enable,q_in,data;
+
+always @ (posedge clk)
+if (reset)  begin
+   data <= 0;
+end else if (enable) begin   
+   data <= q_in;
+end
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_bus_con.v b/tests/asicworld/code_verilog_tutorial_bus_con.v
new file mode 100644 (file)
index 0000000..b100c81
--- /dev/null
@@ -0,0 +1,8 @@
+module bus_con (a,b, y);
+               input [3:0] a, b;
+               output [7:0] y;
+               wire [7:0] y;
+                
+               assign y = {a,b};
+                
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_comment.v b/tests/asicworld/code_verilog_tutorial_comment.v
new file mode 100644 (file)
index 0000000..1cc0eb4
--- /dev/null
@@ -0,0 +1,25 @@
+/* This is a
+  Multi line comment
+  example */
+module addbit (
+a,
+b,
+ci,
+sum,
+co);
+
+// Input Ports  Single line comment
+input           a;
+input           b;
+input           ci;
+// Output ports
+output         sum;
+output         co;
+// Data Types      
+wire            a;
+wire            b;
+wire            ci;
+wire            sum;
+wire            co; 
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_counter.v b/tests/asicworld/code_verilog_tutorial_counter.v
new file mode 100644 (file)
index 0000000..5345197
--- /dev/null
@@ -0,0 +1,19 @@
+//-----------------------------------------------------\r
+// Design Name : counter\r
+// File Name   : counter.v\r
+// Function    : 4 bit up counter\r
+// Coder       : Deepak\r
+//-----------------------------------------------------\r
+module counter (clk, reset, enable, count);\r
+input clk, reset, enable;\r
+output [3:0] count;\r
+reg [3:0] count;                                   \r
+\r
+always @ (posedge clk)\r
+if (reset == 1'b1) begin\r
+  count <= 0;\r
+end else if ( enable == 1'b1) begin\r
+  count <= count + 1;\r
+end\r
+\r
+endmodule  \r
diff --git a/tests/asicworld/code_verilog_tutorial_counter_tb.v b/tests/asicworld/code_verilog_tutorial_counter_tb.v
new file mode 100644 (file)
index 0000000..1047793
--- /dev/null
@@ -0,0 +1,113 @@
+///////////////////////////////////////////////////////////////////////////\r
+// MODULE               : counter_tb                                     //\r
+// TOP MODULE           : --                                             //\r
+//                                                                       //\r
+// PURPOSE              : 4-bit up counter test bench                    //\r
+//                                                                       //\r
+// DESIGNER             : Deepak Kumar Tala                              //\r
+//                                                                       //\r
+// Revision History                                                      //\r
+//                                                                       //\r
+// DEVELOPMENT HISTORY  :                                                //\r
+//               Rev0.0 : Jan 03, 2003                                   //\r
+//                        Initial Revision                               //\r
+//                                                                       //\r
+///////////////////////////////////////////////////////////////////////////\r
+module testbench;\r
+\r
+reg clk, reset, enable;\r
+wire [3:0] count;\r
+reg dut_error;\r
+\r
+counter U0 (\r
+.clk    (clk),\r
+.reset  (reset),\r
+.enable (enable),\r
+.count  (count)\r
+);\r
+\r
+event reset_enable;\r
+event terminate_sim;\r
+\r
+initial\r
+begin\r
+ $display ("###################################################");\r
+ clk = 0;\r
+ reset = 0;\r
+ enable = 0;\r
+ dut_error = 0;\r
+end\r
+\r
+always\r
+  #5 clk = !clk;\r
+\r
+initial\r
+begin\r
+  $dumpfile ("counter.vcd");\r
+  $dumpvars;\r
+end\r
+\r
+\r
+initial\r
+@ (terminate_sim)  begin\r
+ $display ("Terminating simulation");\r
+ if (dut_error == 0) begin\r
+   $display ("Simulation Result : PASSED");\r
+ end\r
+ else begin\r
+   $display ("Simulation Result : FAILED");\r
+ end\r
+ $display ("###################################################");\r
+ #1 $finish;\r
+end\r
+\r
+\r
+\r
+event reset_done;\r
+\r
+initial\r
+forever begin\r
+ @ (reset_enable);\r
+ @ (negedge clk)\r
+ $display ("Applying reset");\r
+   reset = 1;\r
+ @ (negedge clk)\r
+   reset = 0;\r
+ $display ("Came out of Reset");\r
+ -> reset_done;\r
+end\r
+\r
+initial begin\r
+  #10 -> reset_enable;\r
+  @ (reset_done);\r
+  @ (negedge clk);\r
+  enable = 1;\r
+  repeat (5)\r
+  begin\r
+   @ (negedge clk);\r
+  end\r
+  enable = 0;\r
+  #5 -> terminate_sim;\r
+end\r
+\r
+\r
+reg [3:0] count_compare;\r
+\r
+always @ (posedge clk)\r
+if (reset == 1'b1)\r
+ count_compare <= 0;\r
+else if ( enable == 1'b1)\r
+ count_compare <= count_compare + 1;\r
+\r
+\r
+\r
+always @ (negedge clk)\r
+if (count_compare != count) begin\r
+  $display ("DUT ERROR AT TIME%d",$time);\r
+  $display ("Expected value %d, Got Value %d", count_compare, count);\r
+  dut_error = 1;\r
+  #5 -> terminate_sim;\r
+end\r
+\r
+endmodule\r
+\r
diff --git a/tests/asicworld/code_verilog_tutorial_d_ff.v b/tests/asicworld/code_verilog_tutorial_d_ff.v
new file mode 100644 (file)
index 0000000..7a40836
--- /dev/null
@@ -0,0 +1,14 @@
+// D flip-flop Code
+module d_ff ( d, clk, q, q_bar);
+input d ,clk;
+output q, q_bar;
+wire d ,clk;
+reg q, q_bar;
+        
+always @ (posedge clk)
+begin
+  q <= d;
+  q_bar <= !d;
+end
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_decoder.v b/tests/asicworld/code_verilog_tutorial_decoder.v
new file mode 100644 (file)
index 0000000..5efdbd7
--- /dev/null
@@ -0,0 +1,14 @@
+module decoder (in,out);
+input [2:0] in;
+output [7:0] out;
+wire [7:0] out;
+assign out  =          (in == 3'b000 ) ? 8'b0000_0001 : 
+(in == 3'b001 ) ? 8'b0000_0010 : 
+(in == 3'b010 ) ? 8'b0000_0100 : 
+(in == 3'b011 ) ? 8'b0000_1000 : 
+(in == 3'b100 ) ? 8'b0001_0000 : 
+(in == 3'b101 ) ? 8'b0010_0000 : 
+(in == 3'b110 ) ? 8'b0100_0000 : 
+(in == 3'b111 ) ? 8'b1000_0000 : 8'h00;
+                
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_decoder_always.v b/tests/asicworld/code_verilog_tutorial_decoder_always.v
new file mode 100644 (file)
index 0000000..4418ec7
--- /dev/null
@@ -0,0 +1,20 @@
+module decoder_always (in,out);
+input [2:0] in;
+output [7:0] out;
+reg [7:0] out;
+always @ (in)
+begin
+  out = 0;
+  case (in)
+    3'b001 : out = 8'b0000_0001;
+    3'b010 : out = 8'b0000_0010;
+    3'b011 : out = 8'b0000_0100;
+    3'b100 : out = 8'b0000_1000;
+    3'b101 : out = 8'b0001_0000;
+    3'b110 : out = 8'b0100_0000;
+    3'b111 : out = 8'b1000_0000;
+  endcase
+end
+                
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_escape_id.v b/tests/asicworld/code_verilog_tutorial_escape_id.v
new file mode 100644 (file)
index 0000000..6c33da1
--- /dev/null
@@ -0,0 +1,14 @@
+// There must be white space after the
+// string which uses escape character
+module \1dff (
+q,      // Q output
+\q~ ,   // Q_out output
+d,      // D input
+cl$k,   // CLOCK input
+\reset* // Reset input
+);
+
+input d, cl$k, \reset* ;
+output q, \q~ ;  
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_explicit.v b/tests/asicworld/code_verilog_tutorial_explicit.v
new file mode 100644 (file)
index 0000000..88427ff
--- /dev/null
@@ -0,0 +1,35 @@
+module explicit();
+reg clk,d,rst,pre;
+wire q;
+
+// Here q_bar is not connected
+// We can connect ports in any order
+dff u0 (  
+.q     (q),
+.d     (d),
+.clk   (clk),
+.q_bar         (),
+.rst   (rst),
+.pre   (pre)
+);
+
+endmodule
+
+// D fli-flop
+module dff (q, q_bar, clk, d, rst, pre);
+input clk, d, rst, pre;
+output q, q_bar;
+reg q;
+
+assign q_bar = ~q;
+
+always @ (posedge clk)
+if (rst == 1'b1) begin
+  q <= 0;
+end else if (pre == 1'b1) begin
+  q <= 1;
+end else begin
+  q <= d;
+end
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_first_counter.v b/tests/asicworld/code_verilog_tutorial_first_counter.v
new file mode 100644 (file)
index 0000000..d35d4aa
--- /dev/null
@@ -0,0 +1,47 @@
+//-----------------------------------------------------
+// This is my second Verilog Design
+// Design Name : first_counter
+// File Name : first_counter.v
+// Function : This is a 4 bit up-counter with
+// Synchronous active high reset and
+// with active high enable signal
+//-----------------------------------------------------
+module first_counter (
+clock , // Clock input of the design
+reset , // active high, synchronous Reset input
+enable , // Active high enable signal for counter
+counter_out // 4 bit vector output of the counter
+); // End of port list
+//-------------Input Ports-----------------------------
+input clock ;
+input reset ;
+input enable ;
+//-------------Output Ports----------------------------
+output [3:0] counter_out ;
+//-------------Input ports Data Type-------------------
+// By rule all the input ports should be wires   
+wire clock ;
+wire reset ;
+wire enable ;
+//-------------Output Ports Data Type------------------
+// Output port can be a storage element (reg) or a wire
+reg [3:0] counter_out ;
+
+//------------Code Starts Here-------------------------
+// Since this counter is a positive edge trigged one,
+// We trigger the below block with respect to positive
+// edge of the clock.
+always @ (posedge clock)
+begin : COUNTER // Block Name
+  // At every rising edge of clock we check if reset is active
+  // If active, we load the counter output with 4'b0000
+  if (reset == 1'b1) begin
+    counter_out <= 4'b0000;
+  end
+  // If enable is active, then we increment the counter
+  else if (enable == 1'b1) begin
+    counter_out <= counter_out + 1;
+  end
+end // End of Block COUNTER
+
+endmodule // End of Module counter
diff --git a/tests/asicworld/code_verilog_tutorial_first_counter_tb.v b/tests/asicworld/code_verilog_tutorial_first_counter_tb.v
new file mode 100644 (file)
index 0000000..f065732
--- /dev/null
@@ -0,0 +1,36 @@
+module testbench();
+// Declare inputs as regs and outputs as wires
+reg clock, reset, enable;
+wire [3:0] counter_out;
+
+// Initialize all variables
+initial begin        
+  $display ("time\t clk reset enable counter");        
+  $monitor ("%g\t %b   %b     %b      %b", 
+         $time, clock, reset, enable, counter_out);    
+  clock = 1;       // initial value of clock
+  reset = 0;       // initial value of reset
+  enable = 0;      // initial value of enable
+  #5 reset = 1;    // Assert the reset
+  #10 reset = 0;   // De-assert the reset
+  #10 enable = 1;  // Assert enable
+  #100 enable = 0; // De-assert enable
+  #5 $finish;      // Terminate simulation
+end
+
+// Clock generator
+initial begin
+  #1;
+  forever
+    #5 clock = ~clock; // Toggle clock every 5 ticks
+end
+
+// Connect DUT to test bench
+first_counter U_counter (
+clock,
+reset,
+enable,
+counter_out
+);
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_flip_flop.v b/tests/asicworld/code_verilog_tutorial_flip_flop.v
new file mode 100644 (file)
index 0000000..ed2e88c
--- /dev/null
@@ -0,0 +1,15 @@
+module flif_flop (clk,reset, q, d);
+input clk, reset, d;
+output q;
+reg q;
+                
+always @ (posedge clk )
+begin
+  if (reset == 1) begin
+    q <= 0;
+  end else begin
+    q <= d;
+  end
+end
+                
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_fsm_full.v b/tests/asicworld/code_verilog_tutorial_fsm_full.v
new file mode 100644 (file)
index 0000000..fd2d559
--- /dev/null
@@ -0,0 +1,114 @@
+module fsm_full(
+clock , // Clock
+reset , // Active high reset
+req_0 , // Active high request from agent 0
+req_1 , // Active high request from agent 1
+req_2 , // Active high request from agent 2
+req_3 , // Active high request from agent 3
+gnt_0 , // Active high grant to agent 0
+gnt_1 , // Active high grant to agent 1
+gnt_2 , // Active high grant to agent 2
+gnt_3   // Active high grant to agent 3
+);
+// Port declaration here
+input clock ; // Clock
+input reset ; // Active high reset
+input req_0 ; // Active high request from agent 0
+input req_1 ; // Active high request from agent 1
+input req_2 ; // Active high request from agent 2
+input req_3 ; // Active high request from agent 3
+output gnt_0 ; // Active high grant to agent 0
+output gnt_1 ; // Active high grant to agent 1
+output gnt_2 ; // Active high grant to agent 2
+output gnt_3 ; // Active high grant to agent 
+
+// Internal Variables
+reg    gnt_0 ; // Active high grant to agent 0
+reg    gnt_1 ; // Active high grant to agent 1
+reg    gnt_2 ; // Active high grant to agent 2
+reg    gnt_3 ; // Active high grant to agent 
+
+parameter  [2:0]  IDLE  = 3'b000;
+parameter  [2:0]  GNT0  = 3'b001;
+parameter  [2:0]  GNT1  = 3'b010;
+parameter  [2:0]  GNT2  = 3'b011;
+parameter  [2:0]  GNT3  = 3'b100;
+
+reg [2:0] state, next_state;
+
+always @ (state or req_0 or req_1 or req_2 or req_3)
+begin  
+  next_state = 0;
+  case(state)
+    IDLE : if (req_0 == 1'b1) begin
+            next_state = GNT0;
+           end else if (req_1 == 1'b1) begin
+            next_state= GNT1;
+           end else if (req_2 == 1'b1) begin
+            next_state= GNT2;
+           end else if (req_3 == 1'b1) begin
+            next_state= GNT3;
+          end else begin
+            next_state = IDLE;
+           end                 
+    GNT0 : if (req_0 == 1'b0) begin
+            next_state = IDLE;
+           end else begin
+            next_state = GNT0;
+         end
+    GNT1 : if (req_1 == 1'b0) begin
+            next_state = IDLE;
+           end else begin
+            next_state = GNT1;
+         end
+    GNT2 : if (req_2 == 1'b0) begin
+            next_state = IDLE;
+           end else begin
+            next_state = GNT2;
+         end
+    GNT3 : if (req_3 == 1'b0) begin
+            next_state = IDLE;
+           end else begin
+            next_state = GNT3;
+         end
+   default : next_state = IDLE;
+  endcase
+end
+
+always @ (posedge clock)
+begin : OUTPUT_LOGIC
+  if (reset) begin
+    gnt_0 <= 1'b0;
+    gnt_1 <= 1'b0;
+    gnt_2 <= 1'b0;
+    gnt_3 <= 1'b0;
+    state <= IDLE;
+  end else begin
+    state <= next_state;
+    case(state)
+       IDLE : begin
+                gnt_0 <= 1'b0;
+                gnt_1 <= 1'b0;
+                gnt_2 <= 1'b0;
+                gnt_3 <= 1'b0;
+              end
+       GNT0 : begin
+                gnt_0 <= 1'b1;
+              end
+        GNT1 : begin
+                 gnt_1 <= 1'b1;
+               end
+        GNT2 : begin
+                 gnt_2 <= 1'b1;
+               end
+        GNT3 : begin
+                 gnt_3 <= 1'b1;
+               end
+     default : begin
+                 state <= IDLE;
+               end
+    endcase
+  end
+end
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_fsm_full_tb.v b/tests/asicworld/code_verilog_tutorial_fsm_full_tb.v
new file mode 100644 (file)
index 0000000..0097b1c
--- /dev/null
@@ -0,0 +1,48 @@
+module testbench();
+reg clock , reset ;
+reg req_0 , req_1 ,  req_2 , req_3; 
+wire gnt_0 , gnt_1 , gnt_2 , gnt_3 ;
+
+initial begin
+  $display("Time\t    R0 R1 R2 R3 G0 G1 G2 G3");
+  $monitor("%g\t    %b  %b  %b  %b  %b  %b  %b  %b", 
+    $time, req_0, req_1, req_2, req_3, gnt_0, gnt_1, gnt_2, gnt_3);
+  clock = 0;
+  reset = 0;
+  req_0 = 0;
+  req_1 = 0;
+  req_2 = 0;
+  req_3 = 0;
+  #10 reset = 1;
+  #10 reset = 0;
+  #10 req_0 = 1;
+  #20 req_0 = 0;
+  #10 req_1 = 1;
+  #20 req_1 = 0;
+  #10 req_2 = 1;
+  #20 req_2 = 0;
+  #10 req_3 = 1;
+  #20 req_3 = 0;
+  #10 $finish;
+end
+
+initial begin
+ #1;
+ forever
+   #2 clock = ~clock;
+end
+
+fsm_full U_fsm_full(
+clock , // Clock
+reset , // Active high reset
+req_0 , // Active high request from agent 0
+req_1 , // Active high request from agent 1
+req_2 , // Active high request from agent 2
+req_3 , // Active high request from agent 3
+gnt_0 , // Active high grant to agent 0
+gnt_1 , // Active high grant to agent 1
+gnt_2 , // Active high grant to agent 2
+gnt_3   // Active high grant to agent 3
+);
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_good_code.v b/tests/asicworld/code_verilog_tutorial_good_code.v
new file mode 100644 (file)
index 0000000..6ba7764
--- /dev/null
@@ -0,0 +1,18 @@
+      module addbit (
+      a,
+      b,
+      ci,
+      sum,
+      co);
+      input           a;
+      input           b;
+      input           ci;
+      output         sum;
+      output         co;
+      wire            a;
+      wire            b;
+      wire            ci;
+      wire            sum;
+      wire            co;
+
+      endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_if_else.v b/tests/asicworld/code_verilog_tutorial_if_else.v
new file mode 100644 (file)
index 0000000..19b91d3
--- /dev/null
@@ -0,0 +1,13 @@
+module if_else();
+
+reg dff;
+wire clk,din,reset;
+
+always @ (posedge clk)
+if (reset) begin
+  dff <= 0;
+end else  begin
+  dff <= din;
+end
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_multiply.v b/tests/asicworld/code_verilog_tutorial_multiply.v
new file mode 100644 (file)
index 0000000..1912e1e
--- /dev/null
@@ -0,0 +1,8 @@
+module muliply (a,product);
+               input [3:0] a;
+               output [4:0] product;
+               wire [4:0] product;
+                
+               assign product  = a << 1;
+                
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_mux_21.v b/tests/asicworld/code_verilog_tutorial_mux_21.v
new file mode 100644 (file)
index 0000000..a6a0d35
--- /dev/null
@@ -0,0 +1,9 @@
+module mux_21 (a,b,sel,y);
+               input a, b;
+               output y;
+               input sel;
+               wire y;
+                
+               assign y = (sel) ? b : a;
+                
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_n_out_primitive.v b/tests/asicworld/code_verilog_tutorial_n_out_primitive.v
new file mode 100644 (file)
index 0000000..814385a
--- /dev/null
@@ -0,0 +1,13 @@
+module n_out_primitive();
+
+wire out,out_0,out_1,out_2,out_3,out_a,out_b,out_c;
+wire in;
+
+// one output Buffer gate
+buf u_buf0 (out,in);
+// four output Buffer gate 
+buf u_buf1 (out_0, out_1, out_2, out_3, in);
+// three output Invertor gate 
+not u_not0 (out_a, out_b, out_c, in);
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_parallel_if.v b/tests/asicworld/code_verilog_tutorial_parallel_if.v
new file mode 100644 (file)
index 0000000..1dbe737
--- /dev/null
@@ -0,0 +1,21 @@
+module parallel_if();
+
+reg [3:0] counter;
+wire clk,reset,enable, up_en, down_en;
+
+always @ (posedge clk)
+// If reset is asserted
+if (reset == 1'b0) begin
+   counter <= 4'b0000; 
+end else begin
+  // If counter is enable and up count is mode
+  if (enable == 1'b1 && up_en == 1'b1) begin
+    counter <= counter + 1'b1;
+  end
+  // If counter is enable and down count is mode
+  if (enable == 1'b1 && down_en == 1'b1) begin
+    counter <= counter - 1'b1;
+  end 
+end  
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_parity.v b/tests/asicworld/code_verilog_tutorial_parity.v
new file mode 100644 (file)
index 0000000..764396c
--- /dev/null
@@ -0,0 +1,41 @@
+//-----------------------------------------------------
+// This is simple parity Program
+// Design Name : parity
+// File Name   : parity.v
+// Function    : This program shows how a verilog
+//               primitive/module port connection are done
+// Coder       : Deepak
+//-----------------------------------------------------
+module parity (
+a      , // First input
+b      , // Second input 
+c      , // Third Input
+d      , // Fourth Input
+y        // Parity  output
+);
+
+// Input Declaration
+input       a       ;
+input       b       ;
+input       c       ;
+input       d       ;
+// Ouput Declaration
+output      y      ;
+// port data types
+wire        a        ;
+wire        b        ;
+wire        c        ;
+wire        d        ;
+wire        y        ;
+// Internal variables
+wire        out_0 ;
+wire        out_1 ;
+
+// Code starts Here
+xor u0 (out_0,a,b);
+
+xor u1 (out_1,c,d);
+
+xor u2 (y,out_0,out_1);
+
+endmodule // End Of Module parity 
diff --git a/tests/asicworld/code_verilog_tutorial_simple_function.v b/tests/asicworld/code_verilog_tutorial_simple_function.v
new file mode 100644 (file)
index 0000000..5818a1d
--- /dev/null
@@ -0,0 +1,10 @@
+module simple_function();
+
+function  myfunction;
+input a, b, c, d;
+begin
+  myfunction = ((a+b) + (c-d));
+end
+endfunction
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_simple_if.v b/tests/asicworld/code_verilog_tutorial_simple_if.v
new file mode 100644 (file)
index 0000000..a68cc4a
--- /dev/null
@@ -0,0 +1,11 @@
+module simple_if();
+
+reg latch;
+wire enable,din;
+
+always @ (enable or din)
+if (enable) begin
+  latch <= din;
+end  
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_task_global.v b/tests/asicworld/code_verilog_tutorial_task_global.v
new file mode 100644 (file)
index 0000000..3ae8627
--- /dev/null
@@ -0,0 +1,12 @@
+module task_global();
+
+reg [7:0] temp_out;
+reg [7:0] temp_in;
+
+task convert;
+begin
+  temp_out = (9/5) *( temp_in + 32);
+end
+endtask
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_tri_buf.v b/tests/asicworld/code_verilog_tutorial_tri_buf.v
new file mode 100644 (file)
index 0000000..a55b29c
--- /dev/null
@@ -0,0 +1,9 @@
+module tri_buf (a,b,enable);
+ input a;
+ output b;
+ input enable;
+ wire b;
+assign b = (enable) ? a : 1'bz;
+                
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_v2k_reg.v b/tests/asicworld/code_verilog_tutorial_v2k_reg.v
new file mode 100644 (file)
index 0000000..537a9e8
--- /dev/null
@@ -0,0 +1,24 @@
+module v2k_reg();
+
+// v2k allows to init variables
+reg a = 0;
+// Here only last variable is set to 0, i.e d = 0
+// Rest b, c are set to x
+reg b, c, d = 0;
+// reg data type can be signed in v2k
+// We can assign with signed constants
+reg signed [7:0] data = 8'shF0;
+
+// Function can return signed values
+// Its ports can contain signed ports
+function signed [7:0] adder;
+  input a_in;
+  input b_in;
+  input c_in;
+  input signed [7:0] data_in;
+  begin
+    adder = a_in + b_in + c_in + data_in;
+  end
+endfunction
+
+endmodule
diff --git a/tests/asicworld/code_verilog_tutorial_which_clock.v b/tests/asicworld/code_verilog_tutorial_which_clock.v
new file mode 100644 (file)
index 0000000..418a2cf
--- /dev/null
@@ -0,0 +1,12 @@
+module which_clock (x,y,q,d);
+input x,y,d;
+output q;
+reg q;
+
+always @ (posedge x or posedge y)
+   if (x) 
+     q <= 1'b0;
+   else
+     q <= d;
+
+endmodule
diff --git a/tests/asicworld/run-test.sh b/tests/asicworld/run-test.sh
new file mode 100755 (executable)
index 0000000..bf27d15
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+make -C ../.. || exit 1
+exec bash ../tools/autotest.sh *.v
diff --git a/tests/hana/README b/tests/hana/README
new file mode 100644 (file)
index 0000000..3704940
--- /dev/null
@@ -0,0 +1,14 @@
+
+This test cases are copied from the hana project:
+https://sourceforge.net/projects/sim-sim/
+
+** Copy tests from hana: **
+while read fn; do cp -v $fn ALL_TESTS/${fn//\//_}; done < <(find test -name '*.v' ! -name '*_gold.v')
+
+** Eliminate test's we can't parse atm: **
+rm -f test_synthesizability*.v
+rm -f test_parse2synthtrans_latch_1_test.v
+rm -f test_parse2synthtrans_always_1_test.v
+rm -f test_parse2synthtrans_always_2_test.v
+for x in test_*.v; do ../../yosys -b "" $x || rm $x; done
+
diff --git a/tests/hana/hana_vlib.v b/tests/hana/hana_vlib.v
new file mode 100644 (file)
index 0000000..fc82f13
--- /dev/null
@@ -0,0 +1,1139 @@
+/* 
+Copyright (C) 2009-2010 Parvez Ahmad
+Written by Parvez Ahmad <parvez_ahmad@yahoo.co.uk>.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+module BUF (input in, output out);
+
+assign out = in;
+
+endmodule
+
+module TRIBUF(input in, enable, output out);
+
+assign out = enable ? in : 1'bz;
+
+endmodule
+
+module INV(input in, output out);
+
+assign out = ~in;
+
+endmodule
+
+module AND2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output out);
+
+assign out = &in;
+
+endmodule
+
+module AND3 #(parameter SIZE = 3) (input [SIZE-1:0] in, output out);
+
+assign out = &in;
+
+endmodule
+    
+module AND4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output out);
+
+assign out = &in;
+
+endmodule
+
+module OR2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output out);
+
+assign out = |in;
+
+endmodule
+
+module OR3 #(parameter SIZE = 3) (input [SIZE-1:0] in, output out);
+
+assign out = |in;
+
+endmodule
+    
+module OR4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output out);
+
+assign out = |in;
+
+endmodule
+
+
+module NAND2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output out);
+
+assign out = ~&in;
+
+endmodule
+
+module NAND3 #(parameter SIZE = 3) (input [SIZE-1:0] in, output out);
+
+assign out = ~&in;
+
+endmodule
+    
+module NAND4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output out);
+
+assign out = ~&in;
+
+endmodule
+
+module NOR2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output out);
+
+assign out = ~|in;
+
+endmodule
+
+module NOR3 #(parameter SIZE = 3) (input [SIZE-1:0] in, output out);
+
+assign out = ~|in;
+
+endmodule
+    
+module NOR4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output out);
+
+assign out = ~|in;
+
+endmodule
+
+
+module XOR2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output out);
+
+assign out = ^in;
+
+endmodule
+
+module XOR3 #(parameter SIZE = 3) (input [SIZE-1:0] in, output out);
+
+assign out = ^in;
+
+endmodule
+    
+module XOR4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output out);
+
+assign out = ^in;
+
+endmodule
+
+
+module XNOR2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output out);
+
+assign out = ~^in;
+
+endmodule
+
+module XNOR3 #(parameter SIZE = 3) (input [SIZE-1:0] in, output out);
+
+assign out = ~^in;
+
+endmodule
+    
+module XNOR4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output out);
+
+assign out = ~^in;
+
+endmodule
+
+module DEC1 (input in, enable, output reg [1:0] out);
+
+always @(in or enable)
+    if(!enable)
+           out = 2'b00;
+       else begin
+          case (in)
+              1'b0 : out = 2'b01;
+              1'b1 : out = 2'b10;
+           endcase
+       end
+endmodule      
+
+module DEC2 (input [1:0] in, input enable, output reg [3:0] out);
+
+always @(in or enable)
+    if(!enable)
+           out = 4'b0000;
+       else begin
+          case (in)
+              2'b00 : out = 4'b0001;
+              2'b01 : out = 4'b0010;
+              2'b10 : out = 4'b0100;
+              2'b11 : out = 4'b1000;
+           endcase
+       end
+endmodule      
+
+module DEC3 (input [2:0] in, input enable, output reg [7:0] out);
+
+always @(in or enable)
+    if(!enable)
+           out = 8'b00000000;
+       else begin
+          case (in)
+              3'b000 : out = 8'b00000001;
+              3'b001 : out = 8'b00000010;
+              3'b010 : out = 8'b00000100;
+              3'b011 : out = 8'b00001000;
+              3'b100 : out = 8'b00010000;
+              3'b101 : out = 8'b00100000;
+              3'b110 : out = 8'b01000000;
+              3'b111 : out = 8'b10000000;
+           endcase
+       end
+endmodule      
+
+module DEC4 (input [3:0] in, input enable, output reg [15:0] out);
+
+always @(in or enable)
+    if(!enable)
+           out = 16'b0000000000000000;
+       else begin
+          case (in)
+              4'b0000 : out = 16'b0000000000000001;
+              4'b0001 : out = 16'b0000000000000010;
+              4'b0010 : out = 16'b0000000000000100;
+              4'b0011 : out = 16'b0000000000001000;
+              4'b0100 : out = 16'b0000000000010000;
+              4'b0101 : out = 16'b0000000000100000;
+              4'b0110 : out = 16'b0000000001000000;
+              4'b0111 : out = 16'b0000000010000000;
+              4'b1000 : out = 16'b0000000100000000;
+              4'b1001 : out = 16'b0000001000000000;
+              4'b1010 : out = 16'b0000010000000000;
+              4'b1011 : out = 16'b0000100000000000;
+              4'b1100 : out = 16'b0001000000000000;
+              4'b1101 : out = 16'b0010000000000000;
+              4'b1110 : out = 16'b0100000000000000;
+              4'b1111 : out = 16'b1000000000000000;
+           endcase
+       end
+endmodule      
+module DEC5 (input [4:0] in, input enable, output reg [31:0] out);
+
+always @(in or enable)
+    if(!enable)
+           out = 32'b00000000000000000000000000000000;
+       else begin
+          case (in)
+              5'b00000 : out = 32'b00000000000000000000000000000001;
+              5'b00001 : out = 32'b00000000000000000000000000000010;
+              5'b00010 : out = 32'b00000000000000000000000000000100;
+              5'b00011 : out = 32'b00000000000000000000000000001000;
+              5'b00100 : out = 32'b00000000000000000000000000010000;
+              5'b00101 : out = 32'b00000000000000000000000000100000;
+              5'b00110 : out = 32'b00000000000000000000000001000000;
+              5'b00111 : out = 32'b00000000000000000000000010000000;
+              5'b01000 : out = 32'b00000000000000000000000100000000;
+              5'b01001 : out = 32'b00000000000000000000001000000000;
+              5'b01010 : out = 32'b00000000000000000000010000000000;
+              5'b01011 : out = 32'b00000000000000000000100000000000;
+              5'b01100 : out = 32'b00000000000000000001000000000000;
+              5'b01101 : out = 32'b00000000000000000010000000000000;
+              5'b01110 : out = 32'b00000000000000000100000000000000;
+              5'b01111 : out = 32'b00000000000000001000000000000000;
+              5'b10000 : out = 32'b00000000000000010000000000000000;
+              5'b10001 : out = 32'b00000000000000100000000000000000;
+              5'b10010 : out = 32'b00000000000001000000000000000000;
+              5'b10011 : out = 32'b00000000000010000000000000000000;
+              5'b10100 : out = 32'b00000000000100000000000000000000;
+              5'b10101 : out = 32'b00000000001000000000000000000000;
+              5'b10110 : out = 32'b00000000010000000000000000000000;
+              5'b10111 : out = 32'b00000000100000000000000000000000;
+              5'b11000 : out = 32'b00000001000000000000000000000000;
+              5'b11001 : out = 32'b00000010000000000000000000000000;
+              5'b11010 : out = 32'b00000100000000000000000000000000;
+              5'b11011 : out = 32'b00001000000000000000000000000000;
+              5'b11100 : out = 32'b00010000000000000000000000000000;
+              5'b11101 : out = 32'b00100000000000000000000000000000;
+              5'b11110 : out = 32'b01000000000000000000000000000000;
+              5'b11111 : out = 32'b10000000000000000000000000000000;
+           endcase
+       end
+endmodule      
+
+module DEC6 (input [5:0] in, input enable, output reg [63:0] out);
+
+always @(in or enable)
+    if(!enable)
+           out = 64'b0000000000000000000000000000000000000000000000000000000000000000;
+       else begin
+          case (in)
+              6'b000000 : out = 64'b0000000000000000000000000000000000000000000000000000000000000001;
+              6'b000001 : out = 64'b0000000000000000000000000000000000000000000000000000000000000010;
+              6'b000010 : out = 64'b0000000000000000000000000000000000000000000000000000000000000100;
+              6'b000011 : out = 64'b0000000000000000000000000000000000000000000000000000000000001000;
+              6'b000100 : out = 64'b0000000000000000000000000000000000000000000000000000000000010000;
+              6'b000101 : out = 64'b0000000000000000000000000000000000000000000000000000000000100000;
+              6'b000110 : out = 64'b0000000000000000000000000000000000000000000000000000000001000000;
+              6'b000111 : out = 64'b0000000000000000000000000000000000000000000000000000000010000000;
+              6'b001000 : out = 64'b0000000000000000000000000000000000000000000000000000000100000000;
+              6'b001001 : out = 64'b0000000000000000000000000000000000000000000000000000001000000000;
+              6'b001010 : out = 64'b0000000000000000000000000000000000000000000000000000010000000000;
+              6'b001011 : out = 64'b0000000000000000000000000000000000000000000000000000100000000000;
+              6'b001100 : out = 64'b0000000000000000000000000000000000000000000000000001000000000000;
+              6'b001101 : out = 64'b0000000000000000000000000000000000000000000000000010000000000000;
+              6'b001110 : out = 64'b0000000000000000000000000000000000000000000000000100000000000000;
+              6'b001111 : out = 64'b0000000000000000000000000000000000000000000000001000000000000000;
+              6'b010000 : out = 64'b0000000000000000000000000000000000000000000000010000000000000000;
+              6'b010001 : out = 64'b0000000000000000000000000000000000000000000000100000000000000000;
+              6'b010010 : out = 64'b0000000000000000000000000000000000000000000001000000000000000000;
+              6'b010011 : out = 64'b0000000000000000000000000000000000000000000010000000000000000000;
+              6'b010100 : out = 64'b0000000000000000000000000000000000000000000100000000000000000000;
+              6'b010101 : out = 64'b0000000000000000000000000000000000000000001000000000000000000000;
+              6'b010110 : out = 64'b0000000000000000000000000000000000000000010000000000000000000000;
+              6'b010111 : out = 64'b0000000000000000000000000000000000000000100000000000000000000000;
+              6'b011000 : out = 64'b0000000000000000000000000000000000000001000000000000000000000000;
+              6'b011001 : out = 64'b0000000000000000000000000000000000000010000000000000000000000000;
+              6'b011010 : out = 64'b0000000000000000000000000000000000000100000000000000000000000000;
+              6'b011011 : out = 64'b0000000000000000000000000000000000001000000000000000000000000000;
+              6'b011100 : out = 64'b0000000000000000000000000000000000010000000000000000000000000000;
+              6'b011101 : out = 64'b0000000000000000000000000000000000100000000000000000000000000000;
+              6'b011110 : out = 64'b0000000000000000000000000000000001000000000000000000000000000000;
+              6'b011111 : out = 64'b0000000000000000000000000000000010000000000000000000000000000000;
+
+              6'b100000 : out = 64'b0000000000000000000000000000000100000000000000000000000000000000;
+              6'b100001 : out = 64'b0000000000000000000000000000001000000000000000000000000000000000;
+              6'b100010 : out = 64'b0000000000000000000000000000010000000000000000000000000000000000;
+              6'b100011 : out = 64'b0000000000000000000000000000100000000000000000000000000000000000;
+              6'b100100 : out = 64'b0000000000000000000000000001000000000000000000000000000000000000;
+              6'b100101 : out = 64'b0000000000000000000000000010000000000000000000000000000000000000;
+              6'b100110 : out = 64'b0000000000000000000000000100000000000000000000000000000000000000;
+              6'b100111 : out = 64'b0000000000000000000000001000000000000000000000000000000000000000;
+              6'b101000 : out = 64'b0000000000000000000000010000000000000000000000000000000000000000;
+              6'b101001 : out = 64'b0000000000000000000000100000000000000000000000000000000000000000;
+              6'b101010 : out = 64'b0000000000000000000001000000000000000000000000000000000000000000;
+              6'b101011 : out = 64'b0000000000000000000010000000000000000000000000000000000000000000;
+              6'b101100 : out = 64'b0000000000000000000100000000000000000000000000000000000000000000;
+              6'b101101 : out = 64'b0000000000000000001000000000000000000000000000000000000000000000;
+              6'b101110 : out = 64'b0000000000000000010000000000000000000000000000000000000000000000;
+              6'b101111 : out = 64'b0000000000000000100000000000000000000000000000000000000000000000;
+              6'b110000 : out = 64'b0000000000000001000000000000000000000000000000000000000000000000;
+              6'b110001 : out = 64'b0000000000000010000000000000000000000000000000000000000000000000;
+              6'b110010 : out = 64'b0000000000000100000000000000000000000000000000000000000000000000;
+              6'b110011 : out = 64'b0000000000001000000000000000000000000000000000000000000000000000;
+              6'b110100 : out = 64'b0000000000010000000000000000000000000000000000000000000000000000;
+              6'b110101 : out = 64'b0000000000100000000000000000000000000000000000000000000000000000;
+              6'b110110 : out = 64'b0000000001000000000000000000000000000000000000000000000000000000;
+              6'b110111 : out = 64'b0000000010000000000000000000000000000000000000000000000000000000;
+              6'b111000 : out = 64'b0000000100000000000000000000000000000000000000000000000000000000;
+              6'b111001 : out = 64'b0000001000000000000000000000000000000000000000000000000000000000;
+              6'b111010 : out = 64'b0000010000000000000000000000000000000000000000000000000000000000;
+              6'b111011 : out = 64'b0000100000000000000000000000000000000000000000000000000000000000;
+              6'b111100 : out = 64'b0001000000000000000000000000000000000000000000000000000000000000;
+              6'b111101 : out = 64'b0010000000000000000000000000000000000000000000000000000000000000;
+              6'b111110 : out = 64'b0100000000000000000000000000000000000000000000000000000000000000;
+              6'b111111 : out = 64'b1000000000000000000000000000000000000000000000000000000000000000;
+           endcase
+       end
+endmodule      
+
+
+module MUX2(input [1:0] in, input select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+       endcase
+endmodule      
+
+
+module MUX4(input [3:0] in, input [1:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+       endcase
+endmodule      
+
+
+module MUX8(input [7:0] in, input [2:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+           4: out = in[4];
+           5: out = in[5];
+           6: out = in[6];
+           7: out = in[7];
+       endcase
+endmodule      
+
+module MUX16(input [15:0] in, input [3:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+           4: out = in[4];
+           5: out = in[5];
+           6: out = in[6];
+           7: out = in[7];
+           8: out = in[8];
+           9: out = in[9];
+           10: out = in[10];
+           11: out = in[11];
+           12: out = in[12];
+           13: out = in[13];
+           14: out = in[14];
+           15: out = in[15];
+       endcase
+endmodule      
+
+module MUX32(input [31:0] in, input [4:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+           4: out = in[4];
+           5: out = in[5];
+           6: out = in[6];
+           7: out = in[7];
+           8: out = in[8];
+           9: out = in[9];
+           10: out = in[10];
+           11: out = in[11];
+           12: out = in[12];
+           13: out = in[13];
+           14: out = in[14];
+           15: out = in[15];
+           16: out = in[16];
+           17: out = in[17];
+           18: out = in[18];
+           19: out = in[19];
+           20: out = in[20];
+           21: out = in[21];
+           22: out = in[22];
+           23: out = in[23];
+           24: out = in[24];
+           25: out = in[25];
+           26: out = in[26];
+           27: out = in[27];
+           28: out = in[28];
+           29: out = in[29];
+           30: out = in[30];
+           31: out = in[31];
+       endcase
+endmodule      
+
+module MUX64(input [63:0] in, input [5:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+           4: out = in[4];
+           5: out = in[5];
+           6: out = in[6];
+           7: out = in[7];
+           8: out = in[8];
+           9: out = in[9];
+           10: out = in[10];
+           11: out = in[11];
+           12: out = in[12];
+           13: out = in[13];
+           14: out = in[14];
+           15: out = in[15];
+           16: out = in[16];
+           17: out = in[17];
+           18: out = in[18];
+           19: out = in[19];
+           20: out = in[20];
+           21: out = in[21];
+           22: out = in[22];
+           23: out = in[23];
+           24: out = in[24];
+           25: out = in[25];
+           26: out = in[26];
+           27: out = in[27];
+           28: out = in[28];
+           29: out = in[29];
+           30: out = in[30];
+           31: out = in[31];
+           32: out = in[32];
+           33: out = in[33];
+           34: out = in[34];
+           35: out = in[35];
+           36: out = in[36];
+           37: out = in[37];
+           38: out = in[38];
+           39: out = in[39];
+           40: out = in[40];
+           41: out = in[41];
+           42: out = in[42];
+           43: out = in[43];
+           44: out = in[44];
+           45: out = in[45];
+           46: out = in[46];
+           47: out = in[47];
+           48: out = in[48];
+           49: out = in[49];
+           50: out = in[50];
+           51: out = in[51];
+           52: out = in[52];
+           53: out = in[53];
+           54: out = in[54];
+           55: out = in[55];
+           56: out = in[56];
+           57: out = in[57];
+           58: out = in[58];
+           59: out = in[59];
+           60: out = in[60];
+           61: out = in[61];
+           62: out = in[62];
+           63: out = in[63];
+       endcase
+endmodule      
+
+module ADD1(input in1, in2, cin, output out, cout);
+
+assign {cout, out} = in1 + in2 + cin;
+
+endmodule
+
+module ADD2 #(parameter SIZE = 2)(input [SIZE-1:0] in1, in2, 
+    input cin, output [SIZE-1:0] out, output cout);
+
+assign {cout, out} = in1 + in2 + cin;
+
+endmodule
+
+module ADD4 #(parameter SIZE = 4)(input [SIZE-1:0] in1, in2, 
+    input cin, output [SIZE-1:0] out, output cout);
+
+assign {cout, out} = in1 + in2 + cin;
+
+endmodule
+
+module ADD8 #(parameter SIZE = 8)(input [SIZE-1:0] in1, in2, 
+    input cin, output [SIZE-1:0] out, output cout);
+
+assign {cout, out} = in1 + in2 + cin;
+
+endmodule
+
+module ADD16 #(parameter SIZE = 16)(input [SIZE-1:0] in1, in2, 
+    input cin, output [SIZE-1:0] out, output cout);
+
+assign {cout, out} = in1 + in2 + cin;
+
+endmodule
+
+module ADD32 #(parameter SIZE = 32)(input [SIZE-1:0] in1, in2, 
+    input cin, output [SIZE-1:0] out, output cout);
+
+assign {cout, out} = in1 + in2 + cin;
+
+endmodule
+module ADD64 #(parameter SIZE = 64)(input [SIZE-1:0] in1, in2, 
+    input cin, output [SIZE-1:0] out, output cout);
+
+assign {cout, out} = in1 + in2 + cin;
+
+endmodule
+
+module SUB1(input in1, in2, cin, output out, cout);
+
+assign {cout, out} = in1 - in2 - cin;
+
+endmodule
+
+module SUB2 #(parameter SIZE = 2)(input [SIZE-1:0] in1, in2, 
+    input cin, output [SIZE-1:0] out, output cout);
+
+assign {cout, out} = in1 - in2 - cin;
+
+endmodule
+
+module SUB4 #(parameter SIZE = 4)(input [SIZE-1:0] in1, in2, 
+    input cin, output [SIZE-1:0] out, output cout);
+
+assign {cout, out} = in1 - in2 - cin;
+
+endmodule
+
+module SUB8 #(parameter SIZE = 8)(input [SIZE-1:0] in1, in2, 
+    input cin, output [SIZE-1:0] out, output cout);
+
+assign {cout, out} = in1 - in2 - cin;
+
+endmodule
+
+module SUB16 #(parameter SIZE = 16)(input [SIZE-1:0] in1, in2, 
+    input cin, output [SIZE-1:0] out, output cout);
+
+assign {cout, out} = in1 - in2 - cin;
+
+endmodule
+
+module SUB32 #(parameter SIZE = 32)(input [SIZE-1:0] in1, in2, 
+    input cin, output [SIZE-1:0] out, output cout);
+
+assign {cout, out} = in1 - in2 - cin;
+
+endmodule
+module SUB64 #(parameter SIZE = 64)(input [SIZE-1:0] in1, in2, 
+    input cin, output [SIZE-1:0] out, output cout);
+
+assign {cout, out} = in1 - in2 - cin;
+
+endmodule
+
+module MUL1 #(parameter SIZE = 1)(input in1, in2, output [2*SIZE-1:0] out);
+
+assign out = in1*in2;
+
+endmodule
+
+module MUL2 #(parameter SIZE = 2)(input [SIZE-1:0] in1, in2, output [2*SIZE-1:0] out);
+
+assign out = in1*in2;
+
+endmodule
+
+module MUL4 #(parameter SIZE = 4)(input [SIZE-1:0] in1, in2, output [2*SIZE-1:0] out);
+
+assign out = in1*in2;
+
+endmodule
+
+module MUL8 #(parameter SIZE = 8)(input [SIZE-1:0] in1, in2, output [2*SIZE-1:0] out);
+
+assign out = in1*in2;
+
+endmodule
+
+module MUL16 #(parameter SIZE = 16)(input [SIZE-1:0] in1, in2, output [2*SIZE-1:0] out);
+
+assign out = in1*in2;
+
+endmodule
+
+module MUL32 #(parameter SIZE = 32)(input [SIZE-1:0] in1, in2, output [2*SIZE-1:0] out);
+
+assign out = in1*in2;
+
+endmodule
+
+module MUL64 #(parameter SIZE = 64)(input [SIZE-1:0] in1, in2, output [2*SIZE-1:0] out);
+
+assign out = in1*in2;
+
+endmodule
+
+module DIV1 #(parameter SIZE = 1)(input in1, in2, output out, rem);
+
+assign out = in1/in2;
+assign rem = in1%in2;
+
+endmodule
+
+module DIV2 #(parameter SIZE = 2)(input [SIZE-1:0] in1, in2, 
+    output [SIZE-1:0] out, rem);
+
+assign out = in1/in2;
+assign rem = in1%in2;
+
+endmodule
+
+module DIV4 #(parameter SIZE = 4)(input [SIZE-1:0] in1, in2, 
+    output [SIZE-1:0] out, rem);
+
+assign out = in1/in2;
+assign rem = in1%in2;
+
+endmodule
+
+module DIV8 #(parameter SIZE = 8)(input [SIZE-1:0] in1, in2, 
+    output [SIZE-1:0] out, rem);
+
+assign out = in1/in2;
+assign rem = in1%in2;
+
+endmodule
+
+module DIV16 #(parameter SIZE = 16)(input [SIZE-1:0] in1, in2, 
+    output [SIZE-1:0] out, rem);
+
+assign out = in1/in2;
+assign rem = in1%in2;
+
+endmodule
+
+module DIV32 #(parameter SIZE = 32)(input [SIZE-1:0] in1, in2, 
+    output [SIZE-1:0] out, rem);
+
+assign out = in1/in2;
+assign rem = in1%in2;
+
+endmodule
+
+module DIV64 #(parameter SIZE = 64)(input [SIZE-1:0] in1, in2, 
+    output [SIZE-1:0] out, rem);
+
+assign out = in1/in2;
+assign rem = in1%in2;
+
+endmodule
+
+module FF (input d, clk, output reg q);
+always @( posedge clk)
+    q <= d;
+endmodule
+
+
+module RFF(input d, clk, reset, output reg q);
+always @(posedge clk or posedge reset)
+    if(reset)
+           q <= 0;
+       else
+           q <= d;
+endmodule              
+
+module SFF(input d, clk, set, output reg q);
+always @(posedge clk or posedge set)
+    if(set)
+           q <= 1;
+       else
+           q <= d;
+endmodule              
+
+module RSFF(input d, clk, set, reset, output reg q);
+always @(posedge clk or posedge reset or posedge set)
+    if(reset)
+           q <= 0;
+       else if(set)
+           q <= 1;
+       else
+           q <= d;
+endmodule
+
+module SRFF(input d, clk, set, reset, output reg q);
+always @(posedge clk or posedge set or posedge reset)
+    if(set)
+           q <= 1;
+       else if(reset)
+           q <= 0;
+       else
+           q <= d;
+endmodule
+
+module LATCH(input d, enable, output reg q);
+always @( d or enable)
+    if(enable)
+           q <= d;
+endmodule              
+
+module RLATCH(input d, reset, enable, output reg q);
+always @( d or enable or reset)
+    if(enable)
+           if(reset)
+                   q <= 0;
+               else    
+               q <= d;
+endmodule              
+
+module LSHIFT1 #(parameter SIZE = 1)(input in, shift, val, output reg out);
+
+always @ (in, shift, val) begin
+    if(shift)
+           out = val;
+       else 
+           out = in;
+end
+
+endmodule
+
+
+module LSHIFT2 #(parameter SIZE = 2)(input [SIZE-1:0] in, 
+    input [SIZE-1:0] shift, input val,
+    output reg [SIZE-1:0] out);
+
+always @(in or shift or val) begin
+    out = in << shift;
+       if(val)
+           out = out | ({SIZE-1 {1'b1} } >> (SIZE-1-shift));
+end    
+endmodule
+
+module LSHIFT4 #(parameter SIZE = 4)(input [SIZE-1:0] in, 
+    input [2:0] shift, input val, output reg [SIZE-1:0] out);
+
+always @(in or shift or val) begin
+    out = in << shift;
+       if(val)
+           out = out | ({SIZE-1 {1'b1} } >> (SIZE-1-shift));
+end    
+endmodule
+
+
+module LSHIFT8 #(parameter SIZE = 8)(input [SIZE-1:0] in, 
+    input [3:0] shift, input val, output reg [SIZE-1:0] out);
+
+always @(in or shift or val) begin
+    out = in << shift;
+       if(val)
+           out = out | ({SIZE-1 {1'b1} } >> (SIZE-1-shift));
+end    
+endmodule
+
+module LSHIFT16 #(parameter SIZE = 16)(input [SIZE-1:0] in, 
+    input [4:0] shift, input val, output reg [SIZE-1:0] out);
+
+always @(in or shift or val) begin
+    out = in << shift;
+       if(val)
+           out = out | ({SIZE-1 {1'b1} } >> (SIZE-1-shift));
+end    
+endmodule
+
+module LSHIFT32 #(parameter SIZE = 32)(input [SIZE-1:0] in, 
+    input [5:0] shift, input val, output reg [SIZE-1:0] out);
+
+always @(in or shift or val) begin
+    out = in << shift;
+       if(val)
+           out = out | ({SIZE-1 {1'b1} } >> (SIZE-1-shift));
+end    
+endmodule
+
+module LSHIFT64 #(parameter SIZE = 64)(input [SIZE-1:0] in, 
+    input [6:0] shift, input val, output reg [SIZE-1:0] out);
+
+always @(in or shift or val) begin
+    out = in << shift;
+       if(val)
+           out = out | ({SIZE-1 {1'b1} } >> (SIZE-1-shift));
+end    
+endmodule
+
+module RSHIFT1 #(parameter SIZE = 1)(input in, shift, val, output reg out);
+
+always @ (in, shift, val) begin
+    if(shift)
+           out = val;
+       else
+           out = in;
+end
+
+endmodule
+
+module RSHIFT2 #(parameter SIZE = 2)(input [SIZE-1:0] in, 
+    input [SIZE-1:0] shift, input val,
+    output reg [SIZE-1:0] out);
+
+always @(in or shift or val) begin
+    out = in >> shift;
+       if(val)
+           out = out | ({SIZE-1 {1'b1} } << (SIZE-1-shift));
+end    
+
+endmodule
+
+
+module RSHIFT4 #(parameter SIZE = 4)(input [SIZE-1:0] in, 
+    input [2:0] shift, input val,
+    output reg [SIZE-1:0] out);
+
+always @(in or shift or val) begin
+    out = in >> shift;
+       if(val)
+           out = out | ({SIZE-1 {1'b1} } << (SIZE-1-shift));
+end    
+endmodule
+
+module RSHIFT8 #(parameter SIZE = 8)(input [SIZE-1:0] in, 
+    input [3:0] shift, input val,
+    output reg [SIZE-1:0] out);
+
+always @(in or shift or val) begin
+    out = in >> shift;
+       if(val)
+           out = out | ({SIZE-1 {1'b1} } << (SIZE-1-shift));
+end    
+
+endmodule
+
+module RSHIFT16 #(parameter SIZE = 16)(input [SIZE-1:0] in, 
+    input [4:0] shift, input val,
+    output reg [SIZE-1:0] out);
+
+always @(in or shift or val) begin
+    out = in >> shift;
+       if(val)
+           out = out | ({SIZE-1 {1'b1} } << (SIZE-1-shift));
+end    
+endmodule
+
+
+module RSHIFT32 #(parameter SIZE = 32)(input [SIZE-1:0] in, 
+    input [5:0] shift, input val,
+    output reg [SIZE-1:0] out);
+
+always @(in or shift or val) begin
+    out = in >> shift;
+       if(val)
+           out = out | ({SIZE-1 {1'b1} } << (SIZE-1-shift));
+end    
+endmodule
+
+module RSHIFT64 #(parameter SIZE = 64)(input [SIZE-1:0] in, 
+    input [6:0] shift, input val,
+    output reg [SIZE-1:0] out);
+
+always @(in or shift or val) begin
+    out = in >> shift;
+       if(val)
+           out = out | ({SIZE-1 {1'b1} } << (SIZE-1-shift));
+end    
+endmodule
+
+module CMP1 #(parameter SIZE = 1) (input in1, in2, 
+    output reg equal, unequal, greater, lesser);
+
+always @ (in1 or in2) begin
+    if(in1 == in2) begin
+           equal = 1;
+               unequal = 0;
+               greater = 0;
+               lesser = 0;
+       end     
+       else begin
+           equal = 0;
+               unequal = 1;
+
+           if(in1 < in2) begin
+                   greater = 0;
+                   lesser = 1;
+           end 
+           else begin
+                   greater = 1;
+                   lesser = 0;
+           end 
+       end     
+end
+endmodule
+
+
+module CMP2 #(parameter SIZE = 2) (input [SIZE-1:0] in1, in2, 
+    output reg equal, unequal, greater, lesser);
+
+always @ (in1 or in2) begin
+    if(in1 == in2) begin
+           equal = 1;
+               unequal = 0;
+               greater = 0;
+               lesser = 0;
+       end     
+       else begin
+           equal = 0;
+               unequal = 1;
+
+           if(in1 < in2) begin
+                   greater = 0;
+                   lesser = 1;
+           end 
+           else begin
+                   greater = 1;
+                   lesser = 0;
+           end 
+       end     
+end
+endmodule
+
+module CMP4 #(parameter SIZE = 4) (input [SIZE-1:0] in1, in2, 
+    output reg equal, unequal, greater, lesser);
+
+always @ (in1 or in2) begin
+    if(in1 == in2) begin
+           equal = 1;
+               unequal = 0;
+               greater = 0;
+               lesser = 0;
+       end     
+       else begin
+           equal = 0;
+               unequal = 1;
+
+           if(in1 < in2) begin
+                   greater = 0;
+                   lesser = 1;
+           end 
+           else begin
+                   greater = 1;
+                   lesser = 0;
+           end 
+       end     
+end
+endmodule
+
+module CMP8 #(parameter SIZE = 8) (input [SIZE-1:0] in1, in2, 
+    output reg equal, unequal, greater, lesser);
+
+always @ (in1 or in2) begin
+    if(in1 == in2) begin
+           equal = 1;
+               unequal = 0;
+               greater = 0;
+               lesser = 0;
+       end     
+       else begin
+           equal = 0;
+               unequal = 1;
+
+           if(in1 < in2) begin
+                   greater = 0;
+                   lesser = 1;
+           end 
+           else begin
+                   greater = 1;
+                   lesser = 0;
+           end 
+       end     
+end
+endmodule
+
+module CMP16 #(parameter SIZE = 16) (input [SIZE-1:0] in1, in2, 
+    output reg equal, unequal, greater, lesser);
+
+always @ (in1 or in2) begin
+    if(in1 == in2) begin
+           equal = 1;
+               unequal = 0;
+               greater = 0;
+               lesser = 0;
+       end     
+       else begin
+           equal = 0;
+               unequal = 1;
+
+           if(in1 < in2) begin
+                   greater = 0;
+                   lesser = 1;
+           end 
+           else begin
+                   greater = 1;
+                   lesser = 0;
+           end 
+       end     
+end
+endmodule
+
+module CMP32 #(parameter SIZE = 32) (input [SIZE-1:0] in1, in2, 
+    output reg equal, unequal, greater, lesser);
+
+always @ (in1 or in2) begin
+    if(in1 == in2) begin
+           equal = 1;
+               unequal = 0;
+               greater = 0;
+               lesser = 0;
+       end     
+       else begin
+           equal = 0;
+               unequal = 1;
+
+           if(in1 < in2) begin
+                   greater = 0;
+                   lesser = 1;
+           end 
+           else begin
+                   greater = 1;
+                   lesser = 0;
+           end 
+       end     
+end
+endmodule
+
+module CMP64 #(parameter SIZE = 64) (input [SIZE-1:0] in1, in2, 
+    output reg equal, unequal, greater, lesser);
+
+always @ (in1 or in2) begin
+    if(in1 == in2) begin
+           equal = 1;
+               unequal = 0;
+               greater = 0;
+               lesser = 0;
+       end     
+       else begin
+           equal = 0;
+               unequal = 1;
+
+           if(in1 < in2) begin
+                   greater = 0;
+                   lesser = 1;
+           end 
+           else begin
+                   greater = 1;
+                   lesser = 0;
+           end 
+       end     
+end
+endmodule
+
+module VCC (output supply1 out);
+endmodule
+
+module GND (output supply0 out);
+endmodule
+
+
+module INC1 #(parameter SIZE = 1) (input in, output [SIZE:0] out);
+
+assign out = in + 1;
+
+endmodule
+
+module INC2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output [SIZE:0] out);
+
+assign out = in + 1;
+
+endmodule
+
+module INC4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output [SIZE:0] out);
+assign out = in + 1;
+
+endmodule
+
+module INC8 #(parameter SIZE = 8) (input [SIZE-1:0] in, output [SIZE:0] out);
+assign out = in + 1;
+
+endmodule
+
+module INC16 #(parameter SIZE = 16) (input [SIZE-1:0] in, output [SIZE:0] out);
+assign out = in + 1;
+
+endmodule
+
+module INC32 #(parameter SIZE = 32) (input [SIZE-1:0] in, output [SIZE:0] out);
+assign out = in + 1;
+
+endmodule
+module INC64 #(parameter SIZE = 64) (input [SIZE-1:0] in, output [SIZE:0] out);
+assign out = in + 1;
+
+endmodule
+
diff --git a/tests/hana/run-test.sh b/tests/hana/run-test.sh
new file mode 100755 (executable)
index 0000000..b8e7231
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+make -C ../.. || exit 1
+exec bash ../tools/autotest.sh -l hana_vlib.v test_*.v
diff --git a/tests/hana/test_intermout_always_comb_1_test.v b/tests/hana/test_intermout_always_comb_1_test.v
new file mode 100644 (file)
index 0000000..2d5abc4
--- /dev/null
@@ -0,0 +1,13 @@
+module test(a, b, c, d, z);
+input a, b, c, d;
+output z;
+reg z, temp1, temp2;
+
+always @(a or b or c or d)
+begin
+    temp1 = a ^ b;
+       temp2 = c ^ d;
+       z = temp1 ^ temp2;
+end    
+
+endmodule
diff --git a/tests/hana/test_intermout_always_comb_3_test.v b/tests/hana/test_intermout_always_comb_3_test.v
new file mode 100644 (file)
index 0000000..234407e
--- /dev/null
@@ -0,0 +1,10 @@
+module test (in1, in2, out);
+input  in1, in2;
+output  reg out;
+
+always @ ( in1 or in2)
+       if(in1 > in2)
+               out = in1;
+       else
+               out = in2;
+endmodule              
diff --git a/tests/hana/test_intermout_always_comb_4_test.v b/tests/hana/test_intermout_always_comb_4_test.v
new file mode 100644 (file)
index 0000000..b0a94f2
--- /dev/null
@@ -0,0 +1,9 @@
+module test(a, b, c);
+input b, c;
+output reg a;
+
+always @(b or c) begin
+a = b;
+a = c;
+end
+endmodule
diff --git a/tests/hana/test_intermout_always_comb_5_test.v b/tests/hana/test_intermout_always_comb_5_test.v
new file mode 100644 (file)
index 0000000..5152781
--- /dev/null
@@ -0,0 +1,11 @@
+module test(ctrl, in1,  in2, out);
+input ctrl;
+input  in1, in2;
+output  reg out;
+
+always @ (ctrl or in1 or in2)
+       if(ctrl)
+               out = in1 & in2;
+       else 
+               out = in1 | in2;
+endmodule              
diff --git a/tests/hana/test_intermout_always_ff_3_test.v b/tests/hana/test_intermout_always_ff_3_test.v
new file mode 100644 (file)
index 0000000..ed8630c
--- /dev/null
@@ -0,0 +1,15 @@
+module NonBlockingEx(clk, merge, er, xmit, fddi, claim);
+input clk, merge, er, xmit, fddi;
+output reg claim;
+reg fcr;
+
+always @(posedge clk)
+begin
+    fcr = er | xmit;
+
+       if(merge)
+           claim = fcr & fddi;
+       else
+           claim = fddi;
+end
+endmodule
diff --git a/tests/hana/test_intermout_always_ff_4_test.v b/tests/hana/test_intermout_always_ff_4_test.v
new file mode 100644 (file)
index 0000000..cac420a
--- /dev/null
@@ -0,0 +1,11 @@
+module FlipFlop(clk, cs, ns);
+input clk;
+input [31:0] cs;
+output [31:0] ns;
+integer is;
+
+always @(posedge clk)
+    is <= cs;
+
+assign ns = is;
+endmodule      
diff --git a/tests/hana/test_intermout_always_ff_5_test.v b/tests/hana/test_intermout_always_ff_5_test.v
new file mode 100644 (file)
index 0000000..669b2a5
--- /dev/null
@@ -0,0 +1,13 @@
+module FlipFlop(clock, cs, ns);
+input clock;
+input [3:0] cs;
+output reg [3:0] ns;
+reg [3:0] temp;
+
+always @(posedge clock)
+begin
+    temp = cs;
+       ns = temp;
+end    
+
+endmodule      
diff --git a/tests/hana/test_intermout_always_ff_6_test.v b/tests/hana/test_intermout_always_ff_6_test.v
new file mode 100644 (file)
index 0000000..ad0a0df
--- /dev/null
@@ -0,0 +1,7 @@
+module inc(clock, counter);
+
+input clock;
+output reg [3:0] counter;
+always @(posedge clock)
+       counter <= counter + 1;
+endmodule      
diff --git a/tests/hana/test_intermout_always_ff_8_test.v b/tests/hana/test_intermout_always_ff_8_test.v
new file mode 100644 (file)
index 0000000..0f29ea0
--- /dev/null
@@ -0,0 +1,11 @@
+module NegEdgeClock(q, d, clk, reset);
+input d, clk, reset;
+output reg q;
+
+always @(negedge clk or negedge reset)
+    if(!reset)
+           q <= 1'b0;
+       else    
+        q <= d;
+
+endmodule
diff --git a/tests/hana/test_intermout_always_ff_9_test.v b/tests/hana/test_intermout_always_ff_9_test.v
new file mode 100644 (file)
index 0000000..f1f13bb
--- /dev/null
@@ -0,0 +1,14 @@
+module MyCounter (clock, preset, updown, presetdata, counter);
+input clock, preset, updown;
+input [1: 0] presetdata;
+output reg [1:0] counter;
+
+always @(posedge clock)
+    if(preset)
+           counter <= presetdata;
+       else
+           if(updown)
+                   counter <= counter + 1;
+               else
+                   counter <= counter - 1;
+endmodule                      
diff --git a/tests/hana/test_intermout_always_latch_1_test.v b/tests/hana/test_intermout_always_latch_1_test.v
new file mode 100644 (file)
index 0000000..a83be20
--- /dev/null
@@ -0,0 +1,9 @@
+module test(en, in, out);
+input en;
+input [1:0] in;
+output reg [2:0] out;
+
+always @ (en or in)
+       if(en)
+               out = in + 1;
+endmodule              
diff --git a/tests/hana/test_intermout_bufrm_1_test.v b/tests/hana/test_intermout_bufrm_1_test.v
new file mode 100644 (file)
index 0000000..8e3d422
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input in, output out);
+//no buffer removal
+assign out = in;
+endmodule
diff --git a/tests/hana/test_intermout_bufrm_2_test.v b/tests/hana/test_intermout_bufrm_2_test.v
new file mode 100644 (file)
index 0000000..853f1dc
--- /dev/null
@@ -0,0 +1,7 @@
+module test(input in, output out);
+//intermediate buffers should be removed
+wire w1, w2;
+assign w1 = in;
+assign w2 = w1;
+assign out = w2;
+endmodule
diff --git a/tests/hana/test_intermout_bufrm_6_test.v b/tests/hana/test_intermout_bufrm_6_test.v
new file mode 100644 (file)
index 0000000..d4f3878
--- /dev/null
@@ -0,0 +1,22 @@
+module test(in, out);
+input in;
+output out;
+
+wire w1, w2, w3, w4;
+assign w1 = in;
+assign w2 = w1;
+assign w4 = w3;
+assign out = w4;
+mybuf _mybuf(w2, w3);
+endmodule
+
+module mybuf(in, out);
+input in;
+output out;
+wire w1, w2, w3, w4;
+
+assign w1 = in;
+assign w2 = w1;
+assign out = w2;
+endmodule
+
diff --git a/tests/hana/test_intermout_bufrm_7_test.v b/tests/hana/test_intermout_bufrm_7_test.v
new file mode 100644 (file)
index 0000000..7b65130
--- /dev/null
@@ -0,0 +1,33 @@
+module test(in1, in2, out);
+input in1, in2;
+output out;
+// Y with cluster of mybuf instances at the junction
+
+wire w1, w2, w3, w4, w5, w6, w7, w8, w9, w10;
+assign w1 = in1;
+assign w2 = w1;
+assign w5 = in2;
+assign w6 = w5;
+assign w10 = w9;
+assign out = w10;
+
+mybuf _mybuf0(w2, w3);
+mybuf _mybuf1(w3, w4);
+
+mybuf _mybuf2(w6, w7);
+mybuf _mybuf3(w7, w4);
+
+mybuf _mybuf4(w4, w8);
+mybuf _mybuf5(w8, w9);
+endmodule
+
+module mybuf(in, out);
+input in;
+output out;
+wire w1, w2, w3, w4;
+
+assign w1 = in;
+assign w2 = w1;
+assign out = w2;
+endmodule
+
diff --git a/tests/hana/test_intermout_exprs_add_test.v b/tests/hana/test_intermout_exprs_add_test.v
new file mode 100644 (file)
index 0000000..ec70f34
--- /dev/null
@@ -0,0 +1,10 @@
+module test(out, in1, in2, vin1, vin2, vout1);
+output out;
+input in1, in2;
+input [1:0] vin1;
+input [2:0] vin2;
+output [3:0] vout1;
+
+assign out = in1 + in2;
+assign vout1 = vin1 + vin2;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_binlogic_test.v b/tests/hana/test_intermout_exprs_binlogic_test.v
new file mode 100644 (file)
index 0000000..eec8c4b
--- /dev/null
@@ -0,0 +1,13 @@
+module test(in1, in2, vin1, vin2, out, vout, vin3, vin4, vout1 );
+input in1, in2;
+input [1:0] vin1;
+input [3:0] vin2;
+input [1:0] vin3;
+input [3:0] vin4;
+output vout, vout1;
+output out;
+
+assign out = in1 && in2;
+assign vout = vin1 && vin2;
+assign vout1 = vin3 || vin4;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_bitwiseneg_test.v b/tests/hana/test_intermout_exprs_bitwiseneg_test.v
new file mode 100644 (file)
index 0000000..5b62bef
--- /dev/null
@@ -0,0 +1,5 @@
+module test(output out, input in, output [1:0] vout, input [1:0] vin);
+
+assign out = ~in;
+assign vout = ~vin;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_buffer_test.v b/tests/hana/test_intermout_exprs_buffer_test.v
new file mode 100644 (file)
index 0000000..2b4cbc3
--- /dev/null
@@ -0,0 +1,9 @@
+module buffer(in, out, vin, vout);
+input  in;
+output out;
+input [1:0] vin;
+output [1:0] vout;
+
+assign out = in;
+assign vout = vin;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_condexpr_mux_test.v b/tests/hana/test_intermout_exprs_condexpr_mux_test.v
new file mode 100644 (file)
index 0000000..11006e8
--- /dev/null
@@ -0,0 +1,11 @@
+module test(in1, in2, out,  vin1, vin2, vin3, vin4, vout1, vout2, en1, ven1, ven2);
+input in1, in2, en1, ven1;
+input [1:0] ven2;
+output out;
+input [1:0] vin1,  vin2, vin3, vin4;
+output [1:0] vout1, vout2;
+
+assign out = en1 ? in1 : in2;
+assign vout1 = ven1 ? vin1 : vin2;
+assign vout2 = ven2 ? vin3 : vin4;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_condexpr_tribuf_test.v b/tests/hana/test_intermout_exprs_condexpr_tribuf_test.v
new file mode 100644 (file)
index 0000000..5b778fe
--- /dev/null
@@ -0,0 +1,9 @@
+module test(in, out, en, vin1, vout1, en1);
+input in, en, en1;
+output out;
+input [1:0] vin1;
+output [1:0] vout1;
+
+assign out = en ? in : 1'bz;
+assign vout1 = en1 ? vin1 : 2'bzz;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_const_test.v b/tests/hana/test_intermout_exprs_const_test.v
new file mode 100644 (file)
index 0000000..484d810
--- /dev/null
@@ -0,0 +1,7 @@
+module test (out, vout);
+output out;
+output [7:0] vout;
+
+assign out = 1'b1;
+assign vout = 9;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_constshift_test.v b/tests/hana/test_intermout_exprs_constshift_test.v
new file mode 100644 (file)
index 0000000..eb21315
--- /dev/null
@@ -0,0 +1,12 @@
+module test(in, out, vin, vout, vin1, vout1, vin2, vout2);
+
+input in;
+input [3:0] vin, vin1, vin2;
+output [3:0] vout, vout1, vout2;
+output out;
+
+assign out = in << 1;
+assign vout = vin << 2;
+assign vout1 = vin1 >> 2;
+assign vout2 = vin2 >>> 2;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_div_test.v b/tests/hana/test_intermout_exprs_div_test.v
new file mode 100644 (file)
index 0000000..21765fc
--- /dev/null
@@ -0,0 +1,10 @@
+module test(out, in1, in2, vin1, vin2, vout1);
+output out;
+input in1, in2;
+input [1:0] vin1;
+input [2:0] vin2;
+output [3:0] vout1;
+
+assign out = in1 / in2;
+assign vout1 = vin1 / vin2;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_logicneg_test.v b/tests/hana/test_intermout_exprs_logicneg_test.v
new file mode 100644 (file)
index 0000000..b45b32b
--- /dev/null
@@ -0,0 +1,7 @@
+module test(out, vout, in, vin);
+output out, vout;
+input in;
+input [3:0] vin;
+assign out = !in;
+assign vout = !vin;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_mod_test.v b/tests/hana/test_intermout_exprs_mod_test.v
new file mode 100644 (file)
index 0000000..cea6b02
--- /dev/null
@@ -0,0 +1,10 @@
+module test(out, in1, in2, vin1, vin2, vout1);
+output out;
+input in1, in2;
+input [1:0] vin1;
+input [2:0] vin2;
+output [3:0] vout1;
+
+assign out = in1 % in2;
+assign vout1 = vin1 % vin2;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_mul_test.v b/tests/hana/test_intermout_exprs_mul_test.v
new file mode 100644 (file)
index 0000000..f9973da
--- /dev/null
@@ -0,0 +1,10 @@
+module test(out, in1, in2, vin1, vin2, vout1);
+output out;
+input in1, in2;
+input [1:0] vin1;
+input [2:0] vin2;
+output [3:0] vout1;
+
+assign out = in1 * in2;
+assign vout1 = vin1 * vin2;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_redand_test.v b/tests/hana/test_intermout_exprs_redand_test.v
new file mode 100644 (file)
index 0000000..35fdf73
--- /dev/null
@@ -0,0 +1,5 @@
+module test(output out, input [1:0] vin, output out1, input [3:0] vin1);
+
+assign out = &vin;
+assign out1 = &vin1;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_redop_test.v b/tests/hana/test_intermout_exprs_redop_test.v
new file mode 100644 (file)
index 0000000..93fdb2e
--- /dev/null
@@ -0,0 +1,16 @@
+module Reduction (A1, A2, A3, A4, A5, A6, Y1, Y2, Y3, Y4, Y5, Y6);
+input [1:0] A1; 
+input [1:0] A2; 
+input [1:0] A3; 
+input [1:0] A4; 
+input [1:0] A5; 
+input [1:0] A6; 
+output Y1, Y2, Y3, Y4, Y5, Y6; 
+//reg Y1, Y2, Y3, Y4, Y5, Y6; 
+assign Y1=&A1; //reduction AND 
+assign Y2=|A2; //reduction OR 
+assign Y3=~&A3; //reduction NAND 
+assign Y4=~|A4; //reduction NOR 
+assign Y5=^A5; //reduction XOR 
+assign Y6=~^A6; //reduction XNOR 
+endmodule
diff --git a/tests/hana/test_intermout_exprs_sub_test.v b/tests/hana/test_intermout_exprs_sub_test.v
new file mode 100644 (file)
index 0000000..06e3a81
--- /dev/null
@@ -0,0 +1,10 @@
+module test(out, in1, in2, vin1, vin2, vout1);
+output out;
+input in1, in2;
+input [1:0] vin1;
+input [2:0] vin2;
+output [3:0] vout1;
+
+assign out = in1 - in2;
+assign vout1 = vin1 - vin2;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_unaryminus_test.v b/tests/hana/test_intermout_exprs_unaryminus_test.v
new file mode 100644 (file)
index 0000000..ee3f229
--- /dev/null
@@ -0,0 +1,5 @@
+module test(output out, input in, output [31:0] vout, input [31:0] vin);
+
+assign out = -in;
+assign vout = -vin;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_unaryplus_test.v b/tests/hana/test_intermout_exprs_unaryplus_test.v
new file mode 100644 (file)
index 0000000..07be5b2
--- /dev/null
@@ -0,0 +1,4 @@
+module test(output out, input in);
+
+assign out = +in;
+endmodule
diff --git a/tests/hana/test_intermout_exprs_varshift_test.v b/tests/hana/test_intermout_exprs_varshift_test.v
new file mode 100644 (file)
index 0000000..2ca35c0
--- /dev/null
@@ -0,0 +1,10 @@
+module test(vin0, vout0);
+input [2:0] vin0;
+output reg [7:0] vout0;
+
+wire [7:0] myreg0, myreg1, myreg2;
+integer i;
+assign myreg0 = vout0 << vin0;
+
+assign myreg1 = myreg2 >> i;
+endmodule
diff --git a/tests/hana/test_parse2synthtrans_behavopt_1_test.v b/tests/hana/test_parse2synthtrans_behavopt_1_test.v
new file mode 100644 (file)
index 0000000..c825739
--- /dev/null
@@ -0,0 +1,22 @@
+module test(in, out, clk, reset);
+input in, reset;
+output reg out;
+input clk;
+reg signed [3:0] a;
+reg signed [3:0] b;
+reg signed [3:0] c;
+reg [5:0] d;
+reg [5:0] e;
+
+always @(clk or reset) begin
+    a = -4;
+    b = 2;
+    c = a + b;
+    d = a + b + c;
+    d = d*d;
+    if(b)
+        e = d*d;
+    else 
+        e = d + d;
+end
+endmodule
diff --git a/tests/hana/test_parse2synthtrans_case_1_test.v b/tests/hana/test_parse2synthtrans_case_1_test.v
new file mode 100644 (file)
index 0000000..348c566
--- /dev/null
@@ -0,0 +1,26 @@
+module demultiplexer1_to_4 (out0, out1, out2, out3, in, s1, s0);
+output out0, out1, out2, out3;
+reg out0, out1, out2, out3;
+input in;
+input s1, s0;
+reg [3:0] encoding;
+reg [1:0] state;
+   always @(encoding) begin
+        case (encoding)
+        4'bxx11: state = 1;
+        4'bx0xx: state = 3;
+        4'b11xx: state = 4;
+        4'bx1xx: state = 2;
+        4'bxx1x: state = 1;
+        4'bxxx1: state = 0;
+        default: state = 0;
+        endcase
+   end
+   
+   always @(encoding) begin
+        case (encoding)
+        4'b0000: state = 1;
+        default: state = 0;
+        endcase
+   end
+endmodule
diff --git a/tests/hana/test_parse2synthtrans_contassign_1_test.v b/tests/hana/test_parse2synthtrans_contassign_1_test.v
new file mode 100644 (file)
index 0000000..78bf007
--- /dev/null
@@ -0,0 +1,7 @@
+module test(in, out);
+
+input wire in;
+output  out;
+assign out = (in+in);
+assign out = 74;
+endmodule
diff --git a/tests/hana/test_parse2synthtrans_module_basic0_test.v b/tests/hana/test_parse2synthtrans_module_basic0_test.v
new file mode 100644 (file)
index 0000000..67a272d
--- /dev/null
@@ -0,0 +1,2 @@
+module test;
+endmodule
diff --git a/tests/hana/test_parse2synthtrans_operators_1_test.v b/tests/hana/test_parse2synthtrans_operators_1_test.v
new file mode 100644 (file)
index 0000000..93b5691
--- /dev/null
@@ -0,0 +1,11 @@
+module test(in, out);
+input in;
+output out;
+parameter p1 = 10;
+parameter p2 = 5;
+
+assign out = +p1;
+assign out = -p2;
+assign out = p1 + p2;
+assign out = p1 - p2;
+endmodule
diff --git a/tests/hana/test_parse2synthtrans_param_1_test.v b/tests/hana/test_parse2synthtrans_param_1_test.v
new file mode 100644 (file)
index 0000000..146eedf
--- /dev/null
@@ -0,0 +1,7 @@
+module test(in, out);
+input in;
+output out;
+parameter p = 10;
+
+assign out = p;
+endmodule
diff --git a/tests/hana/test_parse2synthtrans_port_scalar_1_test.v b/tests/hana/test_parse2synthtrans_port_scalar_1_test.v
new file mode 100644 (file)
index 0000000..8cdf495
--- /dev/null
@@ -0,0 +1,6 @@
+module test(in, out, io);
+inout io;
+output out;
+input in;
+
+endmodule
diff --git a/tests/hana/test_parse2synthtrans_port_vector_1_test.v b/tests/hana/test_parse2synthtrans_port_vector_1_test.v
new file mode 100644 (file)
index 0000000..a740282
--- /dev/null
@@ -0,0 +1,9 @@
+module test(in1, in2, out1, out2, io1, io2);
+inout [1:0] io1;
+inout [0:1] io2;
+output [1:0] out1;
+output [0:1] out2;
+input [1:0] in1;
+input [0:1] in2;
+
+endmodule
diff --git a/tests/hana/test_parse2synthtrans_v2k_comb_logic_sens_list_test.v b/tests/hana/test_parse2synthtrans_v2k_comb_logic_sens_list_test.v
new file mode 100644 (file)
index 0000000..50f1d35
--- /dev/null
@@ -0,0 +1,9 @@
+module test(q, d, clk, reset);
+output reg q;
+input d, clk, reset;
+
+always @ (posedge clk, negedge reset)
+       if(!reset) q <= 0;
+       else q <= d;
+
+endmodule
diff --git a/tests/hana/test_parser_constructs_module_basic1_test.v b/tests/hana/test_parser_constructs_module_basic1_test.v
new file mode 100644 (file)
index 0000000..67a272d
--- /dev/null
@@ -0,0 +1,2 @@
+module test;
+endmodule
diff --git a/tests/hana/test_parser_constructs_param_basic0_test.v b/tests/hana/test_parser_constructs_param_basic0_test.v
new file mode 100644 (file)
index 0000000..fd67923
--- /dev/null
@@ -0,0 +1,10 @@
+module test #( parameter v2kparam = 5)
+(in, out, io, vin, vout, vio);
+input in;
+output out;
+inout io;
+input [3:0] vin;
+output [v2kparam:0] vout;
+inout [0:3] vio;
+parameter myparam = 10;
+endmodule
diff --git a/tests/hana/test_parser_constructs_port_basic0_test.v b/tests/hana/test_parser_constructs_port_basic0_test.v
new file mode 100644 (file)
index 0000000..8478e31
--- /dev/null
@@ -0,0 +1,8 @@
+module test(in, out, io, vin, vout, vio);
+input in;
+output out;
+inout io;
+input [3:0] vin;
+output [3:0] vout;
+inout [0:3] vio;
+endmodule
diff --git a/tests/hana/test_parser_directives_define_simpledef_test.v b/tests/hana/test_parser_directives_define_simpledef_test.v
new file mode 100644 (file)
index 0000000..4a5d234
--- /dev/null
@@ -0,0 +1,9 @@
+`define parvez ahmad
+`define  WIRE wire
+`define TEN 10
+
+module `parvez();
+parameter param = `TEN;
+`WIRE w;
+assign w = `TEN;
+endmodule
diff --git a/tests/hana/test_parser_misc_operators_test.v b/tests/hana/test_parser_misc_operators_test.v
new file mode 100644 (file)
index 0000000..8fe8e7b
--- /dev/null
@@ -0,0 +1,29 @@
+module test(out, i0, i1, i2, i3, s1, s0);
+output out;
+input i0, i1, i2, i3;
+input s1, s0;
+
+assign out = (~s1 & s0 & i0) |
+                        (~s1 & s0 & i1) |
+                        (s1 & ~s0 & i2) |
+                        (s1 & s0 & i3);
+
+endmodule
+
+module ternaryop(out, i0, i1, i2, i3, s1, s0);
+output out;
+input i0, i1, i2, i3;
+input s1, s0;
+
+assign out = s1 ? (s0 ? i3 : i2) : (s0 ? i1 : i0);
+
+endmodule
+
+module fulladd4(sum, c_out, a, b, c_in);
+output [3:0] sum;
+output c_out;
+input [3:0] a, b;
+input c_in;
+
+assign {c_out, sum} = a + b + c_in;
+endmodule
diff --git a/tests/hana/test_parser_v2k_comb_port_data_type_test.v b/tests/hana/test_parser_v2k_comb_port_data_type_test.v
new file mode 100644 (file)
index 0000000..099585b
--- /dev/null
@@ -0,0 +1,6 @@
+module adder(sum , co, a, b, ci);
+output reg             [31:0]  sum;
+output reg                             co;
+input  wire    [31:0]  a, b;
+input wire                             ci;
+endmodule
diff --git a/tests/hana/test_parser_v2k_comma_sep_sens_list_test.v b/tests/hana/test_parser_v2k_comma_sep_sens_list_test.v
new file mode 100644 (file)
index 0000000..50f1d35
--- /dev/null
@@ -0,0 +1,9 @@
+module test(q, d, clk, reset);
+output reg q;
+input d, clk, reset;
+
+always @ (posedge clk, negedge reset)
+       if(!reset) q <= 0;
+       else q <= d;
+
+endmodule
diff --git a/tests/hana/test_simulation_always_15_test.v b/tests/hana/test_simulation_always_15_test.v
new file mode 100644 (file)
index 0000000..5c5fed5
--- /dev/null
@@ -0,0 +1,5 @@
+module test(input [1:0] in, output reg [1:0] out);
+
+always @(in)
+    out = in;
+endmodule      
diff --git a/tests/hana/test_simulation_always_17_test.v b/tests/hana/test_simulation_always_17_test.v
new file mode 100644 (file)
index 0000000..2d5abc4
--- /dev/null
@@ -0,0 +1,13 @@
+module test(a, b, c, d, z);
+input a, b, c, d;
+output z;
+reg z, temp1, temp2;
+
+always @(a or b or c or d)
+begin
+    temp1 = a ^ b;
+       temp2 = c ^ d;
+       z = temp1 ^ temp2;
+end    
+
+endmodule
diff --git a/tests/hana/test_simulation_always_18_test.v b/tests/hana/test_simulation_always_18_test.v
new file mode 100644 (file)
index 0000000..234407e
--- /dev/null
@@ -0,0 +1,10 @@
+module test (in1, in2, out);
+input  in1, in2;
+output  reg out;
+
+always @ ( in1 or in2)
+       if(in1 > in2)
+               out = in1;
+       else
+               out = in2;
+endmodule              
diff --git a/tests/hana/test_simulation_always_19_test.v b/tests/hana/test_simulation_always_19_test.v
new file mode 100644 (file)
index 0000000..5152781
--- /dev/null
@@ -0,0 +1,11 @@
+module test(ctrl, in1,  in2, out);
+input ctrl;
+input  in1, in2;
+output  reg out;
+
+always @ (ctrl or in1 or in2)
+       if(ctrl)
+               out = in1 & in2;
+       else 
+               out = in1 | in2;
+endmodule              
diff --git a/tests/hana/test_simulation_always_1_test.v b/tests/hana/test_simulation_always_1_test.v
new file mode 100644 (file)
index 0000000..211369c
--- /dev/null
@@ -0,0 +1,5 @@
+module test(input in, output reg out);
+
+always @(in)
+    out = in;
+endmodule      
diff --git a/tests/hana/test_simulation_always_20_test.v b/tests/hana/test_simulation_always_20_test.v
new file mode 100644 (file)
index 0000000..6b3e861
--- /dev/null
@@ -0,0 +1,15 @@
+module NonBlockingEx(clk, merge, er, xmit, fddi, claim);
+input clk, merge, er, xmit, fddi;
+output reg claim;
+reg fcr;
+
+always @(posedge clk)
+begin
+    fcr <= er | xmit;
+
+       if(merge)
+           claim <= fcr & fddi;
+       else
+           claim <= fddi;
+end
+endmodule
diff --git a/tests/hana/test_simulation_always_21_test.v b/tests/hana/test_simulation_always_21_test.v
new file mode 100644 (file)
index 0000000..6c47b4b
--- /dev/null
@@ -0,0 +1,11 @@
+module FlipFlop(clk, cs, ns);
+input clk;
+input [7:0] cs;
+output [7:0] ns;
+integer is;
+
+always @(posedge clk)
+    is <= cs;
+
+assign ns = is;
+endmodule      
diff --git a/tests/hana/test_simulation_always_22_test.v b/tests/hana/test_simulation_always_22_test.v
new file mode 100644 (file)
index 0000000..8d91f81
--- /dev/null
@@ -0,0 +1,7 @@
+module inc(clock, counter);
+
+input clock;
+output reg [7:0] counter;
+always @(posedge clock)
+       counter <= counter + 1;
+endmodule      
diff --git a/tests/hana/test_simulation_always_23_test.v b/tests/hana/test_simulation_always_23_test.v
new file mode 100644 (file)
index 0000000..f1f13bb
--- /dev/null
@@ -0,0 +1,14 @@
+module MyCounter (clock, preset, updown, presetdata, counter);
+input clock, preset, updown;
+input [1: 0] presetdata;
+output reg [1:0] counter;
+
+always @(posedge clock)
+    if(preset)
+           counter <= presetdata;
+       else
+           if(updown)
+                   counter <= counter + 1;
+               else
+                   counter <= counter - 1;
+endmodule                      
diff --git a/tests/hana/test_simulation_always_27_test.v b/tests/hana/test_simulation_always_27_test.v
new file mode 100644 (file)
index 0000000..577378f
--- /dev/null
@@ -0,0 +1,13 @@
+module FlipFlop(clock, cs, ns);
+input clock;
+input cs;
+output reg ns;
+reg temp;
+
+always @(posedge clock)
+begin
+    temp <= cs;
+       ns <= temp;
+end    
+
+endmodule      
diff --git a/tests/hana/test_simulation_always_29_test.v b/tests/hana/test_simulation_always_29_test.v
new file mode 100644 (file)
index 0000000..5560683
--- /dev/null
@@ -0,0 +1,9 @@
+module test(input in, output reg [1:0] out);
+
+    always @(in)
+    begin
+        out = in;
+        out = out + in;
+    end
+
+endmodule
diff --git a/tests/hana/test_simulation_always_31_tt.v b/tests/hana/test_simulation_always_31_tt.v
new file mode 100644 (file)
index 0000000..299c0ca
--- /dev/null
@@ -0,0 +1,50 @@
+module test(clk, cond, data);
+input cond;
+input clk;
+output data;
+
+wire  synth_net;
+wire  synth_net_0;
+wire  synth_net_1;
+wire  synth_net_2;
+
+wire  synth_net_3;
+wire  synth_net_4;
+wire  synth_net_5;
+wire  synth_net_6;
+
+wire  synth_net_7;
+wire  synth_net_8;
+wire  synth_net_9;
+wire  synth_net_10;
+
+wire  synth_net_11;
+wire  tmp;
+AND2 synth_AND(.in({synth_net_0, synth_net_1}), .
+    out(synth_net_2));
+AND2 synth_AND_0(.in({synth_net_3, synth_net_4}), .out(
+    synth_net_5));
+AND2 synth_AND_1(.in({synth_net_6, synth_net_7}), .out(
+    synth_net_8));
+AND2 synth_AND_2(.in({synth_net_9, synth_net_10}), .out(
+    synth_net_11));
+BUF synth_BUF(.in(synth_net), .out(synth_net_0));
+BUF 
+    synth_BUF_0(.in(data), .out(synth_net_3));
+BUF synth_BUF_1(.in(synth_net_8)
+    , .out(tmp));
+BUF synth_BUF_2(.in(tmp), .out(synth_net_9));
+MUX2 synth_MUX(.
+    in({synth_net_2, synth_net_5}), .select(cond), .out(synth_net_6));
+MUX2 
+    synth_MUX_0(.in({synth_net_1, synth_net_4}), .select(cond), .out(synth_net_7
+    ));
+FF synth_FF(.d(synth_net_11), .clk(clk), .q(data));
+VCC synth_VCC(.out(
+    synth_net));
+VCC synth_VCC_0(.out(synth_net_1));
+VCC synth_VCC_1(.out(
+    synth_net_4));
+VCC synth_VCC_2(.out(synth_net_10));
+endmodule
+
diff --git a/tests/hana/test_simulation_and_1_test.v b/tests/hana/test_simulation_and_1_test.v
new file mode 100644 (file)
index 0000000..fba639c
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [1:0] in, output out);
+assign out = in[0] & in[1];
+endmodule
diff --git a/tests/hana/test_simulation_and_2_test.v b/tests/hana/test_simulation_and_2_test.v
new file mode 100644 (file)
index 0000000..715bc7c
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [1:0] in, output out);
+assign out = in[0] && in[1];
+endmodule
diff --git a/tests/hana/test_simulation_and_3_test.v b/tests/hana/test_simulation_and_3_test.v
new file mode 100644 (file)
index 0000000..74dccab
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [2:0] in, output out);
+assign out = in[0] & in[1] & in[2];
+endmodule
diff --git a/tests/hana/test_simulation_and_4_test.v b/tests/hana/test_simulation_and_4_test.v
new file mode 100644 (file)
index 0000000..48ed910
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [2:0] in, output out);
+assign out = in[0] && in[1] && in[2];
+endmodule
diff --git a/tests/hana/test_simulation_and_5_test.v b/tests/hana/test_simulation_and_5_test.v
new file mode 100644 (file)
index 0000000..29a3557
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [3:0] in, output out);
+assign out = in[0] & in[1] & in[2] & in[3];
+endmodule
diff --git a/tests/hana/test_simulation_and_6_test.v b/tests/hana/test_simulation_and_6_test.v
new file mode 100644 (file)
index 0000000..ebce4ee
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [3:0] in, output out);
+assign out = in[0] && in[1] && in[2] && in[3];
+endmodule
diff --git a/tests/hana/test_simulation_and_7_test.v b/tests/hana/test_simulation_and_7_test.v
new file mode 100644 (file)
index 0000000..d394ada
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [3:0] in, output out);
+and myand(out, in[0], in[1], in[2], in[3]);
+endmodule
diff --git a/tests/hana/test_simulation_buffer_1_test.v b/tests/hana/test_simulation_buffer_1_test.v
new file mode 100644 (file)
index 0000000..e9bb7f6
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input in, output out);
+assign out = in;
+endmodule
diff --git a/tests/hana/test_simulation_buffer_2_test.v b/tests/hana/test_simulation_buffer_2_test.v
new file mode 100644 (file)
index 0000000..9a3f5aa
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input [1:0] in, output [1:0] out);
+assign out[0] = in[0];
+assign out[1] = in[1];
+endmodule
diff --git a/tests/hana/test_simulation_buffer_3_test.v b/tests/hana/test_simulation_buffer_3_test.v
new file mode 100644 (file)
index 0000000..9bca426
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input in, output [1:0] out);
+assign out[0] = in;
+assign out[1] = in;
+endmodule
diff --git a/tests/hana/test_simulation_decoder_2_test.v b/tests/hana/test_simulation_decoder_2_test.v
new file mode 100644 (file)
index 0000000..5bdf197
--- /dev/null
@@ -0,0 +1,14 @@
+module test (input [1:0] in, input enable, output reg  out);
+
+always @(in or enable)
+    if(!enable)
+           out = 4'b0000;
+       else begin
+          case (in)
+              2'b00 : out = 0 ;
+              2'b01 : out = 1;
+              2'b10 : out = 0;
+              2'b11 : out = 1;
+           endcase
+       end
+endmodule
diff --git a/tests/hana/test_simulation_decoder_3_test.v b/tests/hana/test_simulation_decoder_3_test.v
new file mode 100644 (file)
index 0000000..44f5de1
--- /dev/null
@@ -0,0 +1,14 @@
+module test (input [1:0] in, input enable, output reg [2:0] out);
+
+always @(in or enable)
+    if(!enable)
+           out = 3'b000;
+       else begin
+          case (in)
+              2'b00 : out = 3'b001 ;
+              2'b01 : out = 3'b010;
+              2'b10 : out = 3'b010;
+              2'b11 : out = 3'b100;
+           endcase
+       end
+endmodule
diff --git a/tests/hana/test_simulation_decoder_4_test.v b/tests/hana/test_simulation_decoder_4_test.v
new file mode 100644 (file)
index 0000000..871a5bb
--- /dev/null
@@ -0,0 +1,14 @@
+module test (input [2:0] in, output reg [7:0] out);
+
+always @(in )
+          case (in)
+              3'b000 : out = 8'b00000001;
+              3'b001 : out = 8'b00000010;
+              3'b010 : out = 8'b00000100;
+              3'b011 : out = 8'b00001000;
+              3'b100 : out = 8'b00010000;
+              3'b101 : out = 8'b00100000;
+              3'b110 : out = 8'b01000000;
+              3'b111 : out = 8'b10000000;
+           endcase
+endmodule      
diff --git a/tests/hana/test_simulation_decoder_5_test.v b/tests/hana/test_simulation_decoder_5_test.v
new file mode 100644 (file)
index 0000000..497fa4b
--- /dev/null
@@ -0,0 +1,17 @@
+module test (input [2:0] in, input enable, output reg [7:0] out);
+
+always @(in or enable )
+    if(!enable)
+           out = 8'b00000000;
+       else    
+          case (in)
+              3'b000 : out = 8'b00000001;
+              3'b001 : out = 8'b00000010;
+              3'b010 : out = 8'b00000100;
+              3'b011 : out = 8'b00001000;
+              3'b100 : out = 8'b00010000;
+              3'b101 : out = 8'b00100000;
+              3'b110 : out = 8'b01000000;
+              3'b111 : out = 8'b10000000;
+           endcase
+endmodule      
diff --git a/tests/hana/test_simulation_decoder_6_test.v b/tests/hana/test_simulation_decoder_6_test.v
new file mode 100644 (file)
index 0000000..fd19ad6
--- /dev/null
@@ -0,0 +1,27 @@
+module test (input [3:0] in, input enable, output reg [15:0] out);
+
+always @(in or enable)
+    if(!enable)
+           out = 16'b0000000000000000;
+       else begin
+          case (in)
+              4'b0000 : out = 16'b0000000000000001;
+              4'b0001 : out = 16'b0000000000000010;
+              4'b0010 : out = 16'b0000000000000100;
+              4'b0011 : out = 16'b0000000000001000;
+              4'b0100 : out = 16'b0000000000010000;
+              4'b0101 : out = 16'b0000000000100000;
+              4'b0110 : out = 16'b0000000001000000;
+              4'b0111 : out = 16'b0000000010000000;
+              4'b1000 : out = 16'b0000000100000000;
+              4'b1001 : out = 16'b0000001000000000;
+              4'b1010 : out = 16'b0000010000000000;
+              4'b1011 : out = 16'b0000100000000000;
+              4'b1100 : out = 16'b0001000000000000;
+              4'b1101 : out = 16'b0010000000000000;
+              4'b1110 : out = 16'b0100000000000000;
+              4'b1111 : out = 16'b1000000000000000;
+           endcase
+       end
+endmodule      
+
diff --git a/tests/hana/test_simulation_decoder_7_test.v b/tests/hana/test_simulation_decoder_7_test.v
new file mode 100644 (file)
index 0000000..462e941
--- /dev/null
@@ -0,0 +1,43 @@
+module test (input [4:0] in, input enable, output reg [31:0] out);
+
+always @(in or enable)
+    if(!enable)
+           out = 32'b00000000000000000000000000000000;
+       else begin
+          case (in)
+              5'b00000 : out = 32'b00000000000000000000000000000001;
+              5'b00001 : out = 32'b00000000000000000000000000000010;
+              5'b00010 : out = 32'b00000000000000000000000000000100;
+              5'b00011 : out = 32'b00000000000000000000000000001000;
+              5'b00100 : out = 32'b00000000000000000000000000010000;
+              5'b00101 : out = 32'b00000000000000000000000000100000;
+              5'b00110 : out = 32'b00000000000000000000000001000000;
+              5'b00111 : out = 32'b00000000000000000000000010000000;
+              5'b01000 : out = 32'b00000000000000000000000100000000;
+              5'b01001 : out = 32'b00000000000000000000001000000000;
+              5'b01010 : out = 32'b00000000000000000000010000000000;
+              5'b01011 : out = 32'b00000000000000000000100000000000;
+              5'b01100 : out = 32'b00000000000000000001000000000000;
+              5'b01101 : out = 32'b00000000000000000010000000000000;
+              5'b01110 : out = 32'b00000000000000000100000000000000;
+              5'b01111 : out = 32'b00000000000000001000000000000000;
+              5'b10000 : out = 32'b00000000000000010000000000000000;
+              5'b10001 : out = 32'b00000000000000100000000000000000;
+              5'b10010 : out = 32'b00000000000001000000000000000000;
+              5'b10011 : out = 32'b00000000000010000000000000000000;
+              5'b10100 : out = 32'b00000000000100000000000000000000;
+              5'b10101 : out = 32'b00000000001000000000000000000000;
+              5'b10110 : out = 32'b00000000010000000000000000000000;
+              5'b10111 : out = 32'b00000000100000000000000000000000;
+              5'b11000 : out = 32'b00000001000000000000000000000000;
+              5'b11001 : out = 32'b00000010000000000000000000000000;
+              5'b11010 : out = 32'b00000100000000000000000000000000;
+              5'b11011 : out = 32'b00001000000000000000000000000000;
+              5'b11100 : out = 32'b00010000000000000000000000000000;
+              5'b11101 : out = 32'b00100000000000000000000000000000;
+              5'b11110 : out = 32'b01000000000000000000000000000000;
+              5'b11111 : out = 32'b10000000000000000000000000000000;
+           endcase
+       end
+endmodule      
+
diff --git a/tests/hana/test_simulation_decoder_8_test.v b/tests/hana/test_simulation_decoder_8_test.v
new file mode 100644 (file)
index 0000000..751d60f
--- /dev/null
@@ -0,0 +1,76 @@
+module test (input [5:0] in, input enable, output reg [63:0] out);
+
+always @(in or enable)
+    if(!enable)
+           out = 64'b0000000000000000000000000000000000000000000000000000000000000000;
+       else begin
+          case (in)
+              6'b000000 : out = 64'b0000000000000000000000000000000000000000000000000000000000000001;
+              6'b000001 : out = 64'b0000000000000000000000000000000000000000000000000000000000000010;
+              6'b000010 : out = 64'b0000000000000000000000000000000000000000000000000000000000000100;
+              6'b000011 : out = 64'b0000000000000000000000000000000000000000000000000000000000001000;
+              6'b000100 : out = 64'b0000000000000000000000000000000000000000000000000000000000010000;
+              6'b000101 : out = 64'b0000000000000000000000000000000000000000000000000000000000100000;
+              6'b000110 : out = 64'b0000000000000000000000000000000000000000000000000000000001000000;
+              6'b000111 : out = 64'b0000000000000000000000000000000000000000000000000000000010000000;
+              6'b001000 : out = 64'b0000000000000000000000000000000000000000000000000000000100000000;
+              6'b001001 : out = 64'b0000000000000000000000000000000000000000000000000000001000000000;
+              6'b001010 : out = 64'b0000000000000000000000000000000000000000000000000000010000000000;
+              6'b001011 : out = 64'b0000000000000000000000000000000000000000000000000000100000000000;
+              6'b001100 : out = 64'b0000000000000000000000000000000000000000000000000001000000000000;
+              6'b001101 : out = 64'b0000000000000000000000000000000000000000000000000010000000000000;
+              6'b001110 : out = 64'b0000000000000000000000000000000000000000000000000100000000000000;
+              6'b001111 : out = 64'b0000000000000000000000000000000000000000000000001000000000000000;
+              6'b010000 : out = 64'b0000000000000000000000000000000000000000000000010000000000000000;
+              6'b010001 : out = 64'b0000000000000000000000000000000000000000000000100000000000000000;
+              6'b010010 : out = 64'b0000000000000000000000000000000000000000000001000000000000000000;
+              6'b010011 : out = 64'b0000000000000000000000000000000000000000000010000000000000000000;
+              6'b010100 : out = 64'b0000000000000000000000000000000000000000000100000000000000000000;
+              6'b010101 : out = 64'b0000000000000000000000000000000000000000001000000000000000000000;
+              6'b010110 : out = 64'b0000000000000000000000000000000000000000010000000000000000000000;
+              6'b010111 : out = 64'b0000000000000000000000000000000000000000100000000000000000000000;
+              6'b011000 : out = 64'b0000000000000000000000000000000000000001000000000000000000000000;
+              6'b011001 : out = 64'b0000000000000000000000000000000000000010000000000000000000000000;
+              6'b011010 : out = 64'b0000000000000000000000000000000000000100000000000000000000000000;
+              6'b011011 : out = 64'b0000000000000000000000000000000000001000000000000000000000000000;
+              6'b011100 : out = 64'b0000000000000000000000000000000000010000000000000000000000000000;
+              6'b011101 : out = 64'b0000000000000000000000000000000000100000000000000000000000000000;
+              6'b011110 : out = 64'b0000000000000000000000000000000001000000000000000000000000000000;
+              6'b011111 : out = 64'b0000000000000000000000000000000010000000000000000000000000000000;
+
+              6'b100000 : out = 64'b0000000000000000000000000000000100000000000000000000000000000000;
+              6'b100001 : out = 64'b0000000000000000000000000000001000000000000000000000000000000000;
+              6'b100010 : out = 64'b0000000000000000000000000000010000000000000000000000000000000000;
+              6'b100011 : out = 64'b0000000000000000000000000000100000000000000000000000000000000000;
+              6'b100100 : out = 64'b0000000000000000000000000001000000000000000000000000000000000000;
+              6'b100101 : out = 64'b0000000000000000000000000010000000000000000000000000000000000000;
+              6'b100110 : out = 64'b0000000000000000000000000100000000000000000000000000000000000000;
+              6'b100111 : out = 64'b0000000000000000000000001000000000000000000000000000000000000000;
+              6'b101000 : out = 64'b0000000000000000000000010000000000000000000000000000000000000000;
+              6'b101001 : out = 64'b0000000000000000000000100000000000000000000000000000000000000000;
+              6'b101010 : out = 64'b0000000000000000000001000000000000000000000000000000000000000000;
+              6'b101011 : out = 64'b0000000000000000000010000000000000000000000000000000000000000000;
+              6'b101100 : out = 64'b0000000000000000000100000000000000000000000000000000000000000000;
+              6'b101101 : out = 64'b0000000000000000001000000000000000000000000000000000000000000000;
+              6'b101110 : out = 64'b0000000000000000010000000000000000000000000000000000000000000000;
+              6'b101111 : out = 64'b0000000000000000100000000000000000000000000000000000000000000000;
+              6'b110000 : out = 64'b0000000000000001000000000000000000000000000000000000000000000000;
+              6'b110001 : out = 64'b0000000000000010000000000000000000000000000000000000000000000000;
+              6'b110010 : out = 64'b0000000000000100000000000000000000000000000000000000000000000000;
+              6'b110011 : out = 64'b0000000000001000000000000000000000000000000000000000000000000000;
+              6'b110100 : out = 64'b0000000000010000000000000000000000000000000000000000000000000000;
+              6'b110101 : out = 64'b0000000000100000000000000000000000000000000000000000000000000000;
+              6'b110110 : out = 64'b0000000001000000000000000000000000000000000000000000000000000000;
+              6'b110111 : out = 64'b0000000010000000000000000000000000000000000000000000000000000000;
+              6'b111000 : out = 64'b0000000100000000000000000000000000000000000000000000000000000000;
+              6'b111001 : out = 64'b0000001000000000000000000000000000000000000000000000000000000000;
+              6'b111010 : out = 64'b0000010000000000000000000000000000000000000000000000000000000000;
+              6'b111011 : out = 64'b0000100000000000000000000000000000000000000000000000000000000000;
+              6'b111100 : out = 64'b0001000000000000000000000000000000000000000000000000000000000000;
+              6'b111101 : out = 64'b0010000000000000000000000000000000000000000000000000000000000000;
+              6'b111110 : out = 64'b0100000000000000000000000000000000000000000000000000000000000000;
+              6'b111111 : out = 64'b1000000000000000000000000000000000000000000000000000000000000000;
+           endcase
+       end
+endmodule      
+
diff --git a/tests/hana/test_simulation_inc_16_test.v b/tests/hana/test_simulation_inc_16_test.v
new file mode 100644 (file)
index 0000000..7ff42ff
--- /dev/null
@@ -0,0 +1,5 @@
+module test(input [15:0] in, output [15:0] out);
+
+assign out = -in;
+
+endmodule
diff --git a/tests/hana/test_simulation_inc_1_test.v b/tests/hana/test_simulation_inc_1_test.v
new file mode 100644 (file)
index 0000000..02bec2c
--- /dev/null
@@ -0,0 +1,5 @@
+module test(input in, output  out);
+
+assign out = -in;
+
+endmodule
diff --git a/tests/hana/test_simulation_inc_2_test.v b/tests/hana/test_simulation_inc_2_test.v
new file mode 100644 (file)
index 0000000..b96e05a
--- /dev/null
@@ -0,0 +1,5 @@
+module test(input [1:0] in, output [1:0] out);
+
+assign out = -in;
+
+endmodule
diff --git a/tests/hana/test_simulation_inc_32_test.v b/tests/hana/test_simulation_inc_32_test.v
new file mode 100644 (file)
index 0000000..5700d0c
--- /dev/null
@@ -0,0 +1,5 @@
+module test(input [31:0] in, output [31:0] out);
+
+assign out = -in;
+
+endmodule
diff --git a/tests/hana/test_simulation_inc_4_test.v b/tests/hana/test_simulation_inc_4_test.v
new file mode 100644 (file)
index 0000000..34940d6
--- /dev/null
@@ -0,0 +1,5 @@
+module test(input [3:0] in, output [3:0] out);
+
+assign out = -in;
+
+endmodule
diff --git a/tests/hana/test_simulation_inc_8_test.v b/tests/hana/test_simulation_inc_8_test.v
new file mode 100644 (file)
index 0000000..c36d69f
--- /dev/null
@@ -0,0 +1,5 @@
+module test(input [7:0] in, output [7:0] out);
+
+assign out = -in;
+
+endmodule
diff --git a/tests/hana/test_simulation_mod_1_xx.v b/tests/hana/test_simulation_mod_1_xx.v
new file mode 100644 (file)
index 0000000..75144a8
--- /dev/null
@@ -0,0 +1,13 @@
+module test(in1, in2, out);
+input in1;
+input in2;
+output out;
+
+wire  synth_net_0;
+wire  synth_net_1;
+BUF synth_BUF_0(.in(synth_net_1), .out(out
+    ));
+DIV1 synth_DIV(.in1(in1), .in2(in2), .rem(synth_net_0), .out(synth_net_1
+    ));
+endmodule
+
diff --git a/tests/hana/test_simulation_mux_16_test.v b/tests/hana/test_simulation_mux_16_test.v
new file mode 100644 (file)
index 0000000..de4b6f8
--- /dev/null
@@ -0,0 +1,22 @@
+module test(input [15:0] in, input [3:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+           4: out = in[4];
+           5: out = in[5];
+           6: out = in[6];
+           7: out = in[7];
+           8: out = in[8];
+           9: out = in[9];
+           10: out = in[10];
+           11: out = in[11];
+           12: out = in[12];
+           13: out = in[13];
+           14: out = in[14];
+           15: out = in[15];
+       endcase
+endmodule
diff --git a/tests/hana/test_simulation_mux_2_test.v b/tests/hana/test_simulation_mux_2_test.v
new file mode 100644 (file)
index 0000000..bc676c7
--- /dev/null
@@ -0,0 +1,8 @@
+module test(input [1:0] in, input select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+       endcase
+endmodule      
diff --git a/tests/hana/test_simulation_mux_32_test.v b/tests/hana/test_simulation_mux_32_test.v
new file mode 100644 (file)
index 0000000..16de4d7
--- /dev/null
@@ -0,0 +1,39 @@
+module test(input [31:0] in, input [4:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+           4: out = in[4];
+           5: out = in[5];
+           6: out = in[6];
+           7: out = in[7];
+           8: out = in[8];
+           9: out = in[9];
+           10: out = in[10];
+           11: out = in[11];
+           12: out = in[12];
+           13: out = in[13];
+           14: out = in[14];
+           15: out = in[15];
+           16: out = in[16];
+           17: out = in[17];
+           18: out = in[18];
+           19: out = in[19];
+           20: out = in[20];
+           21: out = in[21];
+           22: out = in[22];
+           23: out = in[23];
+           24: out = in[24];
+           25: out = in[25];
+           26: out = in[26];
+           27: out = in[27];
+           28: out = in[28];
+           29: out = in[29];
+           30: out = in[30];
+           31: out = in[31];
+       endcase
+endmodule      
+
diff --git a/tests/hana/test_simulation_mux_4_test.v b/tests/hana/test_simulation_mux_4_test.v
new file mode 100644 (file)
index 0000000..6a112c6
--- /dev/null
@@ -0,0 +1,10 @@
+module test(input [3:0] in, input [1:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+       endcase
+endmodule      
diff --git a/tests/hana/test_simulation_mux_64_test.v b/tests/hana/test_simulation_mux_64_test.v
new file mode 100644 (file)
index 0000000..420239c
--- /dev/null
@@ -0,0 +1,71 @@
+module test(input [63:0] in, input [5:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+           4: out = in[4];
+           5: out = in[5];
+           6: out = in[6];
+           7: out = in[7];
+           8: out = in[8];
+           9: out = in[9];
+           10: out = in[10];
+           11: out = in[11];
+           12: out = in[12];
+           13: out = in[13];
+           14: out = in[14];
+           15: out = in[15];
+           16: out = in[16];
+           17: out = in[17];
+           18: out = in[18];
+           19: out = in[19];
+           20: out = in[20];
+           21: out = in[21];
+           22: out = in[22];
+           23: out = in[23];
+           24: out = in[24];
+           25: out = in[25];
+           26: out = in[26];
+           27: out = in[27];
+           28: out = in[28];
+           29: out = in[29];
+           30: out = in[30];
+           31: out = in[31];
+           32: out = in[32];
+           33: out = in[33];
+           34: out = in[34];
+           35: out = in[35];
+           36: out = in[36];
+           37: out = in[37];
+           38: out = in[38];
+           39: out = in[39];
+           40: out = in[40];
+           41: out = in[41];
+           42: out = in[42];
+           43: out = in[43];
+           44: out = in[44];
+           45: out = in[45];
+           46: out = in[46];
+           47: out = in[47];
+           48: out = in[48];
+           49: out = in[49];
+           50: out = in[50];
+           51: out = in[51];
+           52: out = in[52];
+           53: out = in[53];
+           54: out = in[54];
+           55: out = in[55];
+           56: out = in[56];
+           57: out = in[57];
+           58: out = in[58];
+           59: out = in[59];
+           60: out = in[60];
+           61: out = in[61];
+           62: out = in[62];
+           63: out = in[63];
+       endcase
+endmodule      
+
diff --git a/tests/hana/test_simulation_mux_8_test.v b/tests/hana/test_simulation_mux_8_test.v
new file mode 100644 (file)
index 0000000..f53a2c5
--- /dev/null
@@ -0,0 +1,14 @@
+module test(input [7:0] in, input [2:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+           4: out = in[4];
+           5: out = in[5];
+           6: out = in[6];
+           7: out = in[7];
+       endcase
+endmodule
diff --git a/tests/hana/test_simulation_nand_1_test.v b/tests/hana/test_simulation_nand_1_test.v
new file mode 100644 (file)
index 0000000..d8f34ee
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [1:0] in, output out);
+assign out = ~(in[0] & in[1]);
+endmodule
diff --git a/tests/hana/test_simulation_nand_3_test.v b/tests/hana/test_simulation_nand_3_test.v
new file mode 100644 (file)
index 0000000..8926ceb
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [2:0] in, output out);
+assign out = !(in[0] & in[1] & in[2]);
+endmodule
diff --git a/tests/hana/test_simulation_nand_4_test.v b/tests/hana/test_simulation_nand_4_test.v
new file mode 100644 (file)
index 0000000..703a2de
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [2:0] in, output out);
+assign out = ~(in[0] && in[1] && in[2]);
+endmodule
diff --git a/tests/hana/test_simulation_nand_5_test.v b/tests/hana/test_simulation_nand_5_test.v
new file mode 100644 (file)
index 0000000..adef3c9
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [3:0] in, output out);
+assign out = !(in[0] & in[1] & in[2] & in[3]);
+endmodule
diff --git a/tests/hana/test_simulation_nand_6_test.v b/tests/hana/test_simulation_nand_6_test.v
new file mode 100644 (file)
index 0000000..a2136f2
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [3:0] in, output out);
+assign out = !(in[0] && in[1] && in[2] && in[3]);
+endmodule
diff --git a/tests/hana/test_simulation_nor_1_test.v b/tests/hana/test_simulation_nor_1_test.v
new file mode 100644 (file)
index 0000000..df4e8bf
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [1:0] in, output out);
+assign out = ~(in[0] | in[1]);
+endmodule
diff --git a/tests/hana/test_simulation_nor_2_test.v b/tests/hana/test_simulation_nor_2_test.v
new file mode 100644 (file)
index 0000000..2cfffc4
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [2:0] in, output out);
+assign out = ~(in[0] | in[1] | in[2]);
+endmodule
diff --git a/tests/hana/test_simulation_nor_3_test.v b/tests/hana/test_simulation_nor_3_test.v
new file mode 100644 (file)
index 0000000..9f1ef8f
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [3:0] in, output out);
+assign out = ~(in[0] | in[1] | in[2] | in[3]);
+endmodule
diff --git a/tests/hana/test_simulation_nor_4_test.v b/tests/hana/test_simulation_nor_4_test.v
new file mode 100644 (file)
index 0000000..d8e6850
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [3:0] in, output out);
+nor mynor(out, in[0], in[1], in[2], in[3]);
+endmodule
diff --git a/tests/hana/test_simulation_opt_constprop_contassign_1_test.v b/tests/hana/test_simulation_opt_constprop_contassign_1_test.v
new file mode 100644 (file)
index 0000000..a39b58b
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input in, output out);
+assign out = 1'b1;
+endmodule
diff --git a/tests/hana/test_simulation_or_1_test.v b/tests/hana/test_simulation_or_1_test.v
new file mode 100644 (file)
index 0000000..bdfffd3
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [1:0] in, output out);
+assign out = in[0] | in[1];
+endmodule
diff --git a/tests/hana/test_simulation_or_2_test.v b/tests/hana/test_simulation_or_2_test.v
new file mode 100644 (file)
index 0000000..291c8c7
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [1:0] in, output out);
+assign out = in[0] || in[1];
+endmodule
diff --git a/tests/hana/test_simulation_or_3_test.v b/tests/hana/test_simulation_or_3_test.v
new file mode 100644 (file)
index 0000000..ad00c70
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [2:0] in, output out);
+assign out = in[0] | in[1] | in[2];
+endmodule
diff --git a/tests/hana/test_simulation_or_4_test.v b/tests/hana/test_simulation_or_4_test.v
new file mode 100644 (file)
index 0000000..2ec57fa
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [2:0] in, output out);
+assign out = in[0] || in[1] || in[2];
+endmodule
diff --git a/tests/hana/test_simulation_or_5_test.v b/tests/hana/test_simulation_or_5_test.v
new file mode 100644 (file)
index 0000000..f6a2d14
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [3:0] in, output out);
+assign out = in[0] | in[1] | in[2] | in[3];
+endmodule
diff --git a/tests/hana/test_simulation_or_6_test.v b/tests/hana/test_simulation_or_6_test.v
new file mode 100644 (file)
index 0000000..ecd85c3
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [3:0] in, output out);
+assign out = in[0] || in[1] || in[2] || in[3];
+endmodule
diff --git a/tests/hana/test_simulation_seq_ff_1_test.v b/tests/hana/test_simulation_seq_ff_1_test.v
new file mode 100644 (file)
index 0000000..5aac49c
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input in,  input clk, output reg out);
+always @(posedge clk)
+    out <= in;
+endmodule      
diff --git a/tests/hana/test_simulation_seq_ff_2_test.v b/tests/hana/test_simulation_seq_ff_2_test.v
new file mode 100644 (file)
index 0000000..f1d2b7b
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input  in,  input clk,  output reg out);
+always @(negedge clk)
+   out <= in;
+endmodule      
diff --git a/tests/hana/test_simulation_shifter_left_16_test.v b/tests/hana/test_simulation_shifter_left_16_test.v
new file mode 100644 (file)
index 0000000..a57dac4
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input [15:0] IN, input [4:0] SHIFT, output [15:0] OUT);
+
+assign OUT = IN << SHIFT;
+endmodule
diff --git a/tests/hana/test_simulation_shifter_left_32_test.v b/tests/hana/test_simulation_shifter_left_32_test.v
new file mode 100644 (file)
index 0000000..672938a
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input [31:0] IN, input [5:0] SHIFT, output [31:0] OUT);
+
+assign OUT = IN << SHIFT;
+endmodule
diff --git a/tests/hana/test_simulation_shifter_left_4_test.v b/tests/hana/test_simulation_shifter_left_4_test.v
new file mode 100644 (file)
index 0000000..c525401
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input [3:0] IN, input [2:0] SHIFT, output [3:0] OUT);
+
+assign OUT = IN << SHIFT;
+endmodule
diff --git a/tests/hana/test_simulation_shifter_left_64_test.v b/tests/hana/test_simulation_shifter_left_64_test.v
new file mode 100644 (file)
index 0000000..276a7c5
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input [63:0] IN, input [6:0] SHIFT, output [63:0] OUT);
+
+assign OUT = IN << SHIFT;
+endmodule
diff --git a/tests/hana/test_simulation_shifter_left_8_test.v b/tests/hana/test_simulation_shifter_left_8_test.v
new file mode 100644 (file)
index 0000000..c172770
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input [7:0] IN, input [3:0] SHIFT, output [7:0] OUT);
+
+assign OUT = IN << SHIFT;
+endmodule
diff --git a/tests/hana/test_simulation_shifter_right_16_test.v b/tests/hana/test_simulation_shifter_right_16_test.v
new file mode 100644 (file)
index 0000000..6152adc
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input [15:0] IN, input [4:0] SHIFT, output [15:0] OUT);
+
+assign OUT = IN >> SHIFT;
+endmodule
diff --git a/tests/hana/test_simulation_shifter_right_32_test.v b/tests/hana/test_simulation_shifter_right_32_test.v
new file mode 100644 (file)
index 0000000..e910cdd
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input [31:0] IN, input [5:0] SHIFT, output [31:0] OUT);
+
+assign OUT = IN >> SHIFT;
+endmodule
diff --git a/tests/hana/test_simulation_shifter_right_4_test.v b/tests/hana/test_simulation_shifter_right_4_test.v
new file mode 100644 (file)
index 0000000..608c196
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input [3:0] IN, input [2:0] SHIFT, output [3:0] OUT);
+
+assign OUT = IN >> SHIFT;
+endmodule
diff --git a/tests/hana/test_simulation_shifter_right_64_test.v b/tests/hana/test_simulation_shifter_right_64_test.v
new file mode 100644 (file)
index 0000000..c26d593
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input [63:0] IN, input [6:0] SHIFT, output [63:0] OUT);
+
+assign OUT = IN >> SHIFT;
+endmodule
diff --git a/tests/hana/test_simulation_shifter_right_8_test.v b/tests/hana/test_simulation_shifter_right_8_test.v
new file mode 100644 (file)
index 0000000..a91c594
--- /dev/null
@@ -0,0 +1,4 @@
+module test(input [7:0] IN, input [3:0] SHIFT, output [7:0] OUT);
+
+assign OUT = IN >> SHIFT;
+endmodule
diff --git a/tests/hana/test_simulation_sop_basic_10_test.v b/tests/hana/test_simulation_sop_basic_10_test.v
new file mode 100644 (file)
index 0000000..bc676c7
--- /dev/null
@@ -0,0 +1,8 @@
+module test(input [1:0] in, input select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+       endcase
+endmodule      
diff --git a/tests/hana/test_simulation_sop_basic_11_test.v b/tests/hana/test_simulation_sop_basic_11_test.v
new file mode 100644 (file)
index 0000000..6a112c6
--- /dev/null
@@ -0,0 +1,10 @@
+module test(input [3:0] in, input [1:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+       endcase
+endmodule      
diff --git a/tests/hana/test_simulation_sop_basic_12_test.v b/tests/hana/test_simulation_sop_basic_12_test.v
new file mode 100644 (file)
index 0000000..f53a2c5
--- /dev/null
@@ -0,0 +1,14 @@
+module test(input [7:0] in, input [2:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+           4: out = in[4];
+           5: out = in[5];
+           6: out = in[6];
+           7: out = in[7];
+       endcase
+endmodule
diff --git a/tests/hana/test_simulation_sop_basic_18_test.v b/tests/hana/test_simulation_sop_basic_18_test.v
new file mode 100644 (file)
index 0000000..03fc35b
--- /dev/null
@@ -0,0 +1,5 @@
+module test(input [7:0] in, output out);
+
+assign out = ~^in;
+
+endmodule
diff --git a/tests/hana/test_simulation_sop_basic_3_test.v b/tests/hana/test_simulation_sop_basic_3_test.v
new file mode 100644 (file)
index 0000000..81759c2
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input in, output out);
+assign out = ~in;
+endmodule
diff --git a/tests/hana/test_simulation_sop_basic_7_test.v b/tests/hana/test_simulation_sop_basic_7_test.v
new file mode 100644 (file)
index 0000000..e9bb7f6
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input in, output out);
+assign out = in;
+endmodule
diff --git a/tests/hana/test_simulation_sop_basic_8_test.v b/tests/hana/test_simulation_sop_basic_8_test.v
new file mode 100644 (file)
index 0000000..a51ead0
--- /dev/null
@@ -0,0 +1,3 @@
+module test(output out);
+assign out = 1'b0;
+endmodule
diff --git a/tests/hana/test_simulation_sop_basic_9_test.v b/tests/hana/test_simulation_sop_basic_9_test.v
new file mode 100644 (file)
index 0000000..81759c2
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input in, output out);
+assign out = ~in;
+endmodule
diff --git a/tests/hana/test_simulation_techmap_and_19_tech.v b/tests/hana/test_simulation_techmap_and_19_tech.v
new file mode 100644 (file)
index 0000000..2491087
--- /dev/null
@@ -0,0 +1,7 @@
+module TECH_AND18(input [17:0] in, output out);
+assign out = &in;
+endmodule
+
+module TECH_AND4(input [3:0] in, output out);
+assign out = &in;
+endmodule
diff --git a/tests/hana/test_simulation_techmap_and_5_tech.v b/tests/hana/test_simulation_techmap_and_5_tech.v
new file mode 100644 (file)
index 0000000..6ec6a61
--- /dev/null
@@ -0,0 +1,3 @@
+module TECH_AND5(input [4:0] in, output out);
+assign out = &in;
+endmodule
diff --git a/tests/hana/test_simulation_techmap_buf_test.v b/tests/hana/test_simulation_techmap_buf_test.v
new file mode 100644 (file)
index 0000000..e9bb7f6
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input in, output out);
+assign out = in;
+endmodule
diff --git a/tests/hana/test_simulation_techmap_inv_test.v b/tests/hana/test_simulation_techmap_inv_test.v
new file mode 100644 (file)
index 0000000..81759c2
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input in, output out);
+assign out = ~in;
+endmodule
diff --git a/tests/hana/test_simulation_techmap_mux_0_test.v b/tests/hana/test_simulation_techmap_mux_0_test.v
new file mode 100644 (file)
index 0000000..bc676c7
--- /dev/null
@@ -0,0 +1,8 @@
+module test(input [1:0] in, input select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+       endcase
+endmodule      
diff --git a/tests/hana/test_simulation_techmap_mux_128_test.v b/tests/hana/test_simulation_techmap_mux_128_test.v
new file mode 100644 (file)
index 0000000..544c016
--- /dev/null
@@ -0,0 +1,134 @@
+module test(input [127:0] in, input [6:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+           4: out = in[4];
+           5: out = in[5];
+           6: out = in[6];
+           7: out = in[7];
+           8: out = in[8];
+           9: out = in[9];
+           10: out = in[10];
+           11: out = in[11];
+           12: out = in[12];
+           13: out = in[13];
+           14: out = in[14];
+           15: out = in[15];
+           16: out = in[16];
+           17: out = in[17];
+           18: out = in[18];
+           19: out = in[19];
+           20: out = in[20];
+           21: out = in[21];
+           22: out = in[22];
+           23: out = in[23];
+           24: out = in[24];
+           25: out = in[25];
+           26: out = in[26];
+           27: out = in[27];
+           28: out = in[28];
+           29: out = in[29];
+           30: out = in[30];
+           31: out = in[31];
+           32: out = in[32];
+           33: out = in[33];
+           34: out = in[34];
+           35: out = in[35];
+           36: out = in[36];
+           37: out = in[37];
+           38: out = in[38];
+           39: out = in[39];
+           40: out = in[40];
+           41: out = in[41];
+           42: out = in[42];
+           43: out = in[43];
+           44: out = in[44];
+           45: out = in[45];
+           46: out = in[46];
+           47: out = in[47];
+           48: out = in[48];
+           49: out = in[49];
+           50: out = in[50];
+           51: out = in[51];
+           52: out = in[52];
+           53: out = in[53];
+           54: out = in[54];
+           55: out = in[55];
+           56: out = in[56];
+           57: out = in[57];
+           58: out = in[58];
+           59: out = in[59];
+           60: out = in[60];
+           61: out = in[61];
+           62: out = in[62];
+           63: out = in[63];
+           64: out = in[64];
+           65: out = in[65];
+           66: out = in[66];
+           67: out = in[67];
+           68: out = in[68];
+           69: out = in[69];
+           70: out = in[70];
+           71: out = in[71];
+           72: out = in[72];
+           73: out = in[73];
+           74: out = in[74];
+           75: out = in[75];
+           76: out = in[76];
+           77: out = in[77];
+           78: out = in[78];
+           79: out = in[79];
+           80: out = in[80];
+           81: out = in[81];
+           82: out = in[82];
+           83: out = in[83];
+           84: out = in[84];
+           85: out = in[85];
+           86: out = in[86];
+           87: out = in[87];
+           88: out = in[88];
+           89: out = in[89];
+           90: out = in[90];
+           91: out = in[91];
+           92: out = in[92];
+           93: out = in[93];
+           94: out = in[94];
+           95: out = in[95];
+           96: out = in[96];
+           97: out = in[97];
+           98: out = in[98];
+           99: out = in[99];
+           100: out = in[100];
+           101: out = in[101];
+           102: out = in[102];
+           103: out = in[103];
+           104: out = in[104];
+           105: out = in[105];
+           106: out = in[106];
+           107: out = in[107];
+           108: out = in[108];
+           109: out = in[109];
+           110: out = in[110];
+           111: out = in[111];
+           112: out = in[112];
+           113: out = in[113];
+           114: out = in[114];
+           115: out = in[115];
+           116: out = in[116];
+           117: out = in[117];
+           118: out = in[118];
+           119: out = in[119];
+           120: out = in[120];
+           121: out = in[121];
+           122: out = in[122];
+           123: out = in[123];
+           124: out = in[124];
+           125: out = in[125];
+           126: out = in[126];
+           127: out = in[127];
+       endcase
+endmodule
diff --git a/tests/hana/test_simulation_techmap_mux_8_test.v b/tests/hana/test_simulation_techmap_mux_8_test.v
new file mode 100644 (file)
index 0000000..f53a2c5
--- /dev/null
@@ -0,0 +1,14 @@
+module test(input [7:0] in, input [2:0] select, output reg out);
+
+always @( in or select)
+    case (select)
+           0: out = in[0];
+           1: out = in[1];
+           2: out = in[2];
+           3: out = in[3];
+           4: out = in[4];
+           5: out = in[5];
+           6: out = in[6];
+           7: out = in[7];
+       endcase
+endmodule
diff --git a/tests/hana/test_simulation_techmap_nand_19_tech.v b/tests/hana/test_simulation_techmap_nand_19_tech.v
new file mode 100644 (file)
index 0000000..6a119e1
--- /dev/null
@@ -0,0 +1,11 @@
+module TECH_NAND18(input [17:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+module TECH_NAND4(input [3:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+module TECH_NAND2(input [1:0] in, output out);
+assign out = ~(&in);
+endmodule
diff --git a/tests/hana/test_simulation_techmap_nand_2_tech.v b/tests/hana/test_simulation_techmap_nand_2_tech.v
new file mode 100644 (file)
index 0000000..6a119e1
--- /dev/null
@@ -0,0 +1,11 @@
+module TECH_NAND18(input [17:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+module TECH_NAND4(input [3:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+module TECH_NAND2(input [1:0] in, output out);
+assign out = ~(&in);
+endmodule
diff --git a/tests/hana/test_simulation_techmap_nand_5_tech.v b/tests/hana/test_simulation_techmap_nand_5_tech.v
new file mode 100644 (file)
index 0000000..6a119e1
--- /dev/null
@@ -0,0 +1,11 @@
+module TECH_NAND18(input [17:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+module TECH_NAND4(input [3:0] in, output out);
+assign out = ~(&in);
+endmodule
+
+module TECH_NAND2(input [1:0] in, output out);
+assign out = ~(&in);
+endmodule
diff --git a/tests/hana/test_simulation_techmap_nor_19_tech.v b/tests/hana/test_simulation_techmap_nor_19_tech.v
new file mode 100644 (file)
index 0000000..89fb2c7
--- /dev/null
@@ -0,0 +1,11 @@
+module TECH_NOR18(input [17:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+module TECH_NOR4(input [3:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+module TECH_NOR2(input [1:0] in, output out);
+assign out = ~(|in);
+endmodule
diff --git a/tests/hana/test_simulation_techmap_nor_2_tech.v b/tests/hana/test_simulation_techmap_nor_2_tech.v
new file mode 100644 (file)
index 0000000..89fb2c7
--- /dev/null
@@ -0,0 +1,11 @@
+module TECH_NOR18(input [17:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+module TECH_NOR4(input [3:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+module TECH_NOR2(input [1:0] in, output out);
+assign out = ~(|in);
+endmodule
diff --git a/tests/hana/test_simulation_techmap_nor_5_tech.v b/tests/hana/test_simulation_techmap_nor_5_tech.v
new file mode 100644 (file)
index 0000000..89fb2c7
--- /dev/null
@@ -0,0 +1,11 @@
+module TECH_NOR18(input [17:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+module TECH_NOR4(input [3:0] in, output out);
+assign out = ~(|in);
+endmodule
+
+module TECH_NOR2(input [1:0] in, output out);
+assign out = ~(|in);
+endmodule
diff --git a/tests/hana/test_simulation_techmap_or_19_tech.v b/tests/hana/test_simulation_techmap_or_19_tech.v
new file mode 100644 (file)
index 0000000..745d7b7
--- /dev/null
@@ -0,0 +1,7 @@
+module TECH_OR18(input [17:0] in, output out);
+assign out = |in;
+endmodule
+
+module TECH_OR4(input [3:0] in, output out);
+assign out = |in;
+endmodule
diff --git a/tests/hana/test_simulation_techmap_or_5_tech.v b/tests/hana/test_simulation_techmap_or_5_tech.v
new file mode 100644 (file)
index 0000000..05c38b6
--- /dev/null
@@ -0,0 +1,3 @@
+module TECH_OR5(input [4:0] in, output out);
+assign out = |in;
+endmodule
diff --git a/tests/hana/test_simulation_techmap_xnor_2_tech.v b/tests/hana/test_simulation_techmap_xnor_2_tech.v
new file mode 100644 (file)
index 0000000..4eb0568
--- /dev/null
@@ -0,0 +1,6 @@
+module TECH_XOR5(input [4:0] in, output out);
+assign out = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4];
+endmodule
+module TECH_XOR2(input [1:0] in, output out);
+assign out = in[0] ^ in[1];
+endmodule
diff --git a/tests/hana/test_simulation_techmap_xnor_5_tech.v b/tests/hana/test_simulation_techmap_xnor_5_tech.v
new file mode 100644 (file)
index 0000000..4eb0568
--- /dev/null
@@ -0,0 +1,6 @@
+module TECH_XOR5(input [4:0] in, output out);
+assign out = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4];
+endmodule
+module TECH_XOR2(input [1:0] in, output out);
+assign out = in[0] ^ in[1];
+endmodule
diff --git a/tests/hana/test_simulation_techmap_xor_19_tech.v b/tests/hana/test_simulation_techmap_xor_19_tech.v
new file mode 100644 (file)
index 0000000..2042a0a
--- /dev/null
@@ -0,0 +1,3 @@
+module TECH_XOR2(input [1:0] in, output out);
+assign out = in[0] ^ in[1];
+endmodule
diff --git a/tests/hana/test_simulation_techmap_xor_2_tech.v b/tests/hana/test_simulation_techmap_xor_2_tech.v
new file mode 100644 (file)
index 0000000..4eb0568
--- /dev/null
@@ -0,0 +1,6 @@
+module TECH_XOR5(input [4:0] in, output out);
+assign out = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4];
+endmodule
+module TECH_XOR2(input [1:0] in, output out);
+assign out = in[0] ^ in[1];
+endmodule
diff --git a/tests/hana/test_simulation_techmap_xor_5_tech.v b/tests/hana/test_simulation_techmap_xor_5_tech.v
new file mode 100644 (file)
index 0000000..4eb0568
--- /dev/null
@@ -0,0 +1,6 @@
+module TECH_XOR5(input [4:0] in, output out);
+assign out = in[0] ^ in[1] ^ in[2] ^ in[3] ^ in[4];
+endmodule
+module TECH_XOR2(input [1:0] in, output out);
+assign out = in[0] ^ in[1];
+endmodule
diff --git a/tests/hana/test_simulation_tribuf_2_test.v b/tests/hana/test_simulation_tribuf_2_test.v
new file mode 100644 (file)
index 0000000..1e82aaf
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [1:0] in, input enable, output [1:0] out);
+assign out = enable ? in : 2'bzz;
+endmodule
diff --git a/tests/hana/test_simulation_xnor_1_test.v b/tests/hana/test_simulation_xnor_1_test.v
new file mode 100644 (file)
index 0000000..adc6ae5
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [1:0] in, output out);
+assign out = ~(in[0] ^ in[1]);
+endmodule
diff --git a/tests/hana/test_simulation_xnor_2_test.v b/tests/hana/test_simulation_xnor_2_test.v
new file mode 100644 (file)
index 0000000..701bcc7
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [2:0] in, output out);
+assign out = ~(in[0] ^ in[1] ^ in[2]);
+endmodule
diff --git a/tests/hana/test_simulation_xnor_3_test.v b/tests/hana/test_simulation_xnor_3_test.v
new file mode 100644 (file)
index 0000000..a8c87cc
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [3:0] in, output out);
+assign out = ~(in[0] ^ in[1] ^ in[2] ^ in[3]);
+endmodule
diff --git a/tests/hana/test_simulation_xnor_4_test.v b/tests/hana/test_simulation_xnor_4_test.v
new file mode 100644 (file)
index 0000000..fa671ff
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [3:0] in, output out);
+xnor myxnor(out, in[0], in[1], in[2], in[3]);
+endmodule
diff --git a/tests/hana/test_simulation_xor_1_test.v b/tests/hana/test_simulation_xor_1_test.v
new file mode 100644 (file)
index 0000000..f6447f8
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [1:0] in, output out);
+assign out = (in[0] ^ in[1]);
+endmodule
diff --git a/tests/hana/test_simulation_xor_2_test.v b/tests/hana/test_simulation_xor_2_test.v
new file mode 100644 (file)
index 0000000..d94081d
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [2:0] in, output out);
+assign out = (in[0] ^ in[1] ^ in[2]);
+endmodule
diff --git a/tests/hana/test_simulation_xor_3_test.v b/tests/hana/test_simulation_xor_3_test.v
new file mode 100644 (file)
index 0000000..cfa1318
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [3:0] in, output out);
+assign out = (in[0] ^ in[1] ^ in[2] ^ in[3]);
+endmodule
diff --git a/tests/hana/test_simulation_xor_4_test.v b/tests/hana/test_simulation_xor_4_test.v
new file mode 100644 (file)
index 0000000..be6cab6
--- /dev/null
@@ -0,0 +1,3 @@
+module test(input [3:0] in, output out);
+xor myxor(out, in[0], in[1], in[2], in[3]);
+endmodule
diff --git a/tests/i2c_bench/i2c_master_bit_ctrl.v b/tests/i2c_bench/i2c_master_bit_ctrl.v
new file mode 100644 (file)
index 0000000..6594fd6
--- /dev/null
@@ -0,0 +1,576 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE rev.B2 compliant I2C Master bit-controller        ////
+////                                                             ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: i2c_master_bit_ctrl.v,v 1.14 2009-01-20 10:25:29 rherveille Exp $
+//
+//  $Date: 2009-01-20 10:25:29 $
+//  $Revision: 1.14 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: $
+//               Revision 1.14  2009/01/20 10:25:29  rherveille
+//               Added clock synchronization logic
+//               Fixed slave_wait signal
+//
+//               Revision 1.13  2009/01/19 20:29:26  rherveille
+//               Fixed synopsys miss spell (synopsis)
+//               Fixed cr[0] register width
+//               Fixed ! usage instead of ~
+//               Fixed bit controller parameter width to 18bits
+//
+//               Revision 1.12  2006/09/04 09:08:13  rherveille
+//               fixed short scl high pulse after clock stretch
+//               fixed slave model not returning correct '(n)ack' signal
+//
+//               Revision 1.11  2004/05/07 11:02:26  rherveille
+//               Fixed a bug where the core would signal an arbitration lost (AL bit set), when another master controls the bus and the other master generates a STOP bit.
+//
+//               Revision 1.10  2003/08/09 07:01:33  rherveille
+//               Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
+//               Fixed a potential bug in the byte controller's host-acknowledge generation.
+//
+//               Revision 1.9  2003/03/10 14:26:37  rherveille
+//               Fixed cmd_ack generation item (no bug).
+//
+//               Revision 1.8  2003/02/05 00:06:10  rherveille
+//               Fixed a bug where the core would trigger an erroneous 'arbitration lost' interrupt after being reset, when the reset pulse width < 3 clk cycles.
+//
+//               Revision 1.7  2002/12/26 16:05:12  rherveille
+//               Small code simplifications
+//
+//               Revision 1.6  2002/12/26 15:02:32  rherveille
+//               Core is now a Multimaster I2C controller
+//
+//               Revision 1.5  2002/11/30 22:24:40  rherveille
+//               Cleaned up code
+//
+//               Revision 1.4  2002/10/30 18:10:07  rherveille
+//               Fixed some reported minor start/stop generation timing issuess.
+//
+//               Revision 1.3  2002/06/15 07:37:03  rherveille
+//               Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment.
+//
+//               Revision 1.2  2001/11/05 11:59:25  rherveille
+//               Fixed wb_ack_o generation bug.
+//               Fixed bug in the byte_controller statemachine.
+//               Added headers.
+//
+
+//
+/////////////////////////////////////
+// Bit controller section
+/////////////////////////////////////
+//
+// Translate simple commands into SCL/SDA transitions
+// Each command has 5 states, A/B/C/D/idle
+//
+// start:      SCL     ~~~~~~~~~~\____
+//     SDA     ~~~~~~~~\______
+//              x | A | B | C | D | i
+//
+// repstart    SCL     ____/~~~~\___
+//     SDA     __/~~~\______
+//              x | A | B | C | D | i
+//
+// stop        SCL     ____/~~~~~~~~
+//     SDA     ==\____/~~~~~
+//              x | A | B | C | D | i
+//
+//- write      SCL     ____/~~~~\____
+//     SDA     ==X=========X=
+//              x | A | B | C | D | i
+//
+//- read       SCL     ____/~~~~\____
+//     SDA     XXXX=====XXXX
+//              x | A | B | C | D | i
+//
+
+// Timing:     Normal mode      Fast mode
+///////////////////////////////////////////////////////////////////////
+// Fscl        100KHz           400KHz
+// Th_scl      4.0us            0.6us   High period of SCL
+// Tl_scl      4.7us            1.3us   Low period of SCL
+// Tsu:sta     4.7us            0.6us   setup time for a repeated start condition
+// Tsu:sto     4.0us            0.6us   setup time for a stop conditon
+// Tbuf        4.7us            1.3us   Bus free time between a stop and start condition
+//
+
+// synopsys translate_off
+`include "timescale.v"
+// synopsys translate_on
+
+`include "i2c_master_defines.v"
+
+module i2c_master_bit_ctrl (
+    input             clk,      // system clock
+    input             rst,      // synchronous active high reset
+    input             nReset,   // asynchronous active low reset
+    input             ena,      // core enable signal
+
+    input      [15:0] clk_cnt,  // clock prescale value
+
+    input      [ 3:0] cmd,      // command (from byte controller)
+    output reg        cmd_ack,  // command complete acknowledge
+    output reg        busy,     // i2c bus busy
+    output reg        al,       // i2c bus arbitration lost
+
+    input             din,
+    output reg        dout,
+
+    input             scl_i,    // i2c clock line input
+    output            scl_o,    // i2c clock line output
+    output reg        scl_oen,  // i2c clock line output enable (active low)
+    input             sda_i,    // i2c data line input
+    output            sda_o,    // i2c data line output
+    output reg        sda_oen   // i2c data line output enable (active low)
+);
+
+
+    //
+    // variable declarations
+    //
+
+    reg [ 1:0] cSCL, cSDA;      // capture SCL and SDA
+    reg [ 2:0] fSCL, fSDA;      // SCL and SDA filter inputs
+    reg        sSCL, sSDA;      // filtered and synchronized SCL and SDA inputs
+    reg        dSCL, dSDA;      // delayed versions of sSCL and sSDA
+    reg        dscl_oen;        // delayed scl_oen
+    reg        sda_chk;         // check SDA output (Multi-master arbitration)
+    reg        clk_en;          // clock generation signals
+    reg        slave_wait;      // slave inserts wait states
+    reg [15:0] cnt;             // clock divider counter (synthesis)
+    reg [13:0] filter_cnt;      // clock divider for filter
+
+
+    // state machine variable
+    reg [17:0] c_state; // synopsys enum_state
+
+    //
+    // module body
+    //
+
+    // whenever the slave is not ready it can delay the cycle by pulling SCL low
+    // delay scl_oen
+    always @(posedge clk)
+      dscl_oen <= scl_oen;
+
+    // slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low
+    // slave_wait remains asserted until the slave releases SCL
+    always @(posedge clk or negedge nReset)
+      if (!nReset) slave_wait <= 1'b0;
+      else         slave_wait <= (scl_oen & ~dscl_oen & ~sSCL) | (slave_wait & ~sSCL);
+
+    // master drives SCL high, but another master pulls it low
+    // master start counting down its low cycle now (clock synchronization)
+    wire scl_sync   = dSCL & ~sSCL & scl_oen;
+
+
+    // generate clk enable signal
+    always @(posedge clk or negedge nReset)
+      if (~nReset)
+      begin
+          cnt    <= 16'h0;
+          clk_en <= 1'b1;
+      end
+      else if (rst || ~|cnt || !ena || scl_sync)
+      begin
+          cnt    <= clk_cnt;
+          clk_en <= 1'b1;
+      end
+      else if (slave_wait)
+      begin
+          cnt    <= cnt;
+          clk_en <= 1'b0;    
+      end
+      else
+      begin
+          cnt    <= cnt - 16'h1;
+          clk_en <= 1'b0;
+      end
+
+
+    // generate bus status controller
+
+    // capture SDA and SCL
+    // reduce metastability risk
+    always @(posedge clk or negedge nReset)
+      if (!nReset)
+      begin
+          cSCL <= 2'b00;
+          cSDA <= 2'b00;
+      end
+      else if (rst)
+      begin
+          cSCL <= 2'b00;
+          cSDA <= 2'b00;
+      end
+      else
+      begin
+          cSCL <= {cSCL[0],scl_i};
+          cSDA <= {cSDA[0],sda_i};
+      end
+
+
+    // filter SCL and SDA signals; (attempt to) remove glitches
+    always @(posedge clk or negedge nReset)
+      if      (!nReset     ) filter_cnt <= 14'h0;
+      else if (rst || !ena ) filter_cnt <= 14'h0;
+      else if (~|filter_cnt) filter_cnt <= clk_cnt[15:2]; //16x I2C bus frequency
+      else                   filter_cnt <= filter_cnt -1;
+
+
+    always @(posedge clk or negedge nReset)
+      if (!nReset)
+      begin
+          fSCL <= 3'b111;
+          fSDA <= 3'b111;
+      end
+      else if (rst)
+      begin
+          fSCL <= 3'b111;
+          fSDA <= 3'b111;
+      end
+      else if (~|filter_cnt)
+      begin
+          fSCL <= {fSCL[1:0],cSCL[1]};
+          fSDA <= {fSDA[1:0],cSDA[1]};
+      end
+
+
+    // generate filtered SCL and SDA signals
+    always @(posedge clk or negedge nReset)
+      if (~nReset)
+      begin
+          sSCL <= 1'b1;
+          sSDA <= 1'b1;
+
+          dSCL <= 1'b1;
+          dSDA <= 1'b1;
+      end
+      else if (rst)
+      begin
+          sSCL <= 1'b1;
+          sSDA <= 1'b1;
+
+          dSCL <= 1'b1;
+          dSDA <= 1'b1;
+      end
+      else
+      begin
+          sSCL <= &fSCL[2:1] | &fSCL[1:0] | (fSCL[2] & fSCL[0]);
+          sSDA <= &fSDA[2:1] | &fSDA[1:0] | (fSDA[2] & fSDA[0]);
+
+          dSCL <= sSCL;
+          dSDA <= sSDA;
+      end
+
+    // detect start condition => detect falling edge on SDA while SCL is high
+    // detect stop condition => detect rising edge on SDA while SCL is high
+    reg sta_condition;
+    reg sto_condition;
+    always @(posedge clk or negedge nReset)
+      if (~nReset)
+      begin
+          sta_condition <= 1'b0;
+          sto_condition <= 1'b0;
+      end
+      else if (rst)
+      begin
+          sta_condition <= 1'b0;
+          sto_condition <= 1'b0;
+      end
+      else
+      begin
+          sta_condition <= ~sSDA &  dSDA & sSCL;
+          sto_condition <=  sSDA & ~dSDA & sSCL;
+      end
+
+
+    // generate i2c bus busy signal
+    always @(posedge clk or negedge nReset)
+      if      (!nReset) busy <= 1'b0;
+      else if (rst    ) busy <= 1'b0;
+      else              busy <= (sta_condition | busy) & ~sto_condition;
+
+
+    // generate arbitration lost signal
+    // aribitration lost when:
+    // 1) master drives SDA high, but the i2c bus is low
+    // 2) stop detected while not requested
+    reg cmd_stop;
+    always @(posedge clk or negedge nReset)
+      if (~nReset)
+          cmd_stop <= 1'b0;
+      else if (rst)
+          cmd_stop <= 1'b0;
+      else if (clk_en)
+          cmd_stop <= cmd == `I2C_CMD_STOP;
+
+    always @(posedge clk or negedge nReset)
+      if (~nReset)
+          al <= 1'b0;
+      else if (rst)
+          al <= 1'b0;
+      else
+          al <= (sda_chk & ~sSDA & sda_oen) | (|c_state & sto_condition & ~cmd_stop);
+
+
+    // generate dout signal (store SDA on rising edge of SCL)
+    always @(posedge clk)
+      if (sSCL & ~dSCL) dout <= sSDA;
+
+
+    // generate statemachine
+
+    // nxt_state decoder
+    parameter [17:0] idle    = 18'b0_0000_0000_0000_0000;
+    parameter [17:0] start_a = 18'b0_0000_0000_0000_0001;
+    parameter [17:0] start_b = 18'b0_0000_0000_0000_0010;
+    parameter [17:0] start_c = 18'b0_0000_0000_0000_0100;
+    parameter [17:0] start_d = 18'b0_0000_0000_0000_1000;
+    parameter [17:0] start_e = 18'b0_0000_0000_0001_0000;
+    parameter [17:0] stop_a  = 18'b0_0000_0000_0010_0000;
+    parameter [17:0] stop_b  = 18'b0_0000_0000_0100_0000;
+    parameter [17:0] stop_c  = 18'b0_0000_0000_1000_0000;
+    parameter [17:0] stop_d  = 18'b0_0000_0001_0000_0000;
+    parameter [17:0] rd_a    = 18'b0_0000_0010_0000_0000;
+    parameter [17:0] rd_b    = 18'b0_0000_0100_0000_0000;
+    parameter [17:0] rd_c    = 18'b0_0000_1000_0000_0000;
+    parameter [17:0] rd_d    = 18'b0_0001_0000_0000_0000;
+    parameter [17:0] wr_a    = 18'b0_0010_0000_0000_0000;
+    parameter [17:0] wr_b    = 18'b0_0100_0000_0000_0000;
+    parameter [17:0] wr_c    = 18'b0_1000_0000_0000_0000;
+    parameter [17:0] wr_d    = 18'b1_0000_0000_0000_0000;
+
+    always @(posedge clk or negedge nReset)
+      if (!nReset)
+      begin
+          c_state <= idle;
+          cmd_ack <= 1'b0;
+          scl_oen <= 1'b1;
+          sda_oen <= 1'b1;
+          sda_chk <= 1'b0;
+      end
+      else if (rst | al)
+      begin
+          c_state <= idle;
+          cmd_ack <= 1'b0;
+          scl_oen <= 1'b1;
+          sda_oen <= 1'b1;
+          sda_chk <= 1'b0;
+      end
+      else
+      begin
+          cmd_ack   <= 1'b0; // default no command acknowledge + assert cmd_ack only 1clk cycle
+
+          if (clk_en)
+              case (c_state) // synopsys full_case parallel_case
+                    // idle state
+                    idle:
+                    begin
+                        case (cmd) // synopsys full_case parallel_case
+                             `I2C_CMD_START: c_state <= start_a;
+                             `I2C_CMD_STOP:  c_state <= stop_a;
+                             `I2C_CMD_WRITE: c_state <= wr_a;
+                             `I2C_CMD_READ:  c_state <= rd_a;
+                             default:        c_state <= idle;
+                        endcase
+
+                        scl_oen <= scl_oen; // keep SCL in same state
+                        sda_oen <= sda_oen; // keep SDA in same state
+                        sda_chk <= 1'b0;    // don't check SDA output
+                    end
+
+                    // start
+                    start_a:
+                    begin
+                        c_state <= start_b;
+                        scl_oen <= scl_oen; // keep SCL in same state
+                        sda_oen <= 1'b1;    // set SDA high
+                        sda_chk <= 1'b0;    // don't check SDA output
+                    end
+
+                    start_b:
+                    begin
+                        c_state <= start_c;
+                        scl_oen <= 1'b1; // set SCL high
+                        sda_oen <= 1'b1; // keep SDA high
+                        sda_chk <= 1'b0; // don't check SDA output
+                    end
+
+                    start_c:
+                    begin
+                        c_state <= start_d;
+                        scl_oen <= 1'b1; // keep SCL high
+                        sda_oen <= 1'b0; // set SDA low
+                        sda_chk <= 1'b0; // don't check SDA output
+                    end
+
+                    start_d:
+                    begin
+                        c_state <= start_e;
+                        scl_oen <= 1'b1; // keep SCL high
+                        sda_oen <= 1'b0; // keep SDA low
+                        sda_chk <= 1'b0; // don't check SDA output
+                    end
+
+                    start_e:
+                    begin
+                        c_state <= idle;
+                        cmd_ack <= 1'b1;
+                        scl_oen <= 1'b0; // set SCL low
+                        sda_oen <= 1'b0; // keep SDA low
+                        sda_chk <= 1'b0; // don't check SDA output
+                    end
+
+                    // stop
+                    stop_a:
+                    begin
+                        c_state <= stop_b;
+                        scl_oen <= 1'b0; // keep SCL low
+                        sda_oen <= 1'b0; // set SDA low
+                        sda_chk <= 1'b0; // don't check SDA output
+                    end
+
+                    stop_b:
+                    begin
+                        c_state <= stop_c;
+                        scl_oen <= 1'b1; // set SCL high
+                        sda_oen <= 1'b0; // keep SDA low
+                        sda_chk <= 1'b0; // don't check SDA output
+                    end
+
+                    stop_c:
+                    begin
+                        c_state <= stop_d;
+                        scl_oen <= 1'b1; // keep SCL high
+                        sda_oen <= 1'b0; // keep SDA low
+                        sda_chk <= 1'b0; // don't check SDA output
+                    end
+
+                    stop_d:
+                    begin
+                        c_state <= idle;
+                        cmd_ack <= 1'b1;
+                        scl_oen <= 1'b1; // keep SCL high
+                        sda_oen <= 1'b1; // set SDA high
+                        sda_chk <= 1'b0; // don't check SDA output
+                    end
+
+                    // read
+                    rd_a:
+                    begin
+                        c_state <= rd_b;
+                        scl_oen <= 1'b0; // keep SCL low
+                        sda_oen <= 1'b1; // tri-state SDA
+                        sda_chk <= 1'b0; // don't check SDA output
+                    end
+
+                    rd_b:
+                    begin
+                        c_state <= rd_c;
+                        scl_oen <= 1'b1; // set SCL high
+                        sda_oen <= 1'b1; // keep SDA tri-stated
+                        sda_chk <= 1'b0; // don't check SDA output
+                    end
+
+                    rd_c:
+                    begin
+                        c_state <= rd_d;
+                        scl_oen <= 1'b1; // keep SCL high
+                        sda_oen <= 1'b1; // keep SDA tri-stated
+                        sda_chk <= 1'b0; // don't check SDA output
+                    end
+
+                    rd_d:
+                    begin
+                        c_state <= idle;
+                        cmd_ack <= 1'b1;
+                        scl_oen <= 1'b0; // set SCL low
+                        sda_oen <= 1'b1; // keep SDA tri-stated
+                        sda_chk <= 1'b0; // don't check SDA output
+                    end
+
+                    // write
+                    wr_a:
+                    begin
+                        c_state <= wr_b;
+                        scl_oen <= 1'b0; // keep SCL low
+                        sda_oen <= din;  // set SDA
+                        sda_chk <= 1'b0; // don't check SDA output (SCL low)
+                    end
+
+                    wr_b:
+                    begin
+                        c_state <= wr_c;
+                        scl_oen <= 1'b1; // set SCL high
+                        sda_oen <= din;  // keep SDA
+                        sda_chk <= 1'b0; // don't check SDA output yet
+                                            // allow some time for SDA and SCL to settle
+                    end
+
+                    wr_c:
+                    begin
+                        c_state <= wr_d;
+                        scl_oen <= 1'b1; // keep SCL high
+                        sda_oen <= din;
+                        sda_chk <= 1'b1; // check SDA output
+                    end
+
+                    wr_d:
+                    begin
+                        c_state <= idle;
+                        cmd_ack <= 1'b1;
+                        scl_oen <= 1'b0; // set SCL low
+                        sda_oen <= din;
+                        sda_chk <= 1'b0; // don't check SDA output (SCL low)
+                    end
+
+              endcase
+      end
+
+
+    // assign scl and sda output (always gnd)
+    assign scl_o = 1'b0;
+    assign sda_o = 1'b0;
+
+endmodule
diff --git a/tests/i2c_bench/i2c_master_byte_ctrl.v b/tests/i2c_bench/i2c_master_byte_ctrl.v
new file mode 100644 (file)
index 0000000..513953a
--- /dev/null
@@ -0,0 +1,344 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE rev.B2 compliant I2C Master byte-controller       ////
+////                                                             ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: i2c_master_byte_ctrl.v,v 1.8 2009-01-19 20:29:26 rherveille Exp $
+//
+//  $Date: 2009-01-19 20:29:26 $
+//  $Revision: 1.8 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: not supported by cvs2svn $
+//               Revision 1.7  2004/02/18 11:40:46  rherveille
+//               Fixed a potential bug in the statemachine. During a 'stop' 2 cmd_ack signals were generated. Possibly canceling a new start command.
+//
+//               Revision 1.6  2003/08/09 07:01:33  rherveille
+//               Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
+//               Fixed a potential bug in the byte controller's host-acknowledge generation.
+//
+//               Revision 1.5  2002/12/26 15:02:32  rherveille
+//               Core is now a Multimaster I2C controller
+//
+//               Revision 1.4  2002/11/30 22:24:40  rherveille
+//               Cleaned up code
+//
+//               Revision 1.3  2001/11/05 11:59:25  rherveille
+//               Fixed wb_ack_o generation bug.
+//               Fixed bug in the byte_controller statemachine.
+//               Added headers.
+//
+
+// synopsys translate_off
+`include "timescale.v"
+// synopsys translate_on
+
+`include "i2c_master_defines.v"
+
+module i2c_master_byte_ctrl (
+       clk, rst, nReset, ena, clk_cnt, start, stop, read, write, ack_in, din,
+       cmd_ack, ack_out, dout, i2c_busy, i2c_al, scl_i, scl_o, scl_oen, sda_i, sda_o, sda_oen );
+
+       //
+       // inputs & outputs
+       //
+       input clk;     // master clock
+       input rst;     // synchronous active high reset
+       input nReset;  // asynchronous active low reset
+       input ena;     // core enable signal
+
+       input [15:0] clk_cnt; // 4x SCL
+
+       // control inputs
+       input       start;
+       input       stop;
+       input       read;
+       input       write;
+       input       ack_in;
+       input [7:0] din;
+
+       // status outputs
+       output       cmd_ack;
+       reg cmd_ack;
+       output       ack_out;
+       reg ack_out;
+       output       i2c_busy;
+       output       i2c_al;
+       output [7:0] dout;
+
+       // I2C signals
+       input  scl_i;
+       output scl_o;
+       output scl_oen;
+       input  sda_i;
+       output sda_o;
+       output sda_oen;
+
+
+       //
+       // Variable declarations
+       //
+
+       // statemachine
+       parameter [4:0] ST_IDLE  = 5'b0_0000;
+       parameter [4:0] ST_START = 5'b0_0001;
+       parameter [4:0] ST_READ  = 5'b0_0010;
+       parameter [4:0] ST_WRITE = 5'b0_0100;
+       parameter [4:0] ST_ACK   = 5'b0_1000;
+       parameter [4:0] ST_STOP  = 5'b1_0000;
+
+       // signals for bit_controller
+       reg  [3:0] core_cmd;
+       reg        core_txd;
+       wire       core_ack, core_rxd;
+
+       // signals for shift register
+       reg [7:0] sr; //8bit shift register
+       reg       shift, ld;
+
+       // signals for state machine
+       wire       go;
+       reg  [2:0] dcnt;
+       wire       cnt_done;
+
+       //
+       // Module body
+       //
+
+       // hookup bit_controller
+       i2c_master_bit_ctrl bit_controller (
+               .clk     ( clk      ),
+               .rst     ( rst      ),
+               .nReset  ( nReset   ),
+               .ena     ( ena      ),
+               .clk_cnt ( clk_cnt  ),
+               .cmd     ( core_cmd ),
+               .cmd_ack ( core_ack ),
+               .busy    ( i2c_busy ),
+               .al      ( i2c_al   ),
+               .din     ( core_txd ),
+               .dout    ( core_rxd ),
+               .scl_i   ( scl_i    ),
+               .scl_o   ( scl_o    ),
+               .scl_oen ( scl_oen  ),
+               .sda_i   ( sda_i    ),
+               .sda_o   ( sda_o    ),
+               .sda_oen ( sda_oen  )
+       );
+
+       // generate go-signal
+       assign go = (read | write | stop) & ~cmd_ack;
+
+       // assign dout output to shift-register
+       assign dout = sr;
+
+       // generate shift register
+       always @(posedge clk or negedge nReset)
+         if (!nReset)
+           sr <= 8'h0;
+         else if (rst)
+           sr <= 8'h0;
+         else if (ld)
+           sr <= din;
+         else if (shift)
+           sr <= {sr[6:0], core_rxd};
+
+       // generate counter
+       always @(posedge clk or negedge nReset)
+         if (!nReset)
+           dcnt <= 3'h0;
+         else if (rst)
+           dcnt <= 3'h0;
+         else if (ld)
+           dcnt <= 3'h7;
+         else if (shift)
+           dcnt <= dcnt - 3'h1;
+
+       assign cnt_done = ~(|dcnt);
+
+       //
+       // state machine
+       //
+       reg [4:0] c_state; // synopsys enum_state
+
+       always @(posedge clk or negedge nReset)
+         if (!nReset)
+           begin
+               core_cmd <= `I2C_CMD_NOP;
+               core_txd <= 1'b0;
+               shift    <= 1'b0;
+               ld       <= 1'b0;
+               cmd_ack  <= 1'b0;
+               c_state  <= ST_IDLE;
+               ack_out  <= 1'b0;
+           end
+         else if (rst | i2c_al)
+          begin
+              core_cmd <= `I2C_CMD_NOP;
+              core_txd <= 1'b0;
+              shift    <= 1'b0;
+              ld       <= 1'b0;
+              cmd_ack  <= 1'b0;
+              c_state  <= ST_IDLE;
+              ack_out  <= 1'b0;
+          end
+       else
+         begin
+             // initially reset all signals
+             core_txd <= sr[7];
+             shift    <= 1'b0;
+             ld       <= 1'b0;
+             cmd_ack  <= 1'b0;
+
+             case (c_state) // synopsys full_case parallel_case
+               ST_IDLE:
+                 if (go)
+                   begin
+                       if (start)
+                         begin
+                             c_state  <= ST_START;
+                             core_cmd <= `I2C_CMD_START;
+                         end
+                       else if (read)
+                         begin
+                             c_state  <= ST_READ;
+                             core_cmd <= `I2C_CMD_READ;
+                         end
+                       else if (write)
+                         begin
+                             c_state  <= ST_WRITE;
+                             core_cmd <= `I2C_CMD_WRITE;
+                         end
+                       else // stop
+                         begin
+                             c_state  <= ST_STOP;
+                             core_cmd <= `I2C_CMD_STOP;
+                         end
+
+                       ld <= 1'b1;
+                   end
+
+               ST_START:
+                 if (core_ack)
+                   begin
+                       if (read)
+                         begin
+                             c_state  <= ST_READ;
+                             core_cmd <= `I2C_CMD_READ;
+                         end
+                       else
+                         begin
+                             c_state  <= ST_WRITE;
+                             core_cmd <= `I2C_CMD_WRITE;
+                         end
+
+                       ld <= 1'b1;
+                   end
+
+               ST_WRITE:
+                 if (core_ack)
+                   if (cnt_done)
+                     begin
+                         c_state  <= ST_ACK;
+                         core_cmd <= `I2C_CMD_READ;
+                     end
+                   else
+                     begin
+                         c_state  <= ST_WRITE;       // stay in same state
+                         core_cmd <= `I2C_CMD_WRITE; // write next bit
+                         shift    <= 1'b1;
+                     end
+
+               ST_READ:
+                 if (core_ack)
+                   begin
+                       if (cnt_done)
+                         begin
+                             c_state  <= ST_ACK;
+                             core_cmd <= `I2C_CMD_WRITE;
+                         end
+                       else
+                         begin
+                             c_state  <= ST_READ;       // stay in same state
+                             core_cmd <= `I2C_CMD_READ; // read next bit
+                         end
+
+                       shift    <= 1'b1;
+                       core_txd <= ack_in;
+                   end
+
+               ST_ACK:
+                 if (core_ack)
+                   begin
+                      if (stop)
+                        begin
+                            c_state  <= ST_STOP;
+                            core_cmd <= `I2C_CMD_STOP;
+                        end
+                      else
+                        begin
+                            c_state  <= ST_IDLE;
+                            core_cmd <= `I2C_CMD_NOP;
+
+                            // generate command acknowledge signal
+                            cmd_ack  <= 1'b1;
+                        end
+
+                        // assign ack_out output to bit_controller_rxd (contains last received bit)
+                        ack_out <= core_rxd;
+
+                        core_txd <= 1'b1;
+                    end
+                  else
+                    core_txd <= ack_in;
+
+               ST_STOP:
+                 if (core_ack)
+                   begin
+                       c_state  <= ST_IDLE;
+                       core_cmd <= `I2C_CMD_NOP;
+
+                       // generate command acknowledge signal
+                       cmd_ack  <= 1'b1;
+                   end
+
+             endcase
+         end
+endmodule
diff --git a/tests/i2c_bench/i2c_master_defines.v b/tests/i2c_bench/i2c_master_defines.v
new file mode 100644 (file)
index 0000000..e81c546
--- /dev/null
@@ -0,0 +1,59 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE rev.B2 compliant I2C Master controller defines    ////
+////                                                             ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: i2c_master_defines.v,v 1.3 2001-11-05 11:59:25 rherveille Exp $
+//
+//  $Date: 2001-11-05 11:59:25 $
+//  $Revision: 1.3 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: not supported by cvs2svn $
+
+
+// I2C registers wishbone addresses
+
+// bitcontroller states
+`define I2C_CMD_NOP   4'b0000
+`define I2C_CMD_START 4'b0001
+`define I2C_CMD_STOP  4'b0010
+`define I2C_CMD_WRITE 4'b0100
+`define I2C_CMD_READ  4'b1000
diff --git a/tests/i2c_bench/i2c_master_top.v b/tests/i2c_bench/i2c_master_top.v
new file mode 100644 (file)
index 0000000..5e9cde7
--- /dev/null
@@ -0,0 +1,301 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE revB.2 compliant I2C Master controller Top-level  ////
+////                                                             ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: i2c_master_top.v,v 1.12 2009-01-19 20:29:26 rherveille Exp $
+//
+//  $Date: 2009-01-19 20:29:26 $
+//  $Revision: 1.12 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               Revision 1.11  2005/02/27 09:26:24  rherveille
+//               Fixed register overwrite issue.
+//               Removed full_case pragma, replaced it by a default statement.
+//
+//               Revision 1.10  2003/09/01 10:34:38  rherveille
+//               Fix a blocking vs. non-blocking error in the wb_dat output mux.
+//
+//               Revision 1.9  2003/01/09 16:44:45  rherveille
+//               Fixed a bug in the Command Register declaration.
+//
+//               Revision 1.8  2002/12/26 16:05:12  rherveille
+//               Small code simplifications
+//
+//               Revision 1.7  2002/12/26 15:02:32  rherveille
+//               Core is now a Multimaster I2C controller
+//
+//               Revision 1.6  2002/11/30 22:24:40  rherveille
+//               Cleaned up code
+//
+//               Revision 1.5  2001/11/10 10:52:55  rherveille
+//               Changed PRER reset value from 0x0000 to 0xffff, conform specs.
+//
+
+// synopsys translate_off
+`include "timescale.v"
+// synopsys translate_on
+
+`include "i2c_master_defines.v"
+
+module i2c_master_top(
+       wb_clk_i, wb_rst_i, arst_i, wb_adr_i, wb_dat_i, wb_dat_o,
+       wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_inta_o,
+       scl_pad_i, scl_pad_o, scl_padoen_o, sda_pad_i, sda_pad_o, sda_padoen_o );
+
+       // parameters
+       parameter ARST_LVL = 1'b0; // asynchronous reset level
+
+       //
+       // inputs & outputs
+       //
+
+       // wishbone signals
+       input        wb_clk_i;     // master clock input
+       input        wb_rst_i;     // synchronous active high reset
+       input        arst_i;       // asynchronous reset
+       input  [2:0] wb_adr_i;     // lower address bits
+       input  [7:0] wb_dat_i;     // databus input
+       output [7:0] wb_dat_o;     // databus output
+       input        wb_we_i;      // write enable input
+       input        wb_stb_i;     // stobe/core select signal
+       input        wb_cyc_i;     // valid bus cycle input
+       output       wb_ack_o;     // bus cycle acknowledge output
+       output       wb_inta_o;    // interrupt request signal output
+
+       reg [7:0] wb_dat_o;
+       reg wb_ack_o;
+       reg wb_inta_o;
+
+       // I2C signals
+       // i2c clock line
+       input  scl_pad_i;       // SCL-line input
+       output scl_pad_o;       // SCL-line output (always 1'b0)
+       output scl_padoen_o;    // SCL-line output enable (active low)
+
+       // i2c data line
+       input  sda_pad_i;       // SDA-line input
+       output sda_pad_o;       // SDA-line output (always 1'b0)
+       output sda_padoen_o;    // SDA-line output enable (active low)
+
+
+       //
+       // variable declarations
+       //
+
+       // registers
+       reg  [15:0] prer; // clock prescale register
+       reg  [ 7:0] ctr;  // control register
+       reg  [ 7:0] txr;  // transmit register
+       wire [ 7:0] rxr;  // receive register
+       reg  [ 7:0] cr;   // command register
+       wire [ 7:0] sr;   // status register
+
+       // done signal: command completed, clear command register
+       wire done;
+
+       // core enable signal
+       wire core_en;
+       wire ien;
+
+       // status register signals
+       wire irxack;
+       reg  rxack;       // received aknowledge from slave
+       reg  tip;         // transfer in progress
+       reg  irq_flag;    // interrupt pending flag
+       wire i2c_busy;    // bus busy (start signal detected)
+       wire i2c_al;      // i2c bus arbitration lost
+       reg  al;          // status register arbitration lost bit
+
+       //
+       // module body
+       //
+
+       // generate internal reset
+       wire rst_i = arst_i ^ ARST_LVL;
+
+       // generate wishbone signals
+       wire wb_wacc = wb_we_i & wb_ack_o;
+
+       // generate acknowledge output signal
+       always @(posedge wb_clk_i)
+         wb_ack_o <= wb_cyc_i & wb_stb_i & ~wb_ack_o; // because timing is always honored
+
+       // assign DAT_O
+       always @(posedge wb_clk_i)
+       begin
+         case (wb_adr_i) // synopsys parallel_case
+           3'b000: wb_dat_o <= prer[ 7:0];
+           3'b001: wb_dat_o <= prer[15:8];
+           3'b010: wb_dat_o <= ctr;
+           3'b011: wb_dat_o <= rxr; // write is transmit register (txr)
+           3'b100: wb_dat_o <= sr;  // write is command register (cr)
+           3'b101: wb_dat_o <= txr;
+           3'b110: wb_dat_o <= cr;
+           3'b111: wb_dat_o <= 0;   // reserved
+           default: wb_dat_o <= 16'bx;
+         endcase
+       end
+
+       // generate registers
+       always @(posedge wb_clk_i or negedge rst_i)
+         if (!rst_i)
+           begin
+               prer <= 16'hffff;
+               ctr  <=  8'h0;
+               txr  <=  8'h0;
+           end
+         else if (wb_rst_i)
+           begin
+               prer <= 16'hffff;
+               ctr  <=  8'h0;
+               txr  <=  8'h0;
+           end
+         else
+           if (wb_wacc)
+             case (wb_adr_i) // synopsys parallel_case
+                3'b000 : prer [ 7:0] <= wb_dat_i;
+                3'b001 : prer [15:8] <= wb_dat_i;
+                3'b010 : ctr         <= wb_dat_i;
+                3'b011 : txr         <= wb_dat_i;
+                default: ;
+             endcase
+
+       // generate command register (special case)
+       always @(posedge wb_clk_i or negedge rst_i)
+         if (!rst_i)
+           cr <= 8'h0;
+         else if (wb_rst_i)
+           cr <= 8'h0;
+         else if (wb_wacc)
+           begin
+               if (core_en & (wb_adr_i == 3'b100) )
+                 cr <= wb_dat_i;
+           end
+         else
+           begin
+               if (done | i2c_al)
+                 cr[7:4] <= 4'h0;           // clear command bits when done
+                                               // or when aribitration lost
+               cr[2:1] <= 2'b0;             // reserved bits
+               cr[0]   <= 1'b0;             // clear IRQ_ACK bit
+           end
+
+
+       // decode command register
+       wire sta  = cr[7];
+       wire sto  = cr[6];
+       wire rd   = cr[5];
+       wire wr   = cr[4];
+       wire ack  = cr[3];
+       wire iack = cr[0];
+
+       // decode control register
+       assign core_en = ctr[7];
+       assign ien = ctr[6];
+
+       // hookup byte controller block
+       i2c_master_byte_ctrl byte_controller (
+               .clk      ( wb_clk_i     ),
+               .rst      ( wb_rst_i     ),
+               .nReset   ( rst_i        ),
+               .ena      ( core_en      ),
+               .clk_cnt  ( prer         ),
+               .start    ( sta          ),
+               .stop     ( sto          ),
+               .read     ( rd           ),
+               .write    ( wr           ),
+               .ack_in   ( ack          ),
+               .din      ( txr          ),
+               .cmd_ack  ( done         ),
+               .ack_out  ( irxack       ),
+               .dout     ( rxr          ),
+               .i2c_busy ( i2c_busy     ),
+               .i2c_al   ( i2c_al       ),
+               .scl_i    ( scl_pad_i    ),
+               .scl_o    ( scl_pad_o    ),
+               .scl_oen  ( scl_padoen_o ),
+               .sda_i    ( sda_pad_i    ),
+               .sda_o    ( sda_pad_o    ),
+               .sda_oen  ( sda_padoen_o )
+       );
+
+       // status register block + interrupt request signal
+       always @(posedge wb_clk_i or negedge rst_i)
+         if (!rst_i)
+           begin
+               al       <= 1'b0;
+               rxack    <= 1'b0;
+               tip      <= 1'b0;
+               irq_flag <= 1'b0;
+           end
+         else if (wb_rst_i)
+           begin
+               al       <= 1'b0;
+               rxack    <= 1'b0;
+               tip      <= 1'b0;
+               irq_flag <= 1'b0;
+           end
+         else
+           begin
+               al       <= i2c_al | (al & ~sta);
+               rxack    <= irxack;
+               tip      <= (rd | wr);
+               irq_flag <= (done | i2c_al | irq_flag) & ~iack; // interrupt request flag is always generated
+           end
+
+       // generate interrupt request signals
+       always @(posedge wb_clk_i or negedge rst_i)
+         if (!rst_i)
+           wb_inta_o <= 1'b0;
+         else if (wb_rst_i)
+           wb_inta_o <= 1'b0;
+         else
+           wb_inta_o <= irq_flag && ien; // interrupt signal is only generated when IEN (interrupt enable bit is set)
+
+       // assign status register bits
+       assign sr[7]   = rxack;
+       assign sr[6]   = i2c_busy;
+       assign sr[5]   = al;
+       assign sr[4:2] = 3'h0; // reserved
+       assign sr[1]   = tip;
+       assign sr[0]   = irq_flag;
+
+endmodule
diff --git a/tests/i2c_bench/i2c_slave_model.v b/tests/i2c_bench/i2c_slave_model.v
new file mode 100644 (file)
index 0000000..02b7572
--- /dev/null
@@ -0,0 +1,361 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE rev.B2 compliant synthesizable I2C Slave model    ////
+////                                                             ////
+////                                                             ////
+////  Authors: Richard Herveille (richard@asics.ws) www.asics.ws ////
+////           John Sheahan (jrsheahan@optushome.com.au)         ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001,2002 Richard Herveille                   ////
+////                         richard@asics.ws                    ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: i2c_slave_model.v,v 1.7 2006-09-04 09:08:51 rherveille Exp $
+//
+//  $Date: 2006-09-04 09:08:51 $
+//  $Revision: 1.7 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: not supported by cvs2svn $
+//               Revision 1.6  2005/02/28 11:33:48  rherveille
+//               Fixed Tsu:sta timing check.
+//               Added Thd:sta timing check.
+//
+//               Revision 1.5  2003/12/05 11:05:19  rherveille
+//               Fixed slave address MSB='1' bug
+//
+//               Revision 1.4  2003/09/11 08:25:37  rherveille
+//               Fixed a bug in the timing section. Changed 'tst_scl' into 'tst_sto'.
+//
+//               Revision 1.3  2002/10/30 18:11:06  rherveille
+//               Added timing tests to i2c_model.
+//               Updated testbench.
+//
+//               Revision 1.2  2002/03/17 10:26:38  rherveille
+//               Fixed some race conditions in the i2c-slave model.
+//               Added debug information.
+//               Added headers.
+//
+
+`include "timescale.v"
+
+module i2c_slave_model (scl, sda);
+
+       //
+       // parameters
+       //
+       parameter I2C_ADR = 7'b001_0000;
+
+       //
+       // input && outpus
+       //
+       input scl;
+       inout sda;
+
+       //
+       // Variable declaration
+       //
+       wire debug = 1'b1;
+
+       reg [7:0] mem [3:0]; // initiate memory
+       reg [7:0] mem_adr;   // memory address
+       reg [7:0] mem_do;    // memory data output
+
+       reg sta, d_sta;
+       reg sto, d_sto;
+
+       reg [7:0] sr;        // 8bit shift register
+       reg       rw;        // read/write direction
+
+       wire      my_adr;    // my address called ??
+       wire      i2c_reset; // i2c-statemachine reset
+       reg [2:0] bit_cnt;   // 3bit downcounter
+       wire      acc_done;  // 8bits transfered
+       reg       ld;        // load downcounter
+
+       reg       sda_o;     // sda-drive level
+       wire      sda_dly;   // delayed version of sda
+
+       // statemachine declaration
+       parameter idle        = 3'b000;
+       parameter slave_ack   = 3'b001;
+       parameter get_mem_adr = 3'b010;
+       parameter gma_ack     = 3'b011;
+       parameter data        = 3'b100;
+       parameter data_ack    = 3'b101;
+
+       reg [2:0] state; // synopsys enum_state
+
+       //
+       // module body
+       //
+
+       initial
+       begin
+          sda_o = 1'b1;
+          state = idle;
+          mem[0] = 0;
+          mem[1] = 0;
+          mem[2] = 0;
+          mem[3] = 0;
+       end
+
+       // generate shift register
+       always @(posedge scl)
+         sr <= #1 {sr[6:0],sda};
+
+       //detect my_address
+       assign my_adr = (sr[7:1] == I2C_ADR);
+       // FIXME: This should not be a generic assign, but rather
+       // qualified on address transfer phase and probably reset by stop
+
+       //generate bit-counter
+       always @(posedge scl)
+         if(ld)
+           bit_cnt <= #1 3'b111;
+         else
+           bit_cnt <= #1 bit_cnt - 3'h1;
+
+       //generate access done signal
+       assign acc_done = !(|bit_cnt);
+
+       // generate delayed version of sda
+       // this model assumes a hold time for sda after the falling edge of scl.
+       // According to the Phillips i2c spec, there s/b a 0 ns hold time for sda
+       // with regards to scl. If the data changes coincident with the clock, the
+       // acknowledge is missed
+       // Fix by Michael Sosnoski
+       assign #1 sda_dly = sda;
+
+
+       //detect start condition
+       always @(negedge sda)
+         if(scl)
+           begin
+               sta   <= #1 1'b1;
+               d_sta <= #1 1'b0;
+               sto   <= #1 1'b0;
+
+               if(debug)
+                 $display("DEBUG i2c_slave; start condition detected at %t", $time);
+           end
+         else
+           sta <= #1 1'b0;
+
+       always @(posedge scl)
+         d_sta <= #1 sta;
+
+       // detect stop condition
+       always @(posedge sda)
+         if(scl)
+           begin
+              sta <= #1 1'b0;
+              sto <= #1 1'b1;
+
+              if(debug)
+                $display("DEBUG i2c_slave; stop condition detected at %t", $time);
+           end
+         else
+           sto <= #1 1'b0;
+
+       //generate i2c_reset signal
+       assign i2c_reset = sta || sto;
+
+       // generate statemachine
+       always @(negedge scl or posedge sto)
+         if (sto || (sta && !d_sta) )
+           begin
+               state <= #1 idle; // reset statemachine
+
+               sda_o <= #1 1'b1;
+               ld    <= #1 1'b1;
+           end
+         else
+           begin
+               // initial settings
+               sda_o <= #1 1'b1;
+               ld    <= #1 1'b0;
+
+               case(state) // synopsys full_case parallel_case
+                   idle: // idle state
+                     if (acc_done && my_adr)
+                       begin
+                           state <= #1 slave_ack;
+                           rw <= #1 sr[0];
+                           sda_o <= #1 1'b0; // generate i2c_ack
+
+                           #2;
+                           if(debug && rw)
+                             $display("DEBUG i2c_slave; command byte received (read) at %t", $time);
+                           if(debug && !rw)
+                             $display("DEBUG i2c_slave; command byte received (write) at %t", $time);
+
+                           if(rw)
+                             begin
+                                 mem_do <= #1 mem[mem_adr % 4];
+
+                                 if(debug)
+                                   begin
+                                       #2 $display("DEBUG i2c_slave; data block read %x from address %x (1)", mem_do, mem_adr);
+                                       #2 $display("DEBUG i2c_slave; memcheck [0]=%x, [1]=%x, [2]=%x", mem[4'h0], mem[4'h1], mem[4'h2]);
+                                   end
+                             end
+                       end
+
+                   slave_ack:
+                     begin
+                         if(rw)
+                           begin
+                               state <= #1 data;
+                               sda_o <= #1 mem_do[7];
+                           end
+                         else
+                           state <= #1 get_mem_adr;
+
+                         ld    <= #1 1'b1;
+                     end
+
+                   get_mem_adr: // wait for memory address
+                     if(acc_done)
+                       begin
+                           state <= #1 gma_ack;
+                           mem_adr <= #1 sr; // store memory address
+                           sda_o <= #1 !(sr <= 15); // generate i2c_ack, for valid address
+
+                           if(debug)
+                             #1 $display("DEBUG i2c_slave; address received. adr=%x, ack=%b", sr, sda_o);
+                       end
+
+                   gma_ack:
+                     begin
+                         state <= #1 data;
+                         ld    <= #1 1'b1;
+                     end
+
+                   data: // receive or drive data
+                     begin
+                         if(rw)
+                           sda_o <= #1 mem_do[7];
+
+                         if(acc_done)
+                           begin
+                               state <= #1 data_ack;
+                               mem_adr <= #2 mem_adr + 8'h1;
+                               sda_o <= #1 (rw && (mem_adr <= 15) ); // send ack on write, receive ack on read
+
+                               if(rw)
+                                 begin
+                                     #3 mem_do <= mem[mem_adr % 4];
+
+                                     if(debug)
+                                       #5 $display("DEBUG i2c_slave; data block read %x from address %x (2)", mem_do, mem_adr);
+                                 end
+
+                               if(!rw)
+                                 begin
+                                     mem[ mem_adr[3:0] ] <= #1 sr; // store data in memory
+
+                                     if(debug)
+                                       #2 $display("DEBUG i2c_slave; data block write %x to address %x", sr, mem_adr);
+                                 end
+                           end
+                     end
+
+                   data_ack:
+                     begin
+                         ld <= #1 1'b1;
+
+                         if(rw)
+                           if(sr[0]) // read operation && master send NACK
+                             begin
+                                 state <= #1 idle;
+                                 sda_o <= #1 1'b1;
+                             end
+                           else
+                             begin
+                                 state <= #1 data;
+                                 sda_o <= #1 mem_do[7];
+                             end
+                         else
+                           begin
+                               state <= #1 data;
+                               sda_o <= #1 1'b1;
+                           end
+                     end
+
+               endcase
+           end
+
+       // read data from memory
+       always @(posedge scl)
+         if(!acc_done && rw)
+           mem_do <= #1 {mem_do[6:0], 1'b1}; // insert 1'b1 for host ack generation
+
+       // generate tri-states
+       assign sda = sda_o ? 1'bz : 1'b0;
+
+
+       //
+       // Timing checks
+       //
+
+       wire tst_sto = sto;
+       wire tst_sta = sta;
+
+       specify
+         specparam normal_scl_low  = 4700,
+                   normal_scl_high = 4000,
+                   normal_tsu_sta  = 4700,
+                   normal_thd_sta  = 4000,
+                   normal_tsu_sto  = 4000,
+                   normal_tbuf     = 4700,
+
+                   fast_scl_low  = 1300,
+                   fast_scl_high =  600,
+                   fast_tsu_sta  = 1300,
+                   fast_thd_sta  =  600,
+                   fast_tsu_sto  =  600,
+                   fast_tbuf     = 1300;
+
+         $width(negedge scl, normal_scl_low);  // scl low time
+         $width(posedge scl, normal_scl_high); // scl high time
+
+         $setup(posedge scl, negedge sda &&& scl, normal_tsu_sta); // setup start
+         $setup(negedge sda &&& scl, negedge scl, normal_thd_sta); // hold start
+         $setup(posedge scl, posedge sda &&& scl, normal_tsu_sto); // setup stop
+
+         $setup(posedge tst_sta, posedge tst_sto, normal_tbuf); // stop to start time
+       endspecify
+
+endmodule
+
+
diff --git a/tests/i2c_bench/run-test.sh b/tests/i2c_bench/run-test.sh
new file mode 100755 (executable)
index 0000000..5fdbb05
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+set -e
+make -C ../..
+../../yosys -l i2c_master_syn.log -o i2c_master_syn.v \
+               -p hierarchy -p proc -p memory -p techmap -p opt -p abc -p opt \
+               i2c_master_top.v i2c_master_bit_ctrl.v i2c_master_byte_ctrl.v
+. /opt/Xilinx/13.4/ISE_DS/settings64.sh
+
+vlogcomp --work ref i2c_master_bit_ctrl.v
+vlogcomp --work ref i2c_master_byte_ctrl.v
+vlogcomp --work ref i2c_master_top.v
+vlogcomp --work ref i2c_slave_model.v
+vlogcomp --work ref spi_slave_model.v
+vlogcomp --work ref tst_bench_top.v
+vlogcomp --work ref wb_master_model.v
+fuse --work ref -o testbench_ref --top tst_bench_top
+
+cat > testbench_ref.tcl << EOT
+vcd dumpfile testbench_ref.vcd
+vcd dumpvars -m tst_bench_top -l 0
+vcd dumpon
+run 2 ms
+exit
+EOT
+
+./testbench_ref -tclbatch testbench_ref.tcl
+
+vlogcomp --work syn i2c_master_syn.v
+vlogcomp --work syn ../../techlibs/simlib.v
+vlogcomp --work syn ../../techlibs/stdcells_sim.v
+vlogcomp --work syn i2c_slave_model.v
+vlogcomp --work syn spi_slave_model.v
+vlogcomp --work syn tst_bench_top.v
+vlogcomp --work syn wb_master_model.v
+fuse --work syn -o testbench_syn --top tst_bench_top
+
+cat > testbench_syn.tcl << EOT
+vcd dumpfile testbench_syn.vcd
+vcd dumpvars -m tst_bench_top -l 0
+vcd dumpon
+run 2 ms
+exit
+EOT
+
+./testbench_syn -tclbatch testbench_syn.tcl
+
+perl ../tools/vcdcd.pl testbench_ref.vcd testbench_syn.vcd | tee testbench_diff.txt
+echo READY.
+
diff --git a/tests/i2c_bench/spi_slave_model.v b/tests/i2c_bench/spi_slave_model.v
new file mode 100644 (file)
index 0000000..d49347b
--- /dev/null
@@ -0,0 +1,125 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  SPI Slave Model                                            ////
+////                                                             ////
+////                                                             ////
+////  Authors: Richard Herveille (richard@asics.ws) www.asics.ws ////
+////                                                             ////
+////  http://www.opencores.org/projects/simple_spi/              ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2004 Richard Herveille                        ////
+////                         richard@asics.ws                    ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: spi_slave_model.v,v 1.1 2004-02-28 15:32:54 rherveille Exp $
+//
+//  $Date: 2004-02-28 15:32:54 $
+//  $Revision: 1.1 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: not supported by cvs2svn $
+//
+//
+
+
+// Requires: Verilog2001
+
+`include "timescale.v"
+
+module spi_slave_model (
+       input  wire csn,
+       input  wire sc,
+       input  wire di,
+       output wire do
+);
+
+       //
+       // Variable declaration
+       //
+       wire debug = 1'b1;
+
+       wire cpol = 1'b0;
+       wire cpha  = 1'b0;
+
+       reg [7:0] mem [7:0]; // initiate memory
+       reg [2:0] mem_adr;   // memory address
+       reg [7:0] mem_do;    // memory data output
+
+       reg [7:0] sri, sro;  // 8bit shift register
+
+       reg [2:0] bit_cnt;
+       reg       ld;
+
+       wire clk;
+
+       //
+       // module body
+       //
+
+       assign clk = cpol ^ cpha ^ sc;
+
+       // generate shift registers
+       always @(posedge clk)
+         sri <= #1 {sri[6:0],di};
+
+       always @(posedge clk)
+         if (&bit_cnt)
+           sro <= #1 mem[mem_adr];
+         else
+           sro <= #1 {sro[6:0],1'bx};
+
+       assign do = sro[7];
+
+       //generate bit-counter
+       always @(posedge clk, posedge csn)
+         if(csn)
+           bit_cnt <= #1 3'b111;
+         else
+           bit_cnt <= #1 bit_cnt - 3'h1;
+
+       //generate access done signal
+        always @(posedge clk)
+         ld <= #1 ~(|bit_cnt);
+
+       always @(negedge clk)
+          if (ld) begin
+           mem[mem_adr] <= #1 sri;
+           mem_adr      <= #1 mem_adr + 1'b1;
+         end
+
+       initial
+       begin
+         bit_cnt=3'b111;
+         mem_adr = 0;
+         sro = mem[mem_adr];
+       end
+endmodule
+
+
diff --git a/tests/i2c_bench/timescale.v b/tests/i2c_bench/timescale.v
new file mode 100644 (file)
index 0000000..60d4ecb
--- /dev/null
@@ -0,0 +1,2 @@
+`timescale 1ns / 10ps
+
diff --git a/tests/i2c_bench/tst_bench_top.v b/tests/i2c_bench/tst_bench_top.v
new file mode 100644 (file)
index 0000000..9458de0
--- /dev/null
@@ -0,0 +1,468 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE rev.B2 compliant I2C Master controller Testbench  ////
+////                                                             ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: tst_bench_top.v,v 1.8 2006-09-04 09:08:51 rherveille Exp $
+//
+//  $Date: 2006-09-04 09:08:51 $
+//  $Revision: 1.8 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: not supported by cvs2svn $
+//               Revision 1.7  2005/02/27 09:24:18  rherveille
+//               Fixed scl, sda delay.
+//
+//               Revision 1.6  2004/02/28 15:40:42  rherveille
+//               *** empty log message ***
+//
+//               Revision 1.4  2003/12/05 11:04:38  rherveille
+//               Added slave address configurability
+//
+//               Revision 1.3  2002/10/30 18:11:06  rherveille
+//               Added timing tests to i2c_model.
+//               Updated testbench.
+//
+//               Revision 1.2  2002/03/17 10:26:38  rherveille
+//               Fixed some race conditions in the i2c-slave model.
+//               Added debug information.
+//               Added headers.
+//
+
+`include "timescale.v"
+
+module tst_bench_top();
+
+       //
+       // wires && regs
+       //
+       reg  clk;
+       reg  rstn;
+
+       wire [31:0] adr;
+       wire [ 7:0] dat_i, dat_o, dat0_i, dat1_i;
+       wire we;
+       wire stb;
+       wire cyc;
+       wire ack0, ack1;
+       wire inta;
+
+       reg [7:0] q, qq;
+
+       wire scl, scl0_o, scl0_oen, scl1_o, scl1_oen;
+       wire sda, sda0_o, sda0_oen, sda1_o, sda1_oen;
+
+       parameter PRER_LO = 3'b000;
+       parameter PRER_HI = 3'b001;
+       parameter CTR     = 3'b010;
+       parameter RXR     = 3'b011;
+       parameter TXR     = 3'b011;
+       parameter CR      = 3'b100;
+       parameter SR      = 3'b100;
+
+       parameter TXR_R   = 3'b101; // undocumented / reserved output
+       parameter CR_R    = 3'b110; // undocumented / reserved output
+
+       parameter RD      = 1'b1;
+       parameter WR      = 1'b0;
+       parameter SADR    = 7'b0010_000;
+
+       //
+       // Module body
+       //
+
+       // generate clock
+       always #5 clk = ~clk;
+
+       // hookup wishbone master model
+       wb_master_model #(8, 32) u0 (
+               .clk(clk),
+               .rst(rstn),
+               .adr(adr),
+               .din(dat_i),
+               .dout(dat_o),
+               .cyc(cyc),
+               .stb(stb),
+               .we(we),
+               .sel(),
+               .ack(ack0 || ack1),
+               .err(1'b0),
+               .rty(1'b0)
+       );
+
+       wire stb0 = stb & ~adr[3];
+       wire stb1 = stb &  adr[3];
+
+       assign dat_i = ({{8'd8}{stb0}} & dat0_i) | ({{8'd8}{stb1}} & dat1_i);
+
+       // hookup wishbone_i2c_master core
+       i2c_master_top i2c_top (
+
+               // wishbone interface
+               .wb_clk_i(clk),
+               .wb_rst_i(1'b0),
+               .arst_i(rstn),
+               .wb_adr_i(adr[2:0]),
+               .wb_dat_i(dat_o),
+               .wb_dat_o(dat0_i),
+               .wb_we_i(we),
+               .wb_stb_i(stb0),
+               .wb_cyc_i(cyc),
+               .wb_ack_o(ack0),
+               .wb_inta_o(inta),
+
+               // i2c signals
+               .scl_pad_i(scl),
+               .scl_pad_o(scl0_o),
+               .scl_padoen_o(scl0_oen),
+               .sda_pad_i(sda),
+               .sda_pad_o(sda0_o),
+               .sda_padoen_o(sda0_oen)
+       ),
+       i2c_top2 (
+
+               // wishbone interface
+               .wb_clk_i(clk),
+               .wb_rst_i(1'b0),
+               .arst_i(rstn),
+               .wb_adr_i(adr[2:0]),
+               .wb_dat_i(dat_o),
+               .wb_dat_o(dat1_i),
+               .wb_we_i(we),
+               .wb_stb_i(stb1),
+               .wb_cyc_i(cyc),
+               .wb_ack_o(ack1),
+               .wb_inta_o(inta),
+
+               // i2c signals
+               .scl_pad_i(scl),
+               .scl_pad_o(scl1_o),
+               .scl_padoen_o(scl1_oen),
+               .sda_pad_i(sda),
+               .sda_pad_o(sda1_o),
+               .sda_padoen_o(sda1_oen)
+       );
+
+
+       // hookup i2c slave model
+       i2c_slave_model #(SADR) i2c_slave (
+               .scl(scl),
+               .sda(sda)
+       );
+
+       //assign scl = ~((!scl0_oen && !scl0_o) || (!scl1_oen && !scl1_o));
+       //assign sda = ~((!sda0_oen && !sda0_o) || (!sda1_oen && !sda1_o));
+
+        // create i2c lines
+       delay m0_scl (scl0_oen ? 1'bz : scl0_o, scl),
+             m1_scl (scl1_oen ? 1'bz : scl1_o, scl),
+             m0_sda (sda0_oen ? 1'bz : sda0_o, sda),
+             m1_sda (sda1_oen ? 1'bz : sda1_o, sda);
+
+       pullup p1(scl); // pullup scl line
+       pullup p2(sda); // pullup sda line
+
+       initial
+         begin
+             `ifdef WAVES
+                $shm_open("waves");
+                $shm_probe("AS",tst_bench_top,"AS");
+                $display("INFO: Signal dump enabled ...\n\n");
+             `endif
+
+//           force i2c_slave.debug = 1'b1; // enable i2c_slave debug information
+             force i2c_slave.debug = 1'b0; // disable i2c_slave debug information
+
+             $display("\nstatus: %t Testbench started\n\n", $time);
+
+//           $dumpfile("bench.vcd");
+//           $dumpvars(1, tst_bench_top);
+//           $dumpvars(1, tst_bench_top.i2c_slave);
+
+             // initially values
+             clk = 0;
+
+             // reset system
+             rstn = 1'b1; // negate reset
+             #2;
+             rstn = 1'b0; // assert reset
+             #1000;
+             repeat(1) @(posedge clk);
+             rstn = 1'b1; // negate reset
+
+             $display("status: %t done reset", $time);
+
+             @(posedge clk);
+
+             //
+             // program core
+             //
+
+             // program internal registers
+             u0.wb_write(1, PRER_LO, 8'hfa); // load prescaler lo-byte
+             u0.wb_write(1, PRER_LO, 8'hc8); // load prescaler lo-byte
+             u0.wb_write(1, PRER_HI, 8'h00); // load prescaler hi-byte
+             $display("status: %t programmed registers", $time);
+
+             u0.wb_cmp(0, PRER_LO, 8'hc8); // verify prescaler lo-byte
+             u0.wb_cmp(0, PRER_HI, 8'h00); // verify prescaler hi-byte
+             $display("status: %t verified registers", $time);
+
+             u0.wb_write(1, CTR,     8'h80); // enable core
+             $display("status: %t core enabled", $time);
+
+             //
+             // access slave (write)
+             //
+
+             // drive slave address
+             u0.wb_write(1, TXR, {SADR,WR} ); // present slave address, set write-bit
+             u0.wb_write(0, CR,      8'h90 ); // set command (start, write)
+             $display("status: %t generate 'start', write cmd %0h (slave address+write)", $time, {SADR,WR} );
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+                  u0.wb_read(0, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             // send memory address
+             u0.wb_write(1, TXR,     8'h01); // present slave's memory address
+             u0.wb_write(0, CR,      8'h10); // set command (write)
+             $display("status: %t write slave memory address 01", $time);
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+                  u0.wb_read(0, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             // send memory contents
+             u0.wb_write(1, TXR,     8'ha5); // present data
+             u0.wb_write(0, CR,      8'h10); // set command (write)
+             $display("status: %t write data a5", $time);
+
+while (scl) #1;
+force scl= 1'b0;
+#100000;
+release scl;
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+                  u0.wb_read(1, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             // send memory contents for next memory address (auto_inc)
+             u0.wb_write(1, TXR,     8'h5a); // present data
+             u0.wb_write(0, CR,      8'h50); // set command (stop, write)
+             $display("status: %t write next data 5a, generate 'stop'", $time);
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+                  u0.wb_read(1, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             //
+             // delay
+             //
+//           #100000; // wait for 100us.
+//           $display("status: %t wait 100us", $time);
+
+             //
+             // access slave (read)
+             //
+
+             // drive slave address
+             u0.wb_write(1, TXR,{SADR,WR} ); // present slave address, set write-bit
+             u0.wb_write(0, CR,     8'h90 ); // set command (start, write)
+             $display("status: %t generate 'start', write cmd %0h (slave address+write)", $time, {SADR,WR} );
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+                  u0.wb_read(1, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             // send memory address
+             u0.wb_write(1, TXR,     8'h01); // present slave's memory address
+             u0.wb_write(0, CR,      8'h10); // set command (write)
+             $display("status: %t write slave address 01", $time);
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+                  u0.wb_read(1, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             // drive slave address
+             u0.wb_write(1, TXR, {SADR,RD} ); // present slave's address, set read-bit
+             u0.wb_write(0, CR,      8'h90 ); // set command (start, write)
+             $display("status: %t generate 'repeated start', write cmd %0h (slave address+read)", $time, {SADR,RD} );
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+                  u0.wb_read(1, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             // read data from slave
+             u0.wb_write(1, CR,      8'h20); // set command (read, ack_read)
+             $display("status: %t read + ack", $time);
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+                  u0.wb_read(1, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             // check data just received
+             u0.wb_read(1, RXR, qq);
+             if(qq !== 8'ha5)
+               $display("\nERROR: Expected a5, received %x at time %t", qq, $time);
+             else
+               $display("status: %t received %x", $time, qq);
+
+             // read data from slave
+             u0.wb_write(1, CR,      8'h20); // set command (read, ack_read)
+             $display("status: %t read + ack", $time);
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+                  u0.wb_read(1, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             // check data just received
+             u0.wb_read(1, RXR, qq);
+             if(qq !== 8'h5a)
+               $display("\nERROR: Expected 5a, received %x at time %t", qq, $time);
+             else
+               $display("status: %t received %x", $time, qq);
+
+             // read data from slave
+             u0.wb_write(1, CR,      8'h20); // set command (read, ack_read)
+             $display("status: %t read + ack", $time);
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+                  u0.wb_read(1, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             // check data just received
+             u0.wb_read(1, RXR, qq);
+             $display("status: %t received %x from 3rd read address", $time, qq);
+
+             // read data from slave
+             u0.wb_write(1, CR,      8'h28); // set command (read, nack_read)
+             $display("status: %t read + nack", $time);
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+                  u0.wb_read(1, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             // check data just received
+             u0.wb_read(1, RXR, qq);
+             $display("status: %t received %x from 4th read address", $time, qq);
+
+             //
+             // check invalid slave memory address
+             //
+
+             // drive slave address
+             u0.wb_write(1, TXR, {SADR,WR} ); // present slave address, set write-bit
+             u0.wb_write(0, CR,      8'h90 ); // set command (start, write)
+             $display("status: %t generate 'start', write cmd %0h (slave address+write). Check invalid address", $time, {SADR,WR} );
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+                  u0.wb_read(1, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             // send memory address
+             u0.wb_write(1, TXR,     8'h10); // present slave's memory address
+             u0.wb_write(0, CR,      8'h10); // set command (write)
+             $display("status: %t write slave memory address 10", $time);
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+                  u0.wb_read(1, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             // slave should have send NACK
+             $display("status: %t Check for nack", $time);
+             if(!q[7])
+               $display("\nERROR: Expected NACK, received ACK\n");
+
+             // read data from slave
+             u0.wb_write(1, CR,      8'h40); // set command (stop)
+             $display("status: %t generate 'stop'", $time);
+
+             // check tip bit
+             u0.wb_read(1, SR, q);
+             while(q[1])
+             u0.wb_read(1, SR, q); // poll it until it is zero
+             $display("status: %t tip==0", $time);
+
+             #250000; // wait 250us
+             $display("\n\nstatus: %t Testbench done", $time);
+             $finish;
+         end
+
+endmodule
+
+module delay (in, out);
+  input  in;
+  output out;
+
+  assign out = in;
+
+  specify
+    (in => out) = (599,599);
+  endspecify
+endmodule
+
+
diff --git a/tests/i2c_bench/wb_master_model.v b/tests/i2c_bench/wb_master_model.v
new file mode 100644 (file)
index 0000000..65a9b79
--- /dev/null
@@ -0,0 +1,205 @@
+///////////////////////////////////////////////////////////////////////
+////                                                               ////
+////  WISHBONE rev.B2 Wishbone Master model                        ////
+////                                                               ////
+////                                                               ////
+////  Author: Richard Herveille                                    ////
+////          richard@asics.ws                                     ////
+////          www.asics.ws                                         ////
+////                                                               ////
+////  Downloaded from: http://www.opencores.org/projects/mem_ctrl  ////
+////                                                               ////
+///////////////////////////////////////////////////////////////////////
+////                                                               ////
+//// Copyright (C) 2001 Richard Herveille                          ////
+////                    richard@asics.ws                           ////
+////                                                               ////
+//// This source file may be used and distributed without          ////
+//// restriction provided that this copyright statement is not     ////
+//// removed from the file and that any derivative work contains   ////
+//// the original copyright notice and the associated disclaimer.  ////
+////                                                               ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY       ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED     ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS     ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR        ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,           ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES      ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE     ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR          ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT    ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT    ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           ////
+//// POSSIBILITY OF SUCH DAMAGE.                                   ////
+////                                                               ////
+///////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: wb_master_model.v,v 1.4 2004-02-28 15:40:42 rherveille Exp $
+//
+//  $Date: 2004-02-28 15:40:42 $
+//  $Revision: 1.4 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//
+`include "timescale.v"
+
+module wb_master_model(clk, rst, adr, din, dout, cyc, stb, we, sel, ack, err, rty);
+
+parameter dwidth = 32;
+parameter awidth = 32;
+
+input                  clk, rst;
+output [awidth   -1:0] adr;
+input  [dwidth   -1:0] din;
+output [dwidth   -1:0] dout;
+output                 cyc, stb;
+output                         we;
+output [dwidth/8 -1:0] sel;
+input                          ack, err, rty;
+
+////////////////////////////////////////////////////////////////////
+//
+// Local Wires
+//
+
+reg    [awidth   -1:0] adr;
+reg    [dwidth   -1:0] dout;
+reg                           cyc, stb;
+reg                           we;
+reg [dwidth/8 -1:0] sel;
+
+reg [dwidth   -1:0] q;
+
+////////////////////////////////////////////////////////////////////
+//
+// Memory Logic
+//
+
+initial
+       begin
+               //adr = 32'hxxxx_xxxx;
+               //adr = 0;
+               adr  = {awidth{1'bx}};
+               dout = {dwidth{1'bx}};
+               cyc  = 1'b0;
+               stb  = 1'bx;
+               we   = 1'hx;
+               sel  = {dwidth/8{1'bx}};
+               #1;
+               $display("\nINFO: WISHBONE MASTER MODEL INSTANTIATED (%m)\n");
+       end
+
+////////////////////////////////////////////////////////////////////
+//
+// Wishbone write cycle
+//
+
+task wb_write;
+       input   delay;
+       integer delay;
+
+       input   [awidth -1:0]   a;
+       input   [dwidth -1:0]   d;
+
+       begin
+
+               // wait initial delay
+               repeat(delay) @(posedge clk);
+
+               // assert wishbone signal
+               #1;
+               adr  = a;
+               dout = d;
+               cyc  = 1'b1;
+               stb  = 1'b1;
+               we   = 1'b1;
+               sel  = {dwidth/8{1'b1}};
+               @(posedge clk);
+
+               // wait for acknowledge from slave
+               while(~ack)     @(posedge clk);
+
+               // negate wishbone signals
+               #1;
+               cyc  = 1'b0;
+               stb  = 1'bx;
+               adr  = {awidth{1'bx}};
+               dout = {dwidth{1'bx}};
+               we   = 1'hx;
+               sel  = {dwidth/8{1'bx}};
+
+       end
+endtask
+
+////////////////////////////////////////////////////////////////////
+//
+// Wishbone read cycle
+//
+
+task wb_read;
+       input   delay;
+       integer delay;
+
+       input    [awidth -1:0]  a;
+       output  [dwidth -1:0]   d;
+
+       begin
+
+               // wait initial delay
+               repeat(delay) @(posedge clk);
+
+               // assert wishbone signals
+               #1;
+               adr  = a;
+               dout = {dwidth{1'bx}};
+               cyc  = 1'b1;
+               stb  = 1'b1;
+               we   = 1'b0;
+               sel  = {dwidth/8{1'b1}};
+               @(posedge clk);
+
+               // wait for acknowledge from slave
+               while(~ack)     @(posedge clk);
+
+               // negate wishbone signals
+               #1;
+               cyc  = 1'b0;
+               stb  = 1'bx;
+               adr  = {awidth{1'bx}};
+               dout = {dwidth{1'bx}};
+               we   = 1'hx;
+               sel  = {dwidth/8{1'bx}};
+               d    = din;
+
+       end
+endtask
+
+////////////////////////////////////////////////////////////////////
+//
+// Wishbone compare cycle (read data from location and compare with expected data)
+//
+
+task wb_cmp;
+       input   delay;
+       integer delay;
+
+       input [awidth -1:0]     a;
+       input   [dwidth -1:0]   d_exp;
+
+       begin
+               wb_read (delay, a, q);
+
+               if (d_exp !== q)
+                       $display("Data compare error. Received %h, expected %h at time %t", q, d_exp, $time);
+       end
+endtask
+
+endmodule
+
+
diff --git a/tests/iwls2005/README b/tests/iwls2005/README
new file mode 100644 (file)
index 0000000..f44a89d
--- /dev/null
@@ -0,0 +1,7 @@
+
+A collection of smaller rtl examples from the IWLS 2005 benchmark [1].
+We have no testbenches for these but we can check if we can
+parse and synthesize them.
+
+[1] http://iwls.org/iwls2005/benchmarks.html
+
diff --git a/tests/iwls2005/aes_core/aes_cipher_top.v b/tests/iwls2005/aes_core/aes_cipher_top.v
new file mode 100644 (file)
index 0000000..a0acaeb
--- /dev/null
@@ -0,0 +1,256 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  AES Cipher Top Level                                       ////
+////                                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/cores/aes_core/  ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws                       ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: aes_cipher_top.v,v 1.1.1.1 2002/11/09 11:22:48 rudi Exp $
+//
+//  $Date: 2002/11/09 11:22:48 $
+//  $Revision: 1.1.1.1 $
+//  $Author: rudi $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: aes_cipher_top.v,v $
+//               Revision 1.1.1.1  2002/11/09 11:22:48  rudi
+//               Initial Checkin
+//
+//
+//
+//
+//
+//
+
+`include "timescale.v"
+
+module aes_cipher_top(clk, rst, ld, done, key, text_in, text_out );
+input          clk, rst;
+input          ld;
+output         done;
+input  [127:0] key;
+input  [127:0] text_in;
+output [127:0] text_out;
+
+////////////////////////////////////////////////////////////////////
+//
+// Local Wires
+//
+
+wire   [31:0]  w0, w1, w2, w3;
+reg    [127:0] text_in_r;
+reg    [127:0] text_out;
+reg    [7:0]   sa00, sa01, sa02, sa03;
+reg    [7:0]   sa10, sa11, sa12, sa13;
+reg    [7:0]   sa20, sa21, sa22, sa23;
+reg    [7:0]   sa30, sa31, sa32, sa33;
+wire   [7:0]   sa00_next, sa01_next, sa02_next, sa03_next;
+wire   [7:0]   sa10_next, sa11_next, sa12_next, sa13_next;
+wire   [7:0]   sa20_next, sa21_next, sa22_next, sa23_next;
+wire   [7:0]   sa30_next, sa31_next, sa32_next, sa33_next;
+wire   [7:0]   sa00_sub, sa01_sub, sa02_sub, sa03_sub;
+wire   [7:0]   sa10_sub, sa11_sub, sa12_sub, sa13_sub;
+wire   [7:0]   sa20_sub, sa21_sub, sa22_sub, sa23_sub;
+wire   [7:0]   sa30_sub, sa31_sub, sa32_sub, sa33_sub;
+wire   [7:0]   sa00_sr, sa01_sr, sa02_sr, sa03_sr;
+wire   [7:0]   sa10_sr, sa11_sr, sa12_sr, sa13_sr;
+wire   [7:0]   sa20_sr, sa21_sr, sa22_sr, sa23_sr;
+wire   [7:0]   sa30_sr, sa31_sr, sa32_sr, sa33_sr;
+wire   [7:0]   sa00_mc, sa01_mc, sa02_mc, sa03_mc;
+wire   [7:0]   sa10_mc, sa11_mc, sa12_mc, sa13_mc;
+wire   [7:0]   sa20_mc, sa21_mc, sa22_mc, sa23_mc;
+wire   [7:0]   sa30_mc, sa31_mc, sa32_mc, sa33_mc;
+reg            done, ld_r;
+reg    [3:0]   dcnt;
+
+////////////////////////////////////////////////////////////////////
+//
+// Misc Logic
+//
+
+always @(posedge clk)
+       if(!rst)        dcnt <= #1 4'h0;
+       else
+       if(ld)          dcnt <= #1 4'hb;
+       else
+       if(|dcnt)       dcnt <= #1 dcnt - 4'h1;
+
+always @(posedge clk) done <= #1 !(|dcnt[3:1]) & dcnt[0] & !ld;
+always @(posedge clk) if(ld) text_in_r <= #1 text_in;
+always @(posedge clk) ld_r <= #1 ld;
+
+////////////////////////////////////////////////////////////////////
+//
+// Initial Permutation (AddRoundKey)
+//
+
+always @(posedge clk)  sa33 <= #1 ld_r ? text_in_r[007:000] ^ w3[07:00] : sa33_next;
+always @(posedge clk)  sa23 <= #1 ld_r ? text_in_r[015:008] ^ w3[15:08] : sa23_next;
+always @(posedge clk)  sa13 <= #1 ld_r ? text_in_r[023:016] ^ w3[23:16] : sa13_next;
+always @(posedge clk)  sa03 <= #1 ld_r ? text_in_r[031:024] ^ w3[31:24] : sa03_next;
+always @(posedge clk)  sa32 <= #1 ld_r ? text_in_r[039:032] ^ w2[07:00] : sa32_next;
+always @(posedge clk)  sa22 <= #1 ld_r ? text_in_r[047:040] ^ w2[15:08] : sa22_next;
+always @(posedge clk)  sa12 <= #1 ld_r ? text_in_r[055:048] ^ w2[23:16] : sa12_next;
+always @(posedge clk)  sa02 <= #1 ld_r ? text_in_r[063:056] ^ w2[31:24] : sa02_next;
+always @(posedge clk)  sa31 <= #1 ld_r ? text_in_r[071:064] ^ w1[07:00] : sa31_next;
+always @(posedge clk)  sa21 <= #1 ld_r ? text_in_r[079:072] ^ w1[15:08] : sa21_next;
+always @(posedge clk)  sa11 <= #1 ld_r ? text_in_r[087:080] ^ w1[23:16] : sa11_next;
+always @(posedge clk)  sa01 <= #1 ld_r ? text_in_r[095:088] ^ w1[31:24] : sa01_next;
+always @(posedge clk)  sa30 <= #1 ld_r ? text_in_r[103:096] ^ w0[07:00] : sa30_next;
+always @(posedge clk)  sa20 <= #1 ld_r ? text_in_r[111:104] ^ w0[15:08] : sa20_next;
+always @(posedge clk)  sa10 <= #1 ld_r ? text_in_r[119:112] ^ w0[23:16] : sa10_next;
+always @(posedge clk)  sa00 <= #1 ld_r ? text_in_r[127:120] ^ w0[31:24] : sa00_next;
+
+////////////////////////////////////////////////////////////////////
+//
+// Round Permutations
+//
+
+assign sa00_sr = sa00_sub;
+assign sa01_sr = sa01_sub;
+assign sa02_sr = sa02_sub;
+assign sa03_sr = sa03_sub;
+assign sa10_sr = sa11_sub;
+assign sa11_sr = sa12_sub;
+assign sa12_sr = sa13_sub;
+assign sa13_sr = sa10_sub;
+assign sa20_sr = sa22_sub;
+assign sa21_sr = sa23_sub;
+assign sa22_sr = sa20_sub;
+assign sa23_sr = sa21_sub;
+assign sa30_sr = sa33_sub;
+assign sa31_sr = sa30_sub;
+assign sa32_sr = sa31_sub;
+assign sa33_sr = sa32_sub;
+assign {sa00_mc, sa10_mc, sa20_mc, sa30_mc}  = mix_col(sa00_sr,sa10_sr,sa20_sr,sa30_sr);
+assign {sa01_mc, sa11_mc, sa21_mc, sa31_mc}  = mix_col(sa01_sr,sa11_sr,sa21_sr,sa31_sr);
+assign {sa02_mc, sa12_mc, sa22_mc, sa32_mc}  = mix_col(sa02_sr,sa12_sr,sa22_sr,sa32_sr);
+assign {sa03_mc, sa13_mc, sa23_mc, sa33_mc}  = mix_col(sa03_sr,sa13_sr,sa23_sr,sa33_sr);
+assign sa00_next = sa00_mc ^ w0[31:24];
+assign sa01_next = sa01_mc ^ w1[31:24];
+assign sa02_next = sa02_mc ^ w2[31:24];
+assign sa03_next = sa03_mc ^ w3[31:24];
+assign sa10_next = sa10_mc ^ w0[23:16];
+assign sa11_next = sa11_mc ^ w1[23:16];
+assign sa12_next = sa12_mc ^ w2[23:16];
+assign sa13_next = sa13_mc ^ w3[23:16];
+assign sa20_next = sa20_mc ^ w0[15:08];
+assign sa21_next = sa21_mc ^ w1[15:08];
+assign sa22_next = sa22_mc ^ w2[15:08];
+assign sa23_next = sa23_mc ^ w3[15:08];
+assign sa30_next = sa30_mc ^ w0[07:00];
+assign sa31_next = sa31_mc ^ w1[07:00];
+assign sa32_next = sa32_mc ^ w2[07:00];
+assign sa33_next = sa33_mc ^ w3[07:00];
+
+////////////////////////////////////////////////////////////////////
+//
+// Final text output
+//
+
+always @(posedge clk) text_out[127:120] <= #1 sa00_sr ^ w0[31:24];
+always @(posedge clk) text_out[095:088] <= #1 sa01_sr ^ w1[31:24];
+always @(posedge clk) text_out[063:056] <= #1 sa02_sr ^ w2[31:24];
+always @(posedge clk) text_out[031:024] <= #1 sa03_sr ^ w3[31:24];
+always @(posedge clk) text_out[119:112] <= #1 sa10_sr ^ w0[23:16];
+always @(posedge clk) text_out[087:080] <= #1 sa11_sr ^ w1[23:16];
+always @(posedge clk) text_out[055:048] <= #1 sa12_sr ^ w2[23:16];
+always @(posedge clk) text_out[023:016] <= #1 sa13_sr ^ w3[23:16];
+always @(posedge clk) text_out[111:104] <= #1 sa20_sr ^ w0[15:08];
+always @(posedge clk) text_out[079:072] <= #1 sa21_sr ^ w1[15:08];
+always @(posedge clk) text_out[047:040] <= #1 sa22_sr ^ w2[15:08];
+always @(posedge clk) text_out[015:008] <= #1 sa23_sr ^ w3[15:08];
+always @(posedge clk) text_out[103:096] <= #1 sa30_sr ^ w0[07:00];
+always @(posedge clk) text_out[071:064] <= #1 sa31_sr ^ w1[07:00];
+always @(posedge clk) text_out[039:032] <= #1 sa32_sr ^ w2[07:00];
+always @(posedge clk) text_out[007:000] <= #1 sa33_sr ^ w3[07:00];
+
+////////////////////////////////////////////////////////////////////
+//
+// Generic Functions
+//
+
+function [31:0] mix_col;
+input  [7:0]   s0,s1,s2,s3;
+reg    [7:0]   s0_o,s1_o,s2_o,s3_o;
+begin
+mix_col[31:24]=xtime(s0)^xtime(s1)^s1^s2^s3;
+mix_col[23:16]=s0^xtime(s1)^xtime(s2)^s2^s3;
+mix_col[15:08]=s0^s1^xtime(s2)^xtime(s3)^s3;
+mix_col[07:00]=xtime(s0)^s0^s1^s2^xtime(s3);
+end
+endfunction
+
+function [7:0] xtime;
+input [7:0] b; xtime={b[6:0],1'b0}^(8'h1b&{8{b[7]}});
+endfunction
+
+////////////////////////////////////////////////////////////////////
+//
+// Modules
+//
+
+aes_key_expand_128 u0(
+       .clk(           clk     ),
+       .kld(           ld      ),
+       .key(           key     ),
+       .wo_0(          w0      ),
+       .wo_1(          w1      ),
+       .wo_2(          w2      ),
+       .wo_3(          w3      ));
+
+aes_sbox us00( .a(     sa00    ), .d(  sa00_sub        ));
+aes_sbox us01( .a(     sa01    ), .d(  sa01_sub        ));
+aes_sbox us02( .a(     sa02    ), .d(  sa02_sub        ));
+aes_sbox us03( .a(     sa03    ), .d(  sa03_sub        ));
+aes_sbox us10( .a(     sa10    ), .d(  sa10_sub        ));
+aes_sbox us11( .a(     sa11    ), .d(  sa11_sub        ));
+aes_sbox us12( .a(     sa12    ), .d(  sa12_sub        ));
+aes_sbox us13( .a(     sa13    ), .d(  sa13_sub        ));
+aes_sbox us20( .a(     sa20    ), .d(  sa20_sub        ));
+aes_sbox us21( .a(     sa21    ), .d(  sa21_sub        ));
+aes_sbox us22( .a(     sa22    ), .d(  sa22_sub        ));
+aes_sbox us23( .a(     sa23    ), .d(  sa23_sub        ));
+aes_sbox us30( .a(     sa30    ), .d(  sa30_sub        ));
+aes_sbox us31( .a(     sa31    ), .d(  sa31_sub        ));
+aes_sbox us32( .a(     sa32    ), .d(  sa32_sub        ));
+aes_sbox us33( .a(     sa33    ), .d(  sa33_sub        ));
+
+endmodule
+
+
diff --git a/tests/iwls2005/aes_core/aes_inv_cipher_top.v b/tests/iwls2005/aes_core/aes_inv_cipher_top.v
new file mode 100644 (file)
index 0000000..51b3525
--- /dev/null
@@ -0,0 +1,327 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  AES Inverse Cipher Top Level                               ////
+////                                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/cores/aes_core/  ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws                       ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: aes_inv_cipher_top.v,v 1.1.1.1 2002/11/09 11:22:53 rudi Exp $
+//
+//  $Date: 2002/11/09 11:22:53 $
+//  $Revision: 1.1.1.1 $
+//  $Author: rudi $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: aes_inv_cipher_top.v,v $
+//               Revision 1.1.1.1  2002/11/09 11:22:53  rudi
+//               Initial Checkin
+//
+//
+//
+//
+//
+//
+
+`include "timescale.v"
+
+module aes_inv_cipher_top(clk, rst, kld, ld, done, key, text_in, text_out );
+input          clk, rst;
+input          kld, ld;
+output         done;
+input  [127:0] key;
+input  [127:0] text_in;
+output [127:0] text_out;
+
+////////////////////////////////////////////////////////////////////
+//
+// Local Wires
+//
+
+wire   [31:0]  wk0, wk1, wk2, wk3;
+reg    [31:0]  w0, w1, w2, w3;
+reg    [127:0] text_in_r;
+reg    [127:0] text_out;
+reg    [7:0]   sa00, sa01, sa02, sa03;
+reg    [7:0]   sa10, sa11, sa12, sa13;
+reg    [7:0]   sa20, sa21, sa22, sa23;
+reg    [7:0]   sa30, sa31, sa32, sa33;
+wire   [7:0]   sa00_next, sa01_next, sa02_next, sa03_next;
+wire   [7:0]   sa10_next, sa11_next, sa12_next, sa13_next;
+wire   [7:0]   sa20_next, sa21_next, sa22_next, sa23_next;
+wire   [7:0]   sa30_next, sa31_next, sa32_next, sa33_next;
+wire   [7:0]   sa00_sub, sa01_sub, sa02_sub, sa03_sub;
+wire   [7:0]   sa10_sub, sa11_sub, sa12_sub, sa13_sub;
+wire   [7:0]   sa20_sub, sa21_sub, sa22_sub, sa23_sub;
+wire   [7:0]   sa30_sub, sa31_sub, sa32_sub, sa33_sub;
+wire   [7:0]   sa00_sr, sa01_sr, sa02_sr, sa03_sr;
+wire   [7:0]   sa10_sr, sa11_sr, sa12_sr, sa13_sr;
+wire   [7:0]   sa20_sr, sa21_sr, sa22_sr, sa23_sr;
+wire   [7:0]   sa30_sr, sa31_sr, sa32_sr, sa33_sr;
+wire   [7:0]   sa00_ark, sa01_ark, sa02_ark, sa03_ark;
+wire   [7:0]   sa10_ark, sa11_ark, sa12_ark, sa13_ark;
+wire   [7:0]   sa20_ark, sa21_ark, sa22_ark, sa23_ark;
+wire   [7:0]   sa30_ark, sa31_ark, sa32_ark, sa33_ark;
+reg            ld_r, go, done;
+reg    [3:0]   dcnt;
+
+////////////////////////////////////////////////////////////////////
+//
+// Misc Logic
+//
+
+always @(posedge clk)
+       if(!rst)        dcnt <= #1 4'h0;
+       else
+       if(done)        dcnt <= #1 4'h0;
+       else
+       if(ld)          dcnt <= #1 4'h1;
+       else
+       if(go)          dcnt <= #1 dcnt + 4'h1;
+
+always @(posedge clk)  done <= #1 (dcnt==4'hb) & !ld;
+
+always @(posedge clk)
+       if(!rst)        go <= #1 1'b0;
+       else
+       if(ld)          go <= #1 1'b1;
+       else
+       if(done)        go <= #1 1'b0;
+
+always @(posedge clk)  if(ld)  text_in_r <= #1 text_in;
+
+always @(posedge clk)  ld_r <= #1 ld;
+
+////////////////////////////////////////////////////////////////////
+//
+// Initial Permutation
+//
+
+always @(posedge clk)  sa33 <= #1 ld_r ? text_in_r[007:000] ^ w3[07:00] : sa33_next;
+always @(posedge clk)  sa23 <= #1 ld_r ? text_in_r[015:008] ^ w3[15:08] : sa23_next;
+always @(posedge clk)  sa13 <= #1 ld_r ? text_in_r[023:016] ^ w3[23:16] : sa13_next;
+always @(posedge clk)  sa03 <= #1 ld_r ? text_in_r[031:024] ^ w3[31:24] : sa03_next;
+always @(posedge clk)  sa32 <= #1 ld_r ? text_in_r[039:032] ^ w2[07:00] : sa32_next;
+always @(posedge clk)  sa22 <= #1 ld_r ? text_in_r[047:040] ^ w2[15:08] : sa22_next;
+always @(posedge clk)  sa12 <= #1 ld_r ? text_in_r[055:048] ^ w2[23:16] : sa12_next;
+always @(posedge clk)  sa02 <= #1 ld_r ? text_in_r[063:056] ^ w2[31:24] : sa02_next;
+always @(posedge clk)  sa31 <= #1 ld_r ? text_in_r[071:064] ^ w1[07:00] : sa31_next;
+always @(posedge clk)  sa21 <= #1 ld_r ? text_in_r[079:072] ^ w1[15:08] : sa21_next;
+always @(posedge clk)  sa11 <= #1 ld_r ? text_in_r[087:080] ^ w1[23:16] : sa11_next;
+always @(posedge clk)  sa01 <= #1 ld_r ? text_in_r[095:088] ^ w1[31:24] : sa01_next;
+always @(posedge clk)  sa30 <= #1 ld_r ? text_in_r[103:096] ^ w0[07:00] : sa30_next;
+always @(posedge clk)  sa20 <= #1 ld_r ? text_in_r[111:104] ^ w0[15:08] : sa20_next;
+always @(posedge clk)  sa10 <= #1 ld_r ? text_in_r[119:112] ^ w0[23:16] : sa10_next;
+always @(posedge clk)  sa00 <= #1 ld_r ? text_in_r[127:120] ^ w0[31:24] : sa00_next;
+
+////////////////////////////////////////////////////////////////////
+//
+// Round Permutations
+//
+
+assign sa00_sr = sa00;
+assign sa01_sr = sa01;
+assign sa02_sr = sa02;
+assign sa03_sr = sa03;
+assign sa10_sr = sa13;
+assign sa11_sr = sa10;
+assign sa12_sr = sa11;
+assign sa13_sr = sa12;
+assign sa20_sr = sa22;
+assign sa21_sr = sa23;
+assign sa22_sr = sa20;
+assign sa23_sr = sa21;
+assign sa30_sr = sa31;
+assign sa31_sr = sa32;
+assign sa32_sr = sa33;
+assign sa33_sr = sa30;
+assign sa00_ark = sa00_sub ^ w0[31:24];
+assign sa01_ark = sa01_sub ^ w1[31:24];
+assign sa02_ark = sa02_sub ^ w2[31:24];
+assign sa03_ark = sa03_sub ^ w3[31:24];
+assign sa10_ark = sa10_sub ^ w0[23:16];
+assign sa11_ark = sa11_sub ^ w1[23:16];
+assign sa12_ark = sa12_sub ^ w2[23:16];
+assign sa13_ark = sa13_sub ^ w3[23:16];
+assign sa20_ark = sa20_sub ^ w0[15:08];
+assign sa21_ark = sa21_sub ^ w1[15:08];
+assign sa22_ark = sa22_sub ^ w2[15:08];
+assign sa23_ark = sa23_sub ^ w3[15:08];
+assign sa30_ark = sa30_sub ^ w0[07:00];
+assign sa31_ark = sa31_sub ^ w1[07:00];
+assign sa32_ark = sa32_sub ^ w2[07:00];
+assign sa33_ark = sa33_sub ^ w3[07:00];
+assign {sa00_next, sa10_next, sa20_next, sa30_next} = inv_mix_col(sa00_ark,sa10_ark,sa20_ark,sa30_ark);
+assign {sa01_next, sa11_next, sa21_next, sa31_next} = inv_mix_col(sa01_ark,sa11_ark,sa21_ark,sa31_ark);
+assign {sa02_next, sa12_next, sa22_next, sa32_next} = inv_mix_col(sa02_ark,sa12_ark,sa22_ark,sa32_ark);
+assign {sa03_next, sa13_next, sa23_next, sa33_next} = inv_mix_col(sa03_ark,sa13_ark,sa23_ark,sa33_ark);
+
+////////////////////////////////////////////////////////////////////
+//
+// Final Text Output
+//
+
+always @(posedge clk) text_out[127:120] <= #1 sa00_ark;
+always @(posedge clk) text_out[095:088] <= #1 sa01_ark;
+always @(posedge clk) text_out[063:056] <= #1 sa02_ark;
+always @(posedge clk) text_out[031:024] <= #1 sa03_ark;
+always @(posedge clk) text_out[119:112] <= #1 sa10_ark;
+always @(posedge clk) text_out[087:080] <= #1 sa11_ark;
+always @(posedge clk) text_out[055:048] <= #1 sa12_ark;
+always @(posedge clk) text_out[023:016] <= #1 sa13_ark;
+always @(posedge clk) text_out[111:104] <= #1 sa20_ark;
+always @(posedge clk) text_out[079:072] <= #1 sa21_ark;
+always @(posedge clk) text_out[047:040] <= #1 sa22_ark;
+always @(posedge clk) text_out[015:008] <= #1 sa23_ark;
+always @(posedge clk) text_out[103:096] <= #1 sa30_ark;
+always @(posedge clk) text_out[071:064] <= #1 sa31_ark;
+always @(posedge clk) text_out[039:032] <= #1 sa32_ark;
+always @(posedge clk) text_out[007:000] <= #1 sa33_ark;
+
+////////////////////////////////////////////////////////////////////
+//
+// Generic Functions
+//
+
+function [31:0] inv_mix_col;
+input  [7:0]   s0,s1,s2,s3;
+begin
+inv_mix_col[31:24]=pmul_e(s0)^pmul_b(s1)^pmul_d(s2)^pmul_9(s3);
+inv_mix_col[23:16]=pmul_9(s0)^pmul_e(s1)^pmul_b(s2)^pmul_d(s3);
+inv_mix_col[15:08]=pmul_d(s0)^pmul_9(s1)^pmul_e(s2)^pmul_b(s3);
+inv_mix_col[07:00]=pmul_b(s0)^pmul_d(s1)^pmul_9(s2)^pmul_e(s3);
+end
+endfunction
+
+// Some synthesis tools don't like xtime being called recursevly ...
+function [7:0] pmul_e;
+input [7:0] b;
+reg [7:0] two,four,eight;
+begin
+two=xtime(b);four=xtime(two);eight=xtime(four);pmul_e=eight^four^two;
+end
+endfunction
+
+function [7:0] pmul_9;
+input [7:0] b;
+reg [7:0] two,four,eight;
+begin
+two=xtime(b);four=xtime(two);eight=xtime(four);pmul_9=eight^b;
+end
+endfunction
+
+function [7:0] pmul_d;
+input [7:0] b;
+reg [7:0] two,four,eight;
+begin
+two=xtime(b);four=xtime(two);eight=xtime(four);pmul_d=eight^four^b;
+end
+endfunction
+
+function [7:0] pmul_b;
+input [7:0] b;
+reg [7:0] two,four,eight;
+begin
+two=xtime(b);four=xtime(two);eight=xtime(four);pmul_b=eight^two^b;
+end
+endfunction
+
+function [7:0] xtime;
+input [7:0] b;xtime={b[6:0],1'b0}^(8'h1b&{8{b[7]}});
+endfunction
+
+////////////////////////////////////////////////////////////////////
+//
+// Key Buffer
+//
+
+reg    [127:0] kb[10:0];
+reg    [3:0]   kcnt;
+reg            kdone;
+reg            kb_ld;
+
+always @(posedge clk)
+       if(!rst)        kcnt <= #1 4'ha;
+       else
+       if(kld)         kcnt <= #1 4'ha;
+       else
+       if(kb_ld)       kcnt <= #1 kcnt - 4'h1;
+
+always @(posedge clk)
+       if(!rst)        kb_ld <= #1 1'b0;
+       else
+       if(kld)         kb_ld <= #1 1'b1;
+       else
+       if(kcnt==4'h0)  kb_ld <= #1 1'b0;
+
+always @(posedge clk)  kdone <= #1 (kcnt==4'h0) & !kld;
+always @(posedge clk)  if(kb_ld) kb[kcnt] <= #1 {wk3, wk2, wk1, wk0};
+always @(posedge clk)  {w3, w2, w1, w0} <= #1 kb[dcnt];
+
+////////////////////////////////////////////////////////////////////
+//
+// Modules
+//
+
+aes_key_expand_128 u0(
+       .clk(           clk     ),
+       .kld(           kld     ),
+       .key(           key     ),
+       .wo_0(          wk0     ),
+       .wo_1(          wk1     ),
+       .wo_2(          wk2     ),
+       .wo_3(          wk3     ));
+
+aes_inv_sbox us00(     .a(     sa00_sr ),      .d(     sa00_sub        ));
+aes_inv_sbox us01(     .a(     sa01_sr ),      .d(     sa01_sub        ));
+aes_inv_sbox us02(     .a(     sa02_sr ),      .d(     sa02_sub        ));
+aes_inv_sbox us03(     .a(     sa03_sr ),      .d(     sa03_sub        ));
+aes_inv_sbox us10(     .a(     sa10_sr ),      .d(     sa10_sub        ));
+aes_inv_sbox us11(     .a(     sa11_sr ),      .d(     sa11_sub        ));
+aes_inv_sbox us12(     .a(     sa12_sr ),      .d(     sa12_sub        ));
+aes_inv_sbox us13(     .a(     sa13_sr ),      .d(     sa13_sub        ));
+aes_inv_sbox us20(     .a(     sa20_sr ),      .d(     sa20_sub        ));
+aes_inv_sbox us21(     .a(     sa21_sr ),      .d(     sa21_sub        ));
+aes_inv_sbox us22(     .a(     sa22_sr ),      .d(     sa22_sub        ));
+aes_inv_sbox us23(     .a(     sa23_sr ),      .d(     sa23_sub        ));
+aes_inv_sbox us30(     .a(     sa30_sr ),      .d(     sa30_sub        ));
+aes_inv_sbox us31(     .a(     sa31_sr ),      .d(     sa31_sub        ));
+aes_inv_sbox us32(     .a(     sa32_sr ),      .d(     sa32_sub        ));
+aes_inv_sbox us33(     .a(     sa33_sr ),      .d(     sa33_sub        ));
+
+endmodule
+
diff --git a/tests/iwls2005/aes_core/aes_inv_sbox.v b/tests/iwls2005/aes_core/aes_inv_sbox.v
new file mode 100644 (file)
index 0000000..323181e
--- /dev/null
@@ -0,0 +1,328 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  AES Inverse SBOX (ROM)                                     ////
+////                                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/cores/aes_core/  ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws                       ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: aes_inv_sbox.v,v 1.1.1.1 2002/11/09 11:22:55 rudi Exp $
+//
+//  $Date: 2002/11/09 11:22:55 $
+//  $Revision: 1.1.1.1 $
+//  $Author: rudi $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: aes_inv_sbox.v,v $
+//               Revision 1.1.1.1  2002/11/09 11:22:55  rudi
+//               Initial Checkin
+//
+//
+//
+//
+//
+//
+
+`include "timescale.v"
+
+module aes_inv_sbox(a,d);
+input  [7:0]   a;
+output [7:0]   d;
+reg    [7:0]   d;
+
+always @(a)
+       case(a)         // synopsys full_case parallel_case
+          8'h00: d=8'h52;
+          8'h01: d=8'h09;
+          8'h02: d=8'h6a;
+          8'h03: d=8'hd5;
+          8'h04: d=8'h30;
+          8'h05: d=8'h36;
+          8'h06: d=8'ha5;
+          8'h07: d=8'h38;
+          8'h08: d=8'hbf;
+          8'h09: d=8'h40;
+          8'h0a: d=8'ha3;
+          8'h0b: d=8'h9e;
+          8'h0c: d=8'h81;
+          8'h0d: d=8'hf3;
+          8'h0e: d=8'hd7;
+          8'h0f: d=8'hfb;
+          8'h10: d=8'h7c;
+          8'h11: d=8'he3;
+          8'h12: d=8'h39;
+          8'h13: d=8'h82;
+          8'h14: d=8'h9b;
+          8'h15: d=8'h2f;
+          8'h16: d=8'hff;
+          8'h17: d=8'h87;
+          8'h18: d=8'h34;
+          8'h19: d=8'h8e;
+          8'h1a: d=8'h43;
+          8'h1b: d=8'h44;
+          8'h1c: d=8'hc4;
+          8'h1d: d=8'hde;
+          8'h1e: d=8'he9;
+          8'h1f: d=8'hcb;
+          8'h20: d=8'h54;
+          8'h21: d=8'h7b;
+          8'h22: d=8'h94;
+          8'h23: d=8'h32;
+          8'h24: d=8'ha6;
+          8'h25: d=8'hc2;
+          8'h26: d=8'h23;
+          8'h27: d=8'h3d;
+          8'h28: d=8'hee;
+          8'h29: d=8'h4c;
+          8'h2a: d=8'h95;
+          8'h2b: d=8'h0b;
+          8'h2c: d=8'h42;
+          8'h2d: d=8'hfa;
+          8'h2e: d=8'hc3;
+          8'h2f: d=8'h4e;
+          8'h30: d=8'h08;
+          8'h31: d=8'h2e;
+          8'h32: d=8'ha1;
+          8'h33: d=8'h66;
+          8'h34: d=8'h28;
+          8'h35: d=8'hd9;
+          8'h36: d=8'h24;
+          8'h37: d=8'hb2;
+          8'h38: d=8'h76;
+          8'h39: d=8'h5b;
+          8'h3a: d=8'ha2;
+          8'h3b: d=8'h49;
+          8'h3c: d=8'h6d;
+          8'h3d: d=8'h8b;
+          8'h3e: d=8'hd1;
+          8'h3f: d=8'h25;
+          8'h40: d=8'h72;
+          8'h41: d=8'hf8;
+          8'h42: d=8'hf6;
+          8'h43: d=8'h64;
+          8'h44: d=8'h86;
+          8'h45: d=8'h68;
+          8'h46: d=8'h98;
+          8'h47: d=8'h16;
+          8'h48: d=8'hd4;
+          8'h49: d=8'ha4;
+          8'h4a: d=8'h5c;
+          8'h4b: d=8'hcc;
+          8'h4c: d=8'h5d;
+          8'h4d: d=8'h65;
+          8'h4e: d=8'hb6;
+          8'h4f: d=8'h92;
+          8'h50: d=8'h6c;
+          8'h51: d=8'h70;
+          8'h52: d=8'h48;
+          8'h53: d=8'h50;
+          8'h54: d=8'hfd;
+          8'h55: d=8'hed;
+          8'h56: d=8'hb9;
+          8'h57: d=8'hda;
+          8'h58: d=8'h5e;
+          8'h59: d=8'h15;
+          8'h5a: d=8'h46;
+          8'h5b: d=8'h57;
+          8'h5c: d=8'ha7;
+          8'h5d: d=8'h8d;
+          8'h5e: d=8'h9d;
+          8'h5f: d=8'h84;
+          8'h60: d=8'h90;
+          8'h61: d=8'hd8;
+          8'h62: d=8'hab;
+          8'h63: d=8'h00;
+          8'h64: d=8'h8c;
+          8'h65: d=8'hbc;
+          8'h66: d=8'hd3;
+          8'h67: d=8'h0a;
+          8'h68: d=8'hf7;
+          8'h69: d=8'he4;
+          8'h6a: d=8'h58;
+          8'h6b: d=8'h05;
+          8'h6c: d=8'hb8;
+          8'h6d: d=8'hb3;
+          8'h6e: d=8'h45;
+          8'h6f: d=8'h06;
+          8'h70: d=8'hd0;
+          8'h71: d=8'h2c;
+          8'h72: d=8'h1e;
+          8'h73: d=8'h8f;
+          8'h74: d=8'hca;
+          8'h75: d=8'h3f;
+          8'h76: d=8'h0f;
+          8'h77: d=8'h02;
+          8'h78: d=8'hc1;
+          8'h79: d=8'haf;
+          8'h7a: d=8'hbd;
+          8'h7b: d=8'h03;
+          8'h7c: d=8'h01;
+          8'h7d: d=8'h13;
+          8'h7e: d=8'h8a;
+          8'h7f: d=8'h6b;
+          8'h80: d=8'h3a;
+          8'h81: d=8'h91;
+          8'h82: d=8'h11;
+          8'h83: d=8'h41;
+          8'h84: d=8'h4f;
+          8'h85: d=8'h67;
+          8'h86: d=8'hdc;
+          8'h87: d=8'hea;
+          8'h88: d=8'h97;
+          8'h89: d=8'hf2;
+          8'h8a: d=8'hcf;
+          8'h8b: d=8'hce;
+          8'h8c: d=8'hf0;
+          8'h8d: d=8'hb4;
+          8'h8e: d=8'he6;
+          8'h8f: d=8'h73;
+          8'h90: d=8'h96;
+          8'h91: d=8'hac;
+          8'h92: d=8'h74;
+          8'h93: d=8'h22;
+          8'h94: d=8'he7;
+          8'h95: d=8'had;
+          8'h96: d=8'h35;
+          8'h97: d=8'h85;
+          8'h98: d=8'he2;
+          8'h99: d=8'hf9;
+          8'h9a: d=8'h37;
+          8'h9b: d=8'he8;
+          8'h9c: d=8'h1c;
+          8'h9d: d=8'h75;
+          8'h9e: d=8'hdf;
+          8'h9f: d=8'h6e;
+          8'ha0: d=8'h47;
+          8'ha1: d=8'hf1;
+          8'ha2: d=8'h1a;
+          8'ha3: d=8'h71;
+          8'ha4: d=8'h1d;
+          8'ha5: d=8'h29;
+          8'ha6: d=8'hc5;
+          8'ha7: d=8'h89;
+          8'ha8: d=8'h6f;
+          8'ha9: d=8'hb7;
+          8'haa: d=8'h62;
+          8'hab: d=8'h0e;
+          8'hac: d=8'haa;
+          8'had: d=8'h18;
+          8'hae: d=8'hbe;
+          8'haf: d=8'h1b;
+          8'hb0: d=8'hfc;
+          8'hb1: d=8'h56;
+          8'hb2: d=8'h3e;
+          8'hb3: d=8'h4b;
+          8'hb4: d=8'hc6;
+          8'hb5: d=8'hd2;
+          8'hb6: d=8'h79;
+          8'hb7: d=8'h20;
+          8'hb8: d=8'h9a;
+          8'hb9: d=8'hdb;
+          8'hba: d=8'hc0;
+          8'hbb: d=8'hfe;
+          8'hbc: d=8'h78;
+          8'hbd: d=8'hcd;
+          8'hbe: d=8'h5a;
+          8'hbf: d=8'hf4;
+          8'hc0: d=8'h1f;
+          8'hc1: d=8'hdd;
+          8'hc2: d=8'ha8;
+          8'hc3: d=8'h33;
+          8'hc4: d=8'h88;
+          8'hc5: d=8'h07;
+          8'hc6: d=8'hc7;
+          8'hc7: d=8'h31;
+          8'hc8: d=8'hb1;
+          8'hc9: d=8'h12;
+          8'hca: d=8'h10;
+          8'hcb: d=8'h59;
+          8'hcc: d=8'h27;
+          8'hcd: d=8'h80;
+          8'hce: d=8'hec;
+          8'hcf: d=8'h5f;
+          8'hd0: d=8'h60;
+          8'hd1: d=8'h51;
+          8'hd2: d=8'h7f;
+          8'hd3: d=8'ha9;
+          8'hd4: d=8'h19;
+          8'hd5: d=8'hb5;
+          8'hd6: d=8'h4a;
+          8'hd7: d=8'h0d;
+          8'hd8: d=8'h2d;
+          8'hd9: d=8'he5;
+          8'hda: d=8'h7a;
+          8'hdb: d=8'h9f;
+          8'hdc: d=8'h93;
+          8'hdd: d=8'hc9;
+          8'hde: d=8'h9c;
+          8'hdf: d=8'hef;
+          8'he0: d=8'ha0;
+          8'he1: d=8'he0;
+          8'he2: d=8'h3b;
+          8'he3: d=8'h4d;
+          8'he4: d=8'hae;
+          8'he5: d=8'h2a;
+          8'he6: d=8'hf5;
+          8'he7: d=8'hb0;
+          8'he8: d=8'hc8;
+          8'he9: d=8'heb;
+          8'hea: d=8'hbb;
+          8'heb: d=8'h3c;
+          8'hec: d=8'h83;
+          8'hed: d=8'h53;
+          8'hee: d=8'h99;
+          8'hef: d=8'h61;
+          8'hf0: d=8'h17;
+          8'hf1: d=8'h2b;
+          8'hf2: d=8'h04;
+          8'hf3: d=8'h7e;
+          8'hf4: d=8'hba;
+          8'hf5: d=8'h77;
+          8'hf6: d=8'hd6;
+          8'hf7: d=8'h26;
+          8'hf8: d=8'he1;
+          8'hf9: d=8'h69;
+          8'hfa: d=8'h14;
+          8'hfb: d=8'h63;
+          8'hfc: d=8'h55;
+          8'hfd: d=8'h21;
+          8'hfe: d=8'h0c;
+          8'hff: d=8'h7d;
+       endcase
+endmodule
+
+
diff --git a/tests/iwls2005/aes_core/aes_key_expand_128.v b/tests/iwls2005/aes_core/aes_key_expand_128.v
new file mode 100644 (file)
index 0000000..ddc74b7
--- /dev/null
@@ -0,0 +1,87 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  AES Key Expand Block (for 128 bit keys)                    ////
+////                                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/cores/aes_core/  ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws                       ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: aes_key_expand_128.v,v 1.1.1.1 2002/11/09 11:22:38 rudi Exp $
+//
+//  $Date: 2002/11/09 11:22:38 $
+//  $Revision: 1.1.1.1 $
+//  $Author: rudi $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: aes_key_expand_128.v,v $
+//               Revision 1.1.1.1  2002/11/09 11:22:38  rudi
+//               Initial Checkin
+//
+//
+//
+//
+//
+//
+
+`include "timescale.v"
+
+module aes_key_expand_128(clk, kld, key, wo_0, wo_1, wo_2, wo_3);
+input          clk;
+input          kld;
+input  [127:0] key;
+output [31:0]  wo_0, wo_1, wo_2, wo_3;
+reg    [31:0]  w[3:0];
+wire   [31:0]  tmp_w;
+wire   [31:0]  subword;
+wire   [31:0]  rcon;
+
+assign wo_0 = w[0];
+assign wo_1 = w[1];
+assign wo_2 = w[2];
+assign wo_3 = w[3];
+always @(posedge clk)  w[0] <= #1 kld ? key[127:096] : w[0]^subword^rcon;
+always @(posedge clk)  w[1] <= #1 kld ? key[095:064] : w[0]^w[1]^subword^rcon;
+always @(posedge clk)  w[2] <= #1 kld ? key[063:032] : w[0]^w[2]^w[1]^subword^rcon;
+always @(posedge clk)  w[3] <= #1 kld ? key[031:000] : w[0]^w[3]^w[2]^w[1]^subword^rcon;
+assign tmp_w = w[3];
+aes_sbox u0(   .a(tmp_w[23:16]), .d(subword[31:24]));
+aes_sbox u1(   .a(tmp_w[15:08]), .d(subword[23:16]));
+aes_sbox u2(   .a(tmp_w[07:00]), .d(subword[15:08]));
+aes_sbox u3(   .a(tmp_w[31:24]), .d(subword[07:00]));
+aes_rcon r0(   .clk(clk), .kld(kld), .out(rcon));
+endmodule
+
diff --git a/tests/iwls2005/aes_core/aes_rcon.v b/tests/iwls2005/aes_core/aes_rcon.v
new file mode 100644 (file)
index 0000000..c2c0a12
--- /dev/null
@@ -0,0 +1,96 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  AES RCON Block                                             ////
+////                                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/cores/aes_core/  ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws                       ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: aes_rcon.v,v 1.1.1.1 2002/11/09 11:22:38 rudi Exp $
+//
+//  $Date: 2002/11/09 11:22:38 $
+//  $Revision: 1.1.1.1 $
+//  $Author: rudi $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: aes_rcon.v,v $
+//               Revision 1.1.1.1  2002/11/09 11:22:38  rudi
+//               Initial Checkin
+//
+//
+//
+//
+//
+//
+
+`include "timescale.v"
+
+module aes_rcon(clk, kld, out);
+input          clk;
+input          kld;
+output [31:0]  out;
+reg    [31:0]  out;
+reg    [3:0]   rcnt;
+wire   [3:0]   rcnt_next;
+
+always @(posedge clk)
+       if(kld)         out <= #1 32'h01_00_00_00;
+       else            out <= #1 frcon(rcnt_next);
+
+assign rcnt_next = rcnt + 4'h1;
+always @(posedge clk)
+       if(kld)         rcnt <= #1 4'h0;
+       else            rcnt <= #1 rcnt_next;
+
+function [31:0]        frcon;
+input  [3:0]   i;
+case(i)        // synopsys parallel_case
+   4'h0: frcon=32'h01_00_00_00;
+   4'h1: frcon=32'h02_00_00_00;
+   4'h2: frcon=32'h04_00_00_00;
+   4'h3: frcon=32'h08_00_00_00;
+   4'h4: frcon=32'h10_00_00_00;
+   4'h5: frcon=32'h20_00_00_00;
+   4'h6: frcon=32'h40_00_00_00;
+   4'h7: frcon=32'h80_00_00_00;
+   4'h8: frcon=32'h1b_00_00_00;
+   4'h9: frcon=32'h36_00_00_00;
+   default: frcon=32'h00_00_00_00;
+endcase
+endfunction
+
+endmodule
diff --git a/tests/iwls2005/aes_core/aes_sbox.v b/tests/iwls2005/aes_core/aes_sbox.v
new file mode 100644 (file)
index 0000000..e01d75e
--- /dev/null
@@ -0,0 +1,329 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  AES SBOX (ROM)                                             ////
+////                                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/cores/aes_core/  ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws                       ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: aes_sbox.v,v 1.1.1.1 2002/11/09 11:22:38 rudi Exp $
+//
+//  $Date: 2002/11/09 11:22:38 $
+//  $Revision: 1.1.1.1 $
+//  $Author: rudi $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: aes_sbox.v,v $
+//               Revision 1.1.1.1  2002/11/09 11:22:38  rudi
+//               Initial Checkin
+//
+//
+//
+//
+//
+//
+
+`include "timescale.v"
+
+module aes_sbox(a,d);
+input  [7:0]   a;
+output [7:0]   d;
+reg    [7:0]   d;
+
+always @(a)
+       case(a)         // synopsys full_case parallel_case
+          8'h00: d=8'h63;
+          8'h01: d=8'h7c;
+          8'h02: d=8'h77;
+          8'h03: d=8'h7b;
+          8'h04: d=8'hf2;
+          8'h05: d=8'h6b;
+          8'h06: d=8'h6f;
+          8'h07: d=8'hc5;
+          8'h08: d=8'h30;
+          8'h09: d=8'h01;
+          8'h0a: d=8'h67;
+          8'h0b: d=8'h2b;
+          8'h0c: d=8'hfe;
+          8'h0d: d=8'hd7;
+          8'h0e: d=8'hab;
+          8'h0f: d=8'h76;
+          8'h10: d=8'hca;
+          8'h11: d=8'h82;
+          8'h12: d=8'hc9;
+          8'h13: d=8'h7d;
+          8'h14: d=8'hfa;
+          8'h15: d=8'h59;
+          8'h16: d=8'h47;
+          8'h17: d=8'hf0;
+          8'h18: d=8'had;
+          8'h19: d=8'hd4;
+          8'h1a: d=8'ha2;
+          8'h1b: d=8'haf;
+          8'h1c: d=8'h9c;
+          8'h1d: d=8'ha4;
+          8'h1e: d=8'h72;
+          8'h1f: d=8'hc0;
+          8'h20: d=8'hb7;
+          8'h21: d=8'hfd;
+          8'h22: d=8'h93;
+          8'h23: d=8'h26;
+          8'h24: d=8'h36;
+          8'h25: d=8'h3f;
+          8'h26: d=8'hf7;
+          8'h27: d=8'hcc;
+          8'h28: d=8'h34;
+          8'h29: d=8'ha5;
+          8'h2a: d=8'he5;
+          8'h2b: d=8'hf1;
+          8'h2c: d=8'h71;
+          8'h2d: d=8'hd8;
+          8'h2e: d=8'h31;
+          8'h2f: d=8'h15;
+          8'h30: d=8'h04;
+          8'h31: d=8'hc7;
+          8'h32: d=8'h23;
+          8'h33: d=8'hc3;
+          8'h34: d=8'h18;
+          8'h35: d=8'h96;
+          8'h36: d=8'h05;
+          8'h37: d=8'h9a;
+          8'h38: d=8'h07;
+          8'h39: d=8'h12;
+          8'h3a: d=8'h80;
+          8'h3b: d=8'he2;
+          8'h3c: d=8'heb;
+          8'h3d: d=8'h27;
+          8'h3e: d=8'hb2;
+          8'h3f: d=8'h75;
+          8'h40: d=8'h09;
+          8'h41: d=8'h83;
+          8'h42: d=8'h2c;
+          8'h43: d=8'h1a;
+          8'h44: d=8'h1b;
+          8'h45: d=8'h6e;
+          8'h46: d=8'h5a;
+          8'h47: d=8'ha0;
+          8'h48: d=8'h52;
+          8'h49: d=8'h3b;
+          8'h4a: d=8'hd6;
+          8'h4b: d=8'hb3;
+          8'h4c: d=8'h29;
+          8'h4d: d=8'he3;
+          8'h4e: d=8'h2f;
+          8'h4f: d=8'h84;
+          8'h50: d=8'h53;
+          8'h51: d=8'hd1;
+          8'h52: d=8'h00;
+          8'h53: d=8'hed;
+          8'h54: d=8'h20;
+          8'h55: d=8'hfc;
+          8'h56: d=8'hb1;
+          8'h57: d=8'h5b;
+          8'h58: d=8'h6a;
+          8'h59: d=8'hcb;
+          8'h5a: d=8'hbe;
+          8'h5b: d=8'h39;
+          8'h5c: d=8'h4a;
+          8'h5d: d=8'h4c;
+          8'h5e: d=8'h58;
+          8'h5f: d=8'hcf;
+          8'h60: d=8'hd0;
+          8'h61: d=8'hef;
+          8'h62: d=8'haa;
+          8'h63: d=8'hfb;
+          8'h64: d=8'h43;
+          8'h65: d=8'h4d;
+          8'h66: d=8'h33;
+          8'h67: d=8'h85;
+          8'h68: d=8'h45;
+          8'h69: d=8'hf9;
+          8'h6a: d=8'h02;
+          8'h6b: d=8'h7f;
+          8'h6c: d=8'h50;
+          8'h6d: d=8'h3c;
+          8'h6e: d=8'h9f;
+          8'h6f: d=8'ha8;
+          8'h70: d=8'h51;
+          8'h71: d=8'ha3;
+          8'h72: d=8'h40;
+          8'h73: d=8'h8f;
+          8'h74: d=8'h92;
+          8'h75: d=8'h9d;
+          8'h76: d=8'h38;
+          8'h77: d=8'hf5;
+          8'h78: d=8'hbc;
+          8'h79: d=8'hb6;
+          8'h7a: d=8'hda;
+          8'h7b: d=8'h21;
+          8'h7c: d=8'h10;
+          8'h7d: d=8'hff;
+          8'h7e: d=8'hf3;
+          8'h7f: d=8'hd2;
+          8'h80: d=8'hcd;
+          8'h81: d=8'h0c;
+          8'h82: d=8'h13;
+          8'h83: d=8'hec;
+          8'h84: d=8'h5f;
+          8'h85: d=8'h97;
+          8'h86: d=8'h44;
+          8'h87: d=8'h17;
+          8'h88: d=8'hc4;
+          8'h89: d=8'ha7;
+          8'h8a: d=8'h7e;
+          8'h8b: d=8'h3d;
+          8'h8c: d=8'h64;
+          8'h8d: d=8'h5d;
+          8'h8e: d=8'h19;
+          8'h8f: d=8'h73;
+          8'h90: d=8'h60;
+          8'h91: d=8'h81;
+          8'h92: d=8'h4f;
+          8'h93: d=8'hdc;
+          8'h94: d=8'h22;
+          8'h95: d=8'h2a;
+          8'h96: d=8'h90;
+          8'h97: d=8'h88;
+          8'h98: d=8'h46;
+          8'h99: d=8'hee;
+          8'h9a: d=8'hb8;
+          8'h9b: d=8'h14;
+          8'h9c: d=8'hde;
+          8'h9d: d=8'h5e;
+          8'h9e: d=8'h0b;
+          8'h9f: d=8'hdb;
+          8'ha0: d=8'he0;
+          8'ha1: d=8'h32;
+          8'ha2: d=8'h3a;
+          8'ha3: d=8'h0a;
+          8'ha4: d=8'h49;
+          8'ha5: d=8'h06;
+          8'ha6: d=8'h24;
+          8'ha7: d=8'h5c;
+          8'ha8: d=8'hc2;
+          8'ha9: d=8'hd3;
+          8'haa: d=8'hac;
+          8'hab: d=8'h62;
+          8'hac: d=8'h91;
+          8'had: d=8'h95;
+          8'hae: d=8'he4;
+          8'haf: d=8'h79;
+          8'hb0: d=8'he7;
+          8'hb1: d=8'hc8;
+          8'hb2: d=8'h37;
+          8'hb3: d=8'h6d;
+          8'hb4: d=8'h8d;
+          8'hb5: d=8'hd5;
+          8'hb6: d=8'h4e;
+          8'hb7: d=8'ha9;
+          8'hb8: d=8'h6c;
+          8'hb9: d=8'h56;
+          8'hba: d=8'hf4;
+          8'hbb: d=8'hea;
+          8'hbc: d=8'h65;
+          8'hbd: d=8'h7a;
+          8'hbe: d=8'hae;
+          8'hbf: d=8'h08;
+          8'hc0: d=8'hba;
+          8'hc1: d=8'h78;
+          8'hc2: d=8'h25;
+          8'hc3: d=8'h2e;
+          8'hc4: d=8'h1c;
+          8'hc5: d=8'ha6;
+          8'hc6: d=8'hb4;
+          8'hc7: d=8'hc6;
+          8'hc8: d=8'he8;
+          8'hc9: d=8'hdd;
+          8'hca: d=8'h74;
+          8'hcb: d=8'h1f;
+          8'hcc: d=8'h4b;
+          8'hcd: d=8'hbd;
+          8'hce: d=8'h8b;
+          8'hcf: d=8'h8a;
+          8'hd0: d=8'h70;
+          8'hd1: d=8'h3e;
+          8'hd2: d=8'hb5;
+          8'hd3: d=8'h66;
+          8'hd4: d=8'h48;
+          8'hd5: d=8'h03;
+          8'hd6: d=8'hf6;
+          8'hd7: d=8'h0e;
+          8'hd8: d=8'h61;
+          8'hd9: d=8'h35;
+          8'hda: d=8'h57;
+          8'hdb: d=8'hb9;
+          8'hdc: d=8'h86;
+          8'hdd: d=8'hc1;
+          8'hde: d=8'h1d;
+          8'hdf: d=8'h9e;
+          8'he0: d=8'he1;
+          8'he1: d=8'hf8;
+          8'he2: d=8'h98;
+          8'he3: d=8'h11;
+          8'he4: d=8'h69;
+          8'he5: d=8'hd9;
+          8'he6: d=8'h8e;
+          8'he7: d=8'h94;
+          8'he8: d=8'h9b;
+          8'he9: d=8'h1e;
+          8'hea: d=8'h87;
+          8'heb: d=8'he9;
+          8'hec: d=8'hce;
+          8'hed: d=8'h55;
+          8'hee: d=8'h28;
+          8'hef: d=8'hdf;
+          8'hf0: d=8'h8c;
+          8'hf1: d=8'ha1;
+          8'hf2: d=8'h89;
+          8'hf3: d=8'h0d;
+          8'hf4: d=8'hbf;
+          8'hf5: d=8'he6;
+          8'hf6: d=8'h42;
+          8'hf7: d=8'h68;
+          8'hf8: d=8'h41;
+          8'hf9: d=8'h99;
+          8'hfa: d=8'h2d;
+          8'hfb: d=8'h0f;
+          8'hfc: d=8'hb0;
+          8'hfd: d=8'h54;
+          8'hfe: d=8'hbb;
+          8'hff: d=8'h16;
+       endcase
+
+endmodule
+
+
diff --git a/tests/iwls2005/aes_core/timescale.v b/tests/iwls2005/aes_core/timescale.v
new file mode 100644 (file)
index 0000000..ff9e265
--- /dev/null
@@ -0,0 +1 @@
+`timescale 1ns / 10ps
diff --git a/tests/iwls2005/fpu/except.v b/tests/iwls2005/fpu/except.v
new file mode 100644 (file)
index 0000000..007099f
--- /dev/null
@@ -0,0 +1,153 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  EXCEPT                                                     ////
+////  Floating Point Exception/Special Numbers Unit              ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000 Rudolf Usselmann                         ////
+////                    rudi@asics.ws                            ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+
+`timescale 1ns / 100ps
+
+
+module except( clk, opa, opb, inf, ind, qnan, snan, opa_nan, opb_nan,
+               opa_00, opb_00, opa_inf, opb_inf, opa_dn, opb_dn);
+input          clk;
+input  [31:0]  opa, opb;
+output         inf, ind, qnan, snan, opa_nan, opb_nan;
+output         opa_00, opb_00;
+output         opa_inf, opb_inf;
+output         opa_dn;
+output         opb_dn;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Local Wires and registers
+//
+
+wire   [7:0]   expa, expb;             // alias to opX exponent
+wire   [22:0]  fracta, fractb;         // alias to opX fraction
+reg            expa_ff, infa_f_r, qnan_r_a, snan_r_a;
+reg            expb_ff, infb_f_r, qnan_r_b, snan_r_b;
+reg            inf, ind, qnan, snan;   // Output registers
+reg            opa_nan, opb_nan;
+reg            expa_00, expb_00, fracta_00, fractb_00;
+reg            opa_00, opb_00;
+reg            opa_inf, opb_inf;
+reg            opa_dn, opb_dn;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Aliases
+//
+
+assign   expa = opa[30:23];
+assign   expb = opb[30:23];
+assign fracta = opa[22:0];
+assign fractb = opb[22:0];
+
+////////////////////////////////////////////////////////////////////////
+//
+// Determine if any of the input operators is a INF or NAN or any other special number
+//
+
+always @(posedge clk)
+       expa_ff <= #1 &expa;
+
+always @(posedge clk)
+       expb_ff <= #1 &expb;
+       
+always @(posedge clk)
+       infa_f_r <= #1 !(|fracta);
+
+always @(posedge clk)
+       infb_f_r <= #1 !(|fractb);
+
+always @(posedge clk)
+       qnan_r_a <= #1  fracta[22];
+
+always @(posedge clk)
+       snan_r_a <= #1 !fracta[22] & |fracta[21:0];
+       
+always @(posedge clk)
+       qnan_r_b <= #1  fractb[22];
+
+always @(posedge clk)
+       snan_r_b <= #1 !fractb[22] & |fractb[21:0];
+
+always @(posedge clk)
+       ind  <= #1 (expa_ff & infa_f_r) & (expb_ff & infb_f_r);
+
+always @(posedge clk)
+       inf  <= #1 (expa_ff & infa_f_r) | (expb_ff & infb_f_r);
+
+always @(posedge clk)
+       qnan <= #1 (expa_ff & qnan_r_a) | (expb_ff & qnan_r_b);
+
+always @(posedge clk)
+       snan <= #1 (expa_ff & snan_r_a) | (expb_ff & snan_r_b);
+
+always @(posedge clk)
+       opa_nan <= #1 &expa & (|fracta[22:0]);
+
+always @(posedge clk)
+       opb_nan <= #1 &expb & (|fractb[22:0]);
+
+always @(posedge clk)
+       opa_inf <= #1 (expa_ff & infa_f_r);
+
+always @(posedge clk)
+       opb_inf <= #1 (expb_ff & infb_f_r);
+
+always @(posedge clk)
+       expa_00 <= #1 !(|expa);
+
+always @(posedge clk)
+       expb_00 <= #1 !(|expb);
+
+always @(posedge clk)
+       fracta_00 <= #1 !(|fracta);
+
+always @(posedge clk)
+       fractb_00 <= #1 !(|fractb);
+
+always @(posedge clk)
+       opa_00 <= #1 expa_00 & fracta_00;
+
+always @(posedge clk)
+       opb_00 <= #1 expb_00 & fractb_00;
+
+always @(posedge clk)
+       opa_dn <= #1 expa_00;
+
+always @(posedge clk)
+       opb_dn <= #1 expb_00;
+
+endmodule
+
diff --git a/tests/iwls2005/fpu/fpu.v b/tests/iwls2005/fpu/fpu.v
new file mode 100644 (file)
index 0000000..165a1d2
--- /dev/null
@@ -0,0 +1,560 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  FPU                                                        ////
+////  Floating Point Unit (Single precision)                     ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000 Rudolf Usselmann                         ////
+////                    rudi@asics.ws                            ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+`timescale 1ns / 100ps
+
+/*
+
+FPU Operations (fpu_op):
+========================
+
+0 = add
+1 = sub
+2 = mul
+3 = div
+4 =
+5 =
+6 =
+7 =
+
+Rounding Modes (rmode):
+=======================
+
+0 = round_nearest_even
+1 = round_to_zero
+2 = round_up
+3 = round_down
+
+*/
+
+
+module fpu( clk, rmode, fpu_op, opa, opb, out, inf, snan, qnan, ine, overflow, underflow, zero, div_by_zero);
+input          clk;
+input  [1:0]   rmode;
+input  [2:0]   fpu_op;
+input  [31:0]  opa, opb;
+output [31:0]  out;
+output         inf, snan, qnan;
+output         ine;
+output         overflow, underflow;
+output         zero;
+output         div_by_zero;
+
+parameter      INF  = 31'h7f800000,
+               QNAN = 31'h7fc00001,
+               SNAN = 31'h7f800001;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Local Wires
+//
+reg            zero;
+reg    [31:0]  opa_r, opb_r;           // Input operand registers
+reg    [31:0]  out;                    // Output register
+reg            div_by_zero;            // Divide by zero output register
+wire           signa, signb;           // alias to opX sign
+wire           sign_fasu;              // sign output
+wire   [26:0]  fracta, fractb;         // Fraction Outputs from EQU block
+wire   [7:0]   exp_fasu;               // Exponent output from EQU block
+reg    [7:0]   exp_r;                  // Exponent output (registerd)
+wire   [26:0]  fract_out_d;            // fraction output
+wire           co;                     // carry output
+reg    [27:0]  fract_out_q;            // fraction output (registerd)
+wire   [30:0]  out_d;                  // Intermediate final result output
+wire           overflow_d, underflow_d;// Overflow/Underflow Indicators
+reg            overflow, underflow;    // Output registers for Overflow & Underflow
+reg            inf, snan, qnan;        // Output Registers for INF, SNAN and QNAN
+reg            ine;                    // Output Registers for INE
+reg    [1:0]   rmode_r1, rmode_r2,     // Pipeline registers for rounding mode
+               rmode_r3;
+reg    [2:0]   fpu_op_r1, fpu_op_r2,   // Pipeline registers for fp opration
+               fpu_op_r3;
+wire           mul_inf, div_inf;
+wire           mul_00, div_00;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Input Registers
+//
+
+always @(posedge clk)
+       opa_r <= #1 opa;
+
+always @(posedge clk)
+       opb_r <= #1 opb;
+
+always @(posedge clk)
+       rmode_r1 <= #1 rmode;
+
+always @(posedge clk)
+       rmode_r2 <= #1 rmode_r1;
+
+always @(posedge clk)
+       rmode_r3 <= #1 rmode_r2;
+
+always @(posedge clk)
+       fpu_op_r1 <= #1 fpu_op;
+
+always @(posedge clk)
+       fpu_op_r2 <= #1 fpu_op_r1;
+
+always @(posedge clk)
+       fpu_op_r3 <= #1 fpu_op_r2;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Exceptions block
+//
+wire           inf_d, ind_d, qnan_d, snan_d, opa_nan, opb_nan;
+wire           opa_00, opb_00;
+wire           opa_inf, opb_inf;
+wire           opa_dn, opb_dn;
+
+except u0(     .clk(clk),
+               .opa(opa_r), .opb(opb_r),
+               .inf(inf_d), .ind(ind_d),
+               .qnan(qnan_d), .snan(snan_d),
+               .opa_nan(opa_nan), .opb_nan(opb_nan),
+               .opa_00(opa_00), .opb_00(opb_00),
+               .opa_inf(opa_inf), .opb_inf(opb_inf),
+               .opa_dn(opa_dn), .opb_dn(opb_dn)
+               );
+
+////////////////////////////////////////////////////////////////////////
+//
+// Pre-Normalize block
+// - Adjusts the numbers to equal exponents and sorts them
+// - determine result sign
+// - determine actual operation to perform (add or sub)
+//
+
+wire           nan_sign_d, result_zero_sign_d;
+reg            sign_fasu_r;
+wire   [7:0]   exp_mul;
+wire           sign_mul;
+reg            sign_mul_r;
+wire   [23:0]  fracta_mul, fractb_mul;
+wire           inf_mul;
+reg            inf_mul_r;
+wire   [1:0]   exp_ovf;
+reg    [1:0]   exp_ovf_r;
+wire           sign_exe;
+reg            sign_exe_r;
+wire   [2:0]   underflow_fmul_d;
+
+
+pre_norm u1(.clk(clk),                         // System Clock
+       .rmode(rmode_r2),                       // Roundin Mode
+       .add(!fpu_op_r1[0]),                    // Add/Sub Input
+       .opa(opa_r),  .opb(opb_r),              // Registered OP Inputs
+       .opa_nan(opa_nan),                      // OpA is a NAN indicator
+       .opb_nan(opb_nan),                      // OpB is a NAN indicator
+       .fracta_out(fracta),                    // Equalized and sorted fraction
+       .fractb_out(fractb),                    // outputs (Registered)
+       .exp_dn_out(exp_fasu),                  // Selected exponent output (registered);
+       .sign(sign_fasu),                       // Encoded output Sign (registered)
+       .nan_sign(nan_sign_d),                  // Output Sign for NANs (registered)
+       .result_zero_sign(result_zero_sign_d),  // Output Sign for zero result (registered)
+       .fasu_op(fasu_op)                       // Actual fasu operation output (registered)
+       );
+
+always @(posedge clk)
+       sign_fasu_r <= #1 sign_fasu;
+
+pre_norm_fmul u2(
+               .clk(clk),
+               .fpu_op(fpu_op_r1),
+               .opa(opa_r), .opb(opb_r),
+               .fracta(fracta_mul),
+               .fractb(fractb_mul),
+               .exp_out(exp_mul),      // FMUL exponent output (registered)
+               .sign(sign_mul),        // FMUL sign output (registered)
+               .sign_exe(sign_exe),    // FMUL exception sign output (registered)
+               .inf(inf_mul),          // FMUL inf output (registered)
+               .exp_ovf(exp_ovf),      // FMUL exponnent overflow output (registered)
+               .underflow(underflow_fmul_d)
+               );
+
+
+always @(posedge clk)
+       sign_mul_r <= #1 sign_mul;
+
+always @(posedge clk)
+       sign_exe_r <= #1 sign_exe;
+
+always @(posedge clk)
+       inf_mul_r <= #1 inf_mul;
+
+always @(posedge clk)
+       exp_ovf_r <= #1 exp_ovf;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Add/Sub
+//
+
+add_sub27 u3(
+       .add(fasu_op),                  // Add/Sub
+       .opa(fracta),                   // Fraction A input
+       .opb(fractb),                   // Fraction B Input
+       .sum(fract_out_d),              // SUM output
+       .co(co_d) );                    // Carry Output
+
+always @(posedge clk)
+       fract_out_q <= #1 {co_d, fract_out_d};
+
+////////////////////////////////////////////////////////////////////////
+//
+// Mul
+//
+wire   [47:0]  prod;
+
+mul_r2 u5(.clk(clk), .opa(fracta_mul), .opb(fractb_mul), .prod(prod));
+
+////////////////////////////////////////////////////////////////////////
+//
+// Divide
+//
+wire   [49:0]  quo;
+wire   [49:0]  fdiv_opa;
+wire   [49:0]  remainder;
+wire           remainder_00;
+reg    [4:0]   div_opa_ldz_d, div_opa_ldz_r1, div_opa_ldz_r2;
+
+always @(fracta_mul)
+       casex(fracta_mul[22:0])
+          23'b1??????????????????????: div_opa_ldz_d = 1;
+          23'b01?????????????????????: div_opa_ldz_d = 2;
+          23'b001????????????????????: div_opa_ldz_d = 3;
+          23'b0001???????????????????: div_opa_ldz_d = 4;
+          23'b00001??????????????????: div_opa_ldz_d = 5;
+          23'b000001?????????????????: div_opa_ldz_d = 6;
+          23'b0000001????????????????: div_opa_ldz_d = 7;
+          23'b00000001???????????????: div_opa_ldz_d = 8;
+          23'b000000001??????????????: div_opa_ldz_d = 9;
+          23'b0000000001?????????????: div_opa_ldz_d = 10;
+          23'b00000000001????????????: div_opa_ldz_d = 11;
+          23'b000000000001???????????: div_opa_ldz_d = 12;
+          23'b0000000000001??????????: div_opa_ldz_d = 13;
+          23'b00000000000001?????????: div_opa_ldz_d = 14;
+          23'b000000000000001????????: div_opa_ldz_d = 15;
+          23'b0000000000000001???????: div_opa_ldz_d = 16;
+          23'b00000000000000001??????: div_opa_ldz_d = 17;
+          23'b000000000000000001?????: div_opa_ldz_d = 18;
+          23'b0000000000000000001????: div_opa_ldz_d = 19;
+          23'b00000000000000000001???: div_opa_ldz_d = 20;
+          23'b000000000000000000001??: div_opa_ldz_d = 21;
+          23'b0000000000000000000001?: div_opa_ldz_d = 22;
+          23'b0000000000000000000000?: div_opa_ldz_d = 23;
+       endcase
+
+assign fdiv_opa = !(|opa_r[30:23]) ? {(fracta_mul<<div_opa_ldz_d), 26'h0} : {fracta_mul, 26'h0};
+
+
+div_r2 u6(.clk(clk), .opa(fdiv_opa), .opb(fractb_mul), .quo(quo), .rem(remainder));
+
+assign remainder_00 = !(|remainder);
+
+always @(posedge clk)
+       div_opa_ldz_r1 <= #1 div_opa_ldz_d;
+
+always @(posedge clk)
+       div_opa_ldz_r2 <= #1 div_opa_ldz_r1;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Normalize Result
+//
+wire           ine_d;
+reg    [47:0]  fract_denorm;
+wire   [47:0]  fract_div;
+wire           sign_d;
+reg            sign;
+reg    [30:0]  opa_r1;
+reg    [47:0]  fract_i2f;
+reg            opas_r1, opas_r2;
+wire           f2i_out_sign;
+
+always @(posedge clk)                  // Exponent must be once cycle delayed
+       case(fpu_op_r2)
+         0,1:  exp_r <= #1 exp_fasu;
+         2,3:  exp_r <= #1 exp_mul;
+         4:    exp_r <= #1 0;
+         5:    exp_r <= #1 opa_r1[30:23];
+       endcase
+
+assign fract_div = (opb_dn ? quo[49:2] : {quo[26:0], 21'h0});
+
+always @(posedge clk)
+       opa_r1 <= #1 opa_r[30:0];
+
+always @(posedge clk)
+       fract_i2f <= #1 (fpu_op_r2==5) ?
+                       (sign_d ?  1-{24'h00, (|opa_r1[30:23]), opa_r1[22:0]}-1 : {24'h0, (|opa_r1[30:23]), opa_r1[22:0]}) :
+                       (sign_d ? 1 - {opa_r1, 17'h01} : {opa_r1, 17'h0});
+
+always @(fpu_op_r3 or fract_out_q or prod or fract_div or fract_i2f)
+       case(fpu_op_r3)
+          0,1: fract_denorm = {fract_out_q, 20'h0};
+          2:   fract_denorm = prod;
+          3:   fract_denorm = fract_div;
+          4,5: fract_denorm = fract_i2f;
+       endcase
+
+
+always @(posedge clk)
+       opas_r1 <= #1 opa_r[31];
+
+always @(posedge clk)
+       opas_r2 <= #1 opas_r1;
+
+assign sign_d = fpu_op_r2[1] ? sign_mul : sign_fasu;
+
+always @(posedge clk)
+       sign <= #1 (rmode_r2==2'h3) ? !sign_d : sign_d;
+
+post_norm u4(.clk(clk),                        // System Clock
+       .fpu_op(fpu_op_r3),             // Floating Point Operation
+       .opas(opas_r2),                 // OPA Sign
+       .sign(sign),                    // Sign of the result
+       .rmode(rmode_r3),               // Rounding mode
+       .fract_in(fract_denorm),        // Fraction Input
+       .exp_ovf(exp_ovf_r),            // Exponent Overflow
+       .exp_in(exp_r),                 // Exponent Input
+       .opa_dn(opa_dn),                // Operand A Denormalized
+       .opb_dn(opb_dn),                // Operand A Denormalized
+       .rem_00(remainder_00),          // Diveide Remainder is zero
+       .div_opa_ldz(div_opa_ldz_r2),   // Divide opa leading zeros count
+       .output_zero(mul_00 | div_00),  // Force output to Zero
+       .out(out_d),                    // Normalized output (un-registered)
+       .ine(ine_d),                    // Result Inexact output (un-registered)
+       .overflow(overflow_d),          // Overflow output (un-registered)
+       .underflow(underflow_d),        // Underflow output (un-registered)
+       .f2i_out_sign(f2i_out_sign)     // F2I Output Sign
+       );
+
+////////////////////////////////////////////////////////////////////////
+//
+// FPU Outputs
+//
+reg            fasu_op_r1, fasu_op_r2;
+wire   [30:0]  out_fixed;
+wire           output_zero_fasu;
+wire           output_zero_fdiv;
+wire           output_zero_fmul;
+reg            inf_mul2;
+wire           overflow_fasu;
+wire           overflow_fmul;
+wire           overflow_fdiv;
+wire           inf_fmul;
+wire           sign_mul_final;
+wire           out_d_00;
+wire           sign_div_final;
+wire           ine_mul, ine_mula, ine_div, ine_fasu;
+wire           underflow_fasu, underflow_fmul, underflow_fdiv;
+wire           underflow_fmul1;
+reg    [2:0]   underflow_fmul_r;
+reg            opa_nan_r;
+
+
+always @(posedge clk)
+       fasu_op_r1 <= #1 fasu_op;
+
+always @(posedge clk)
+       fasu_op_r2 <= #1 fasu_op_r1;
+
+always @(posedge clk)
+       inf_mul2 <= #1 exp_mul == 8'hff;
+
+
+// Force pre-set values for non numerical output
+assign mul_inf = (fpu_op_r3==3'b010) & (inf_mul_r | inf_mul2) & (rmode_r3==2'h0);
+assign div_inf = (fpu_op_r3==3'b011) & (opb_00 | opa_inf);
+
+assign mul_00 = (fpu_op_r3==3'b010) & (opa_00 | opb_00);
+assign div_00 = (fpu_op_r3==3'b011) & (opa_00 | opb_inf);
+
+assign out_fixed = (   (qnan_d | snan_d) |
+                       (ind_d & !fasu_op_r2) | 
+                       ((fpu_op_r3==3'b011) & opb_00 & opa_00) |
+                       (((opa_inf & opb_00) | (opb_inf & opa_00 )) & fpu_op_r3==3'b010)
+                  )  ? QNAN : INF;
+
+always @(posedge clk)
+       out[30:0] <= #1 (mul_inf | div_inf | (inf_d & (fpu_op_r3!=3'b011) & (fpu_op_r3!=3'b101)) | snan_d | qnan_d) & fpu_op_r3!=3'b100 ? out_fixed :
+                       out_d;
+
+assign out_d_00 = !(|out_d);
+
+assign sign_mul_final = (sign_exe_r & ((opa_00 & opb_inf) | (opb_00 & opa_inf))) ? !sign_mul_r : sign_mul_r;
+assign sign_div_final = (sign_exe_r & (opa_inf & opb_inf)) ? !sign_mul_r : sign_mul_r | (opa_00 & opb_00);
+
+always @(posedge clk)
+       out[31] <= #1   ((fpu_op_r3==3'b101) & out_d_00) ? (f2i_out_sign & !(qnan_d | snan_d) ) :
+                       ((fpu_op_r3==3'b010) & !(snan_d | qnan_d)) ?    sign_mul_final :
+                       ((fpu_op_r3==3'b011) & !(snan_d | qnan_d)) ?    sign_div_final :
+                       (snan_d | qnan_d | ind_d) ?                     nan_sign_d :
+                       output_zero_fasu ?                              result_zero_sign_d :
+                                                                       sign_fasu_r;
+
+// Exception Outputs
+assign ine_mula = ((inf_mul_r |  inf_mul2 | opa_inf | opb_inf) & (rmode_r3==2'h1) & 
+               !((opa_inf & opb_00) | (opb_inf & opa_00 )) & fpu_op_r3[1]);
+
+assign ine_mul  = (ine_mula | ine_d | inf_fmul | out_d_00 | overflow_d | underflow_d) &
+                 !opa_00 & !opb_00 & !(snan_d | qnan_d | inf_d);
+assign ine_div  = (ine_d | overflow_d | underflow_d) & !(opb_00 | snan_d | qnan_d | inf_d);
+assign ine_fasu = (ine_d | overflow_d | underflow_d) & !(snan_d | qnan_d | inf_d);
+
+always @(posedge  clk)
+       ine <= #1        fpu_op_r3[2] ? ine_d :
+                       !fpu_op_r3[1] ? ine_fasu :
+                        fpu_op_r3[0] ? ine_div  : ine_mul;
+
+
+assign overflow_fasu = overflow_d & !(snan_d | qnan_d | inf_d);
+assign overflow_fmul = !inf_d & (inf_mul_r | inf_mul2 | overflow_d) & !(snan_d | qnan_d);
+assign overflow_fdiv = (overflow_d & !(opb_00 | inf_d | snan_d | qnan_d));
+
+always @(posedge clk)
+       overflow <= #1   fpu_op_r3[2] ? 0 :
+                       !fpu_op_r3[1] ? overflow_fasu :
+                        fpu_op_r3[0] ? overflow_fdiv : overflow_fmul;
+
+always @(posedge clk)
+       underflow_fmul_r <= #1 underflow_fmul_d;
+
+
+assign underflow_fmul1 = underflow_fmul_r[0] |
+                       (underflow_fmul_r[1] & underflow_d ) |
+                       ((opa_dn | opb_dn) & out_d_00 & (prod!=0) & sign) |
+                       (underflow_fmul_r[2] & ((out_d[30:23]==0) | (out_d[22:0]==0)));
+
+assign underflow_fasu = underflow_d & !(inf_d | snan_d | qnan_d);
+assign underflow_fmul = underflow_fmul1 & !(snan_d | qnan_d | inf_mul_r);
+assign underflow_fdiv = underflow_fasu & !opb_00;
+
+always @(posedge clk)
+       underflow <= #1  fpu_op_r3[2] ? 0 :
+                       !fpu_op_r3[1] ? underflow_fasu :
+                        fpu_op_r3[0] ? underflow_fdiv : underflow_fmul;
+
+always @(posedge clk)
+       snan <= #1 snan_d;
+
+// synopsys translate_off
+wire           mul_uf_del;
+wire           uf2_del, ufb2_del, ufc2_del,  underflow_d_del;
+wire           co_del;
+wire   [30:0]  out_d_del;
+wire           ov_fasu_del, ov_fmul_del;
+wire   [2:0]   fop;
+wire   [4:0]   ldza_del;
+wire   [49:0]  quo_del;
+
+delay1  #0 ud000(clk, underflow_fmul1, mul_uf_del);
+delay1  #0 ud001(clk, underflow_fmul_r[0], uf2_del);
+delay1  #0 ud002(clk, underflow_fmul_r[1], ufb2_del);
+delay1  #0 ud003(clk, underflow_d, underflow_d_del);
+delay1  #0 ud004(clk, test.u0.u4.exp_out1_co, co_del);
+delay1  #0 ud005(clk, underflow_fmul_r[2], ufc2_del);
+delay1 #30 ud006(clk, out_d, out_d_del);
+
+delay1  #0 ud007(clk, overflow_fasu, ov_fasu_del);
+delay1  #0 ud008(clk, overflow_fmul, ov_fmul_del);
+
+delay1  #2 ud009(clk, fpu_op_r3, fop);
+
+delay3  #4 ud010(clk, div_opa_ldz_d, ldza_del);
+
+delay1  #49 ud012(clk, quo, quo_del);
+
+always @(test.error_event)
+   begin
+       #0.2
+       $display("muf: %b uf0: %b uf1: %b uf2: %b, tx0: %b, co: %b, out_d: %h (%h %h), ov_fasu: %b, ov_fmul: %b, fop: %h",
+                       mul_uf_del, uf2_del, ufb2_del, ufc2_del, underflow_d_del, co_del, out_d_del, out_d_del[30:23], out_d_del[22:0],
+                       ov_fasu_del, ov_fmul_del, fop );
+       $display("ldza: %h, quo: %b",
+                       ldza_del, quo_del);
+   end
+// synopsys translate_on
+
+
+
+// Status Outputs
+always @(posedge clk)
+       qnan <= #1      fpu_op_r3[2] ? 0 : (
+                                               snan_d | qnan_d | (ind_d & !fasu_op_r2) |
+                                               (opa_00 & opb_00 & fpu_op_r3==3'b011) |
+                                               (((opa_inf & opb_00) | (opb_inf & opa_00 )) & fpu_op_r3==3'b010)
+                                          );
+
+assign inf_fmul =      (((inf_mul_r | inf_mul2) & (rmode_r3==2'h0)) | opa_inf | opb_inf) & 
+                       !((opa_inf & opb_00) | (opb_inf & opa_00 )) &
+                       fpu_op_r3==3'b010;
+
+always @(posedge clk)
+       inf <= #1       fpu_op_r3[2] ? 0 :
+                       (!(qnan_d | snan_d) & (
+                                               ((&out_d[30:23]) & !(|out_d[22:0]) & !(opb_00 & fpu_op_r3==3'b011)) |
+                                               (inf_d & !(ind_d & !fasu_op_r2) & !fpu_op_r3[1]) |
+                                               inf_fmul |
+                                               (!opa_00 & opb_00 & fpu_op_r3==3'b011) |
+                                               (fpu_op_r3==3'b011 & opa_inf & !opb_inf)
+                                             )
+                       );
+
+assign output_zero_fasu = out_d_00 & !(inf_d | snan_d | qnan_d);
+assign output_zero_fdiv = (div_00 | (out_d_00 & !opb_00)) & !(opa_inf & opb_inf) &
+                         !(opa_00 & opb_00) & !(qnan_d | snan_d);
+assign output_zero_fmul = (out_d_00 | opa_00 | opb_00) &
+                         !(inf_mul_r | inf_mul2 | opa_inf | opb_inf | snan_d | qnan_d) &
+                         !(opa_inf & opb_00) & !(opb_inf & opa_00);
+
+always @(posedge clk)
+       zero <= #1      fpu_op_r3==3'b101 ?     out_d_00 & !(snan_d | qnan_d):
+                       fpu_op_r3==3'b011 ?     output_zero_fdiv :
+                       fpu_op_r3==3'b010 ?     output_zero_fmul :
+                                               output_zero_fasu ;
+
+always @(posedge clk)
+       opa_nan_r <= #1 !opa_nan & fpu_op_r2==3'b011;
+
+always @(posedge clk)
+       div_by_zero <= #1 opa_nan_r & !opa_00 & !opa_inf & opb_00;
+
+endmodule
diff --git a/tests/iwls2005/fpu/post_norm.v b/tests/iwls2005/fpu/post_norm.v
new file mode 100644 (file)
index 0000000..ff9cf6f
--- /dev/null
@@ -0,0 +1,676 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  Post Norm                                                  ////
+////  Floating Point Post Normalisation Unit                     ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000 Rudolf Usselmann                         ////
+////                    rudi@asics.ws                            ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+
+`timescale 1ns / 100ps
+
+module post_norm( clk, fpu_op, opas, sign, rmode, fract_in, exp_in, exp_ovf,
+               opa_dn, opb_dn, rem_00, div_opa_ldz, output_zero, out,
+               ine, overflow, underflow, f2i_out_sign);
+input          clk;
+input  [2:0]   fpu_op;
+input          opas;
+input          sign;
+input  [1:0]   rmode;
+input  [47:0]  fract_in;
+input  [1:0]   exp_ovf;
+input  [7:0]   exp_in;
+input          opa_dn, opb_dn;
+input          rem_00;
+input  [4:0]   div_opa_ldz;
+input          output_zero;
+output [30:0]  out;
+output         ine;
+output         overflow, underflow;
+output         f2i_out_sign;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Local Wires and registers
+//
+
+wire   [22:0]  fract_out;
+wire   [7:0]   exp_out;
+wire   [30:0]  out;
+wire           exp_out1_co, overflow, underflow;
+wire   [22:0]  fract_out_final;
+reg    [22:0]  fract_out_rnd;
+wire   [8:0]   exp_next_mi;
+wire           dn;
+wire           exp_rnd_adj;
+wire   [7:0]   exp_out_final;
+reg    [7:0]   exp_out_rnd;
+wire           op_dn = opa_dn | opb_dn;
+wire           op_mul = fpu_op[2:0]==3'b010;
+wire           op_div = fpu_op[2:0]==3'b011;
+wire           op_i2f = fpu_op[2:0]==3'b100;
+wire           op_f2i = fpu_op[2:0]==3'b101;
+reg    [5:0]   fi_ldz;
+
+wire           g, r, s;
+wire           round, round2, round2a, round2_fasu, round2_fmul;
+wire   [7:0]   exp_out_rnd0, exp_out_rnd1, exp_out_rnd2, exp_out_rnd2a;
+wire   [22:0]  fract_out_rnd0, fract_out_rnd1, fract_out_rnd2, fract_out_rnd2a;
+wire           exp_rnd_adj0, exp_rnd_adj2a;
+wire           r_sign;
+wire           ovf0, ovf1;
+wire   [23:0]  fract_out_pl1;
+wire   [7:0]   exp_out_pl1, exp_out_mi1;
+wire           exp_out_00, exp_out_fe, exp_out_ff, exp_in_00, exp_in_ff;
+wire           exp_out_final_ff, fract_out_7fffff;
+wire   [24:0]  fract_trunc;
+wire   [7:0]   exp_out1;
+wire           grs_sel;
+wire           fract_out_00, fract_in_00;
+wire           shft_co;
+wire   [8:0]   exp_in_pl1, exp_in_mi1;
+wire   [47:0]  fract_in_shftr;
+wire   [47:0]  fract_in_shftl;
+
+wire   [7:0]   exp_div;
+wire   [7:0]   shft2;
+wire   [7:0]   exp_out1_mi1;
+wire           div_dn;
+wire           div_nr;
+wire           grs_sel_div;
+
+wire           div_inf;
+wire   [6:0]   fi_ldz_2a;
+wire   [7:0]   fi_ldz_2;
+wire   [7:0]   div_shft1, div_shft2, div_shft3, div_shft4;
+wire           div_shft1_co;
+wire   [8:0]   div_exp1;
+wire   [7:0]   div_exp2, div_exp3;
+wire           left_right, lr_mul, lr_div;
+wire   [7:0]   shift_right, shftr_mul, shftr_div;
+wire   [7:0]   shift_left,  shftl_mul, shftl_div;
+wire   [7:0]   fasu_shift;
+wire   [7:0]   exp_fix_div;
+
+wire   [7:0]   exp_fix_diva, exp_fix_divb;
+wire   [5:0]   fi_ldz_mi1;
+wire   [5:0]   fi_ldz_mi22;
+wire           exp_zero;
+wire   [6:0]   ldz_all;
+wire   [7:0]   ldz_dif;
+
+wire   [8:0]   div_scht1a;
+wire   [7:0]   f2i_shft;
+wire   [55:0]  exp_f2i_1;
+wire           f2i_zero, f2i_max;
+wire   [7:0]   f2i_emin;
+wire   [7:0]   conv_shft;
+wire   [7:0]   exp_i2f, exp_f2i, conv_exp;
+wire           round2_f2i;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Normalize and Round Logic
+//
+
+// ---------------------------------------------------------------------
+// Count Leading zeros in fraction
+
+always @(fract_in)
+   casex(fract_in)     // synopsys full_case parallel_case
+       48'b1???????????????????????????????????????????????: fi_ldz =  1;
+       48'b01??????????????????????????????????????????????: fi_ldz =  2;
+       48'b001?????????????????????????????????????????????: fi_ldz =  3;
+       48'b0001????????????????????????????????????????????: fi_ldz =  4;
+       48'b00001???????????????????????????????????????????: fi_ldz =  5;
+       48'b000001??????????????????????????????????????????: fi_ldz =  6;
+       48'b0000001?????????????????????????????????????????: fi_ldz =  7;
+       48'b00000001????????????????????????????????????????: fi_ldz =  8;
+       48'b000000001???????????????????????????????????????: fi_ldz =  9;
+       48'b0000000001??????????????????????????????????????: fi_ldz =  10;
+       48'b00000000001?????????????????????????????????????: fi_ldz =  11;
+       48'b000000000001????????????????????????????????????: fi_ldz =  12;
+       48'b0000000000001???????????????????????????????????: fi_ldz =  13;
+       48'b00000000000001??????????????????????????????????: fi_ldz =  14;
+       48'b000000000000001?????????????????????????????????: fi_ldz =  15;
+       48'b0000000000000001????????????????????????????????: fi_ldz =  16;
+       48'b00000000000000001???????????????????????????????: fi_ldz =  17;
+       48'b000000000000000001??????????????????????????????: fi_ldz =  18;
+       48'b0000000000000000001?????????????????????????????: fi_ldz =  19;
+       48'b00000000000000000001????????????????????????????: fi_ldz =  20;
+       48'b000000000000000000001???????????????????????????: fi_ldz =  21;
+       48'b0000000000000000000001??????????????????????????: fi_ldz =  22;
+       48'b00000000000000000000001?????????????????????????: fi_ldz =  23;
+       48'b000000000000000000000001????????????????????????: fi_ldz =  24;
+       48'b0000000000000000000000001???????????????????????: fi_ldz =  25;
+       48'b00000000000000000000000001??????????????????????: fi_ldz =  26;
+       48'b000000000000000000000000001?????????????????????: fi_ldz =  27;
+       48'b0000000000000000000000000001????????????????????: fi_ldz =  28;
+       48'b00000000000000000000000000001???????????????????: fi_ldz =  29;
+       48'b000000000000000000000000000001??????????????????: fi_ldz =  30;
+       48'b0000000000000000000000000000001?????????????????: fi_ldz =  31;
+       48'b00000000000000000000000000000001????????????????: fi_ldz =  32;
+       48'b000000000000000000000000000000001???????????????: fi_ldz =  33;
+       48'b0000000000000000000000000000000001??????????????: fi_ldz =  34;
+       48'b00000000000000000000000000000000001?????????????: fi_ldz =  35;
+       48'b000000000000000000000000000000000001????????????: fi_ldz =  36;
+       48'b0000000000000000000000000000000000001???????????: fi_ldz =  37;
+       48'b00000000000000000000000000000000000001??????????: fi_ldz =  38;
+       48'b000000000000000000000000000000000000001?????????: fi_ldz =  39;
+       48'b0000000000000000000000000000000000000001????????: fi_ldz =  40;
+       48'b00000000000000000000000000000000000000001???????: fi_ldz =  41;
+       48'b000000000000000000000000000000000000000001??????: fi_ldz =  42;
+       48'b0000000000000000000000000000000000000000001?????: fi_ldz =  43;
+       48'b00000000000000000000000000000000000000000001????: fi_ldz =  44;
+       48'b000000000000000000000000000000000000000000001???: fi_ldz =  45;
+       48'b0000000000000000000000000000000000000000000001??: fi_ldz =  46;
+       48'b00000000000000000000000000000000000000000000001?: fi_ldz =  47;
+       48'b00000000000000000000000000000000000000000000000?: fi_ldz =  48;
+   endcase
+
+
+// ---------------------------------------------------------------------
+// Normalize
+
+wire           exp_in_80;
+wire           rmode_00, rmode_01, rmode_10, rmode_11;
+
+// Misc common signals
+assign exp_in_ff        = &exp_in;
+assign exp_in_00        = !(|exp_in);
+assign exp_in_80       = exp_in[7] & !(|exp_in[6:0]);
+assign exp_out_ff       = &exp_out;
+assign exp_out_00       = !(|exp_out);
+assign exp_out_fe       = &exp_out[7:1] & !exp_out[0];
+assign exp_out_final_ff = &exp_out_final;
+
+assign fract_out_7fffff = &fract_out;
+assign fract_out_00     = !(|fract_out);
+assign fract_in_00      = !(|fract_in);
+
+assign rmode_00 = (rmode==2'b00);
+assign rmode_01 = (rmode==2'b01);
+assign rmode_10 = (rmode==2'b10);
+assign rmode_11 = (rmode==2'b11);
+
+// Fasu Output will be denormalized ...
+assign dn = !op_mul & !op_div & (exp_in_00 | (exp_next_mi[8] & !fract_in[47]) );
+
+// ---------------------------------------------------------------------
+// Fraction Normalization
+parameter      f2i_emax = 8'h9d;
+
+// Incremented fraction for rounding
+assign fract_out_pl1 = fract_out + 1;
+
+// Special Signals for f2i
+assign f2i_emin = rmode_00 ? 8'h7e : 8'h7f;
+assign f2i_zero = (!opas & (exp_in<f2i_emin)) | (opas & (exp_in>f2i_emax)) | (opas & (exp_in<f2i_emin) & (fract_in_00 | !rmode_11));
+assign f2i_max = (!opas & (exp_in>f2i_emax)) | (opas & (exp_in<f2i_emin) & !fract_in_00 & rmode_11);
+
+// Claculate various shifting options
+
+assign {shft_co,shftr_mul} = (!exp_ovf[1] & exp_in_00) ? {1'b0, exp_out} : exp_in_mi1 ;
+assign {div_shft1_co, div_shft1} = exp_in_00 ? {1'b0, div_opa_ldz} : div_scht1a;
+
+assign div_scht1a = exp_in-div_opa_ldz; // 9 bits - includes carry out
+assign div_shft2  = exp_in+2;
+assign div_shft3  = div_opa_ldz+exp_in;
+assign div_shft4  = div_opa_ldz-exp_in;
+
+assign div_dn    = op_dn & div_shft1_co;
+assign div_nr    = op_dn & exp_ovf[1]  & !(|fract_in[46:23]) & (div_shft3>8'h16);
+
+assign f2i_shft  = exp_in-8'h7d;
+
+// Select shifting direction
+assign left_right = op_div ? lr_div : op_mul ? lr_mul : 1;
+
+assign lr_div =        (op_dn & !exp_ovf[1] & exp_ovf[0])     ? 1 :
+                       (op_dn & exp_ovf[1])                   ? 0 :
+                       (op_dn & div_shft1_co)                 ? 0 :
+                       (op_dn & exp_out_00)                   ? 1 :
+                       (!op_dn & exp_out_00 & !exp_ovf[1])    ? 1 :
+                       exp_ovf[1]                             ? 0 :
+                                                                1;
+assign lr_mul =        (shft_co | (!exp_ovf[1] & exp_in_00) |
+                       (!exp_ovf[1] & !exp_in_00 & (exp_out1_co | exp_out_00) )) ?     1 :
+                       ( exp_ovf[1] | exp_in_00 ) ?                                    0 :
+                                                                                       1;
+
+// Select Left and Right shift value
+assign fasu_shift  = (dn | exp_out_00) ? (exp_in_00 ? 8'h2 : exp_in_pl1[7:0]) : {2'h0, fi_ldz};
+assign shift_right = op_div ? shftr_div : shftr_mul;
+
+assign conv_shft = op_f2i ? f2i_shft : {2'h0, fi_ldz};
+
+assign shift_left  = op_div ? shftl_div : op_mul ? shftl_mul : (op_f2i | op_i2f) ? conv_shft : fasu_shift;
+
+assign shftl_mul =     (shft_co |
+                       (!exp_ovf[1] & exp_in_00) |
+                       (!exp_ovf[1] & !exp_in_00 & (exp_out1_co | exp_out_00))) ? exp_in_pl1[7:0] : {2'h0, fi_ldz};
+
+assign shftl_div =     ( op_dn & exp_out_00 & !(!exp_ovf[1] & exp_ovf[0]))     ? div_shft1[7:0] :
+                       (!op_dn & exp_out_00 & !exp_ovf[1])                     ? exp_in[7:0] :
+                                                                                {2'h0, fi_ldz};
+assign shftr_div =     (op_dn & exp_ovf[1])                   ? div_shft3 :
+                       (op_dn & div_shft1_co)                 ? div_shft4 :
+                                                                div_shft2;
+// Do the actual shifting
+assign fract_in_shftr   = (|shift_right[7:6])                      ? 0 : fract_in>>shift_right[5:0];
+assign fract_in_shftl   = (|shift_left[7:6] | (f2i_zero & op_f2i)) ? 0 : fract_in<<shift_left[5:0];
+
+// Chose final fraction output
+assign {fract_out,fract_trunc} = left_right ? fract_in_shftl : fract_in_shftr;
+
+// ---------------------------------------------------------------------
+// Exponent Normalization
+
+assign fi_ldz_mi1    = fi_ldz - 1;
+assign fi_ldz_mi22   = fi_ldz - 22;
+assign exp_out_pl1   = exp_out + 1;
+assign exp_out_mi1   = exp_out - 1;
+assign exp_in_pl1    = exp_in  + 1;    // 9 bits - includes carry out
+assign exp_in_mi1    = exp_in  - 1;    // 9 bits - includes carry out
+assign exp_out1_mi1  = exp_out1 - 1;
+
+assign exp_next_mi  = exp_in_pl1 - fi_ldz_mi1; // 9 bits - includes carry out
+
+assign exp_fix_diva = exp_in - fi_ldz_mi22;
+assign exp_fix_divb = exp_in - fi_ldz_mi1;
+
+assign exp_zero  = (exp_ovf[1] & !exp_ovf[0] & op_mul & (!exp_rnd_adj2a | !rmode[1])) | (op_mul & exp_out1_co);
+assign {exp_out1_co, exp_out1} = fract_in[47] ? exp_in_pl1 : exp_next_mi;
+
+assign f2i_out_sign =  !opas ? ((exp_in<f2i_emin) ? 0 : (exp_in>f2i_emax) ? 0 : opas) :
+                              ((exp_in<f2i_emin) ? 0 : (exp_in>f2i_emax) ? 1 : opas);
+
+assign exp_i2f   = fract_in_00 ? (opas ? 8'h9e : 0) : (8'h9e-fi_ldz);
+assign exp_f2i_1 = {{8{fract_in[47]}}, fract_in }<<f2i_shft;
+assign exp_f2i   = f2i_zero ? 0 : f2i_max ? 8'hff : exp_f2i_1[55:48];
+assign conv_exp  = op_f2i ? exp_f2i : exp_i2f;
+
+assign exp_out = op_div ? exp_div : (op_f2i | op_i2f) ? conv_exp : exp_zero ? 8'h0 : dn ? {6'h0, fract_in[47:46]} : exp_out1;
+
+assign ldz_all   = div_opa_ldz + fi_ldz;
+assign ldz_dif   = fi_ldz_2 - div_opa_ldz;
+assign fi_ldz_2a = 6'd23 - fi_ldz;
+assign fi_ldz_2  = {fi_ldz_2a[6], fi_ldz_2a[6:0]};
+
+assign div_exp1  = exp_in_mi1 + fi_ldz_2;      // 9 bits - includes carry out
+
+assign div_exp2  = exp_in_pl1 - ldz_all;
+assign div_exp3  = exp_in + ldz_dif;
+
+assign exp_div =(opa_dn & opb_dn)                                      ? div_exp3 :
+                opb_dn                                                 ? div_exp1[7:0] :
+               (opa_dn & !( (exp_in<div_opa_ldz) | (div_exp2>9'hfe) )) ? div_exp2 :
+               (opa_dn | (exp_in_00 & !exp_ovf[1]) )                   ? 0 :
+                                                                         exp_out1_mi1;
+
+assign div_inf = opb_dn & !opa_dn & (div_exp1[7:0] < 8'h7f);
+
+// ---------------------------------------------------------------------
+// Round
+
+// Extract rounding (GRS) bits
+assign grs_sel_div = op_div & (exp_ovf[1] | div_dn | exp_out1_co | exp_out_00);
+
+assign g = grs_sel_div ? fract_out[0]                   : fract_out[0];
+assign r = grs_sel_div ? (fract_trunc[24] & !div_nr)    : fract_trunc[24];
+assign s = grs_sel_div ? |fract_trunc[24:0]             : (|fract_trunc[23:0] | (fract_trunc[24] & op_div));
+
+// Round to nearest even
+assign round = (g & r) | (r & s) ;
+assign {exp_rnd_adj0, fract_out_rnd0} = round ? fract_out_pl1 : {1'b0, fract_out};
+assign exp_out_rnd0 =  exp_rnd_adj0 ? exp_out_pl1 : exp_out;
+assign ovf0 = exp_out_final_ff & !rmode_01 & !op_f2i;
+
+// round to zero
+assign fract_out_rnd1 = (exp_out_ff & !op_div & !dn & !op_f2i) ? 23'h7fffff : fract_out;
+assign exp_fix_div    = (fi_ldz>22) ? exp_fix_diva : exp_fix_divb;
+assign exp_out_rnd1   = (g & r & s & exp_in_ff) ? (op_div ? exp_fix_div : exp_next_mi[7:0]) :
+                       (exp_out_ff & !op_f2i) ? exp_in : exp_out;
+assign ovf1 = exp_out_ff & !dn;
+
+// round to +inf (UP) and -inf (DOWN)
+assign r_sign = sign;
+
+assign round2a = !exp_out_fe | !fract_out_7fffff | (exp_out_fe & fract_out_7fffff);
+assign round2_fasu = ((r | s) & !r_sign) & (!exp_out[7] | (exp_out[7] & round2a));
+
+assign round2_fmul = !r_sign & 
+               (
+                       (exp_ovf[1] & !fract_in_00 &
+                               ( ((!exp_out1_co | op_dn) & (r | s | (!rem_00 & op_div) )) | fract_out_00 | (!op_dn & !op_div))
+                        ) |
+                       (
+                               (r | s | (!rem_00 & op_div)) & (
+                                               (!exp_ovf[1] & (exp_in_80 | !exp_ovf[0])) | op_div |
+                                               ( exp_ovf[1] & !exp_ovf[0] & exp_out1_co)
+                                       )
+                       )
+               );
+
+assign round2_f2i = rmode_10 & (( |fract_in[23:0] & !opas & (exp_in<8'h80 )) | (|fract_trunc));
+assign round2 = (op_mul | op_div) ? round2_fmul : op_f2i ? round2_f2i : round2_fasu;
+
+assign {exp_rnd_adj2a, fract_out_rnd2a} = round2 ? fract_out_pl1 : {1'b0, fract_out};
+assign exp_out_rnd2a  = exp_rnd_adj2a ? ((exp_ovf[1] & op_mul) ? exp_out_mi1 : exp_out_pl1) : exp_out;
+
+assign fract_out_rnd2 = (r_sign & exp_out_ff & !op_div & !dn & !op_f2i) ? 23'h7fffff : fract_out_rnd2a;
+assign exp_out_rnd2   = (r_sign & exp_out_ff & !op_f2i) ? 8'hfe      : exp_out_rnd2a;
+
+
+// Choose rounding mode
+always @(rmode or exp_out_rnd0 or exp_out_rnd1 or exp_out_rnd2)
+       case(rmode)     // synopsys full_case parallel_case
+          0: exp_out_rnd = exp_out_rnd0;
+          1: exp_out_rnd = exp_out_rnd1;
+        2,3: exp_out_rnd = exp_out_rnd2;
+       endcase
+
+always @(rmode or fract_out_rnd0 or fract_out_rnd1 or fract_out_rnd2)
+       case(rmode)     // synopsys full_case parallel_case
+          0: fract_out_rnd = fract_out_rnd0;
+          1: fract_out_rnd = fract_out_rnd1;
+        2,3: fract_out_rnd = fract_out_rnd2;
+       endcase
+
+// ---------------------------------------------------------------------
+// Final Output Mux
+// Fix Output for denormalized and special numbers
+wire   max_num, inf_out;
+
+assign max_num =  ( !rmode_00 & (op_mul | op_div ) & (
+                                                         ( exp_ovf[1] &  exp_ovf[0]) |
+                                                         (!exp_ovf[1] & !exp_ovf[0] & exp_in_ff & (fi_ldz_2<24) & (exp_out!=8'hfe) )
+                                                         )
+                  ) |
+
+                  ( op_div & (
+                                  ( rmode_01 & ( div_inf |
+                                                        (exp_out_ff & !exp_ovf[1] ) |
+                                                        (exp_ovf[1] &  exp_ovf[0] )
+                                               )
+                                  ) |
+               
+                                  ( rmode[1] & !exp_ovf[1] & (
+                                                                  ( exp_ovf[0] & exp_in_ff & r_sign & fract_in[47]
+                                                                  ) |
+                                               
+                                                                  (  r_sign & (
+                                                                               (fract_in[47] & div_inf) |
+                                                                               (exp_in[7] & !exp_out_rnd[7] & !exp_in_80 & exp_out!=8'h7f ) |
+                                                                               (exp_in[7] &  exp_out_rnd[7] & r_sign & exp_out_ff & op_dn &
+                                                                                        div_exp1>9'h0fe )
+                                                                               )
+                                                                  ) |
+
+                                                                  ( exp_in_00 & r_sign & (
+                                                                                               div_inf |
+                                                                                               (r_sign & exp_out_ff & fi_ldz_2<24)
+                                                                                         )
+                                                                  )
+                                                              )
+                                 )
+                           )
+                  );
+
+
+assign inf_out = (rmode[1] & (op_mul | op_div) & !r_sign & (   (exp_in_ff & !op_div) |
+                                                               (exp_ovf[1] & exp_ovf[0] & (exp_in_00 | exp_in[7]) ) 
+                                                          )
+               ) | (div_inf & op_div & (
+                                rmode_00 |
+                               (rmode[1] & !exp_in_ff & !exp_ovf[1] & !exp_ovf[0] & !r_sign ) |
+                               (rmode[1] & !exp_ovf[1] & exp_ovf[0] & exp_in_00 & !r_sign)
+                               )
+               ) | (op_div & rmode[1] & exp_in_ff & op_dn & !r_sign & (fi_ldz_2 < 24)  & (exp_out_rnd!=8'hfe) );
+
+assign fract_out_final =       (inf_out | ovf0 | output_zero ) ? 23'h0 :
+                               (max_num | (f2i_max & op_f2i) ) ? 23'h7fffff :
+                               fract_out_rnd;
+
+assign exp_out_final = ((op_div & exp_ovf[1] & !exp_ovf[0]) | output_zero ) ? 8'h00 :
+                       ((op_div & exp_ovf[1] &  exp_ovf[0] & rmode_00) | inf_out | (f2i_max & op_f2i) ) ? 8'hff :
+                       max_num ? 8'hfe :
+                       exp_out_rnd;
+
+
+// ---------------------------------------------------------------------
+// Pack Result
+
+assign out = {exp_out_final, fract_out_final};
+
+// ---------------------------------------------------------------------
+// Exceptions
+wire           underflow_fmul;
+wire           overflow_fdiv;
+wire           undeflow_div;
+
+wire           z =     shft_co | ( exp_ovf[1] |  exp_in_00) |
+                       (!exp_ovf[1] & !exp_in_00 & (exp_out1_co | exp_out_00));
+
+assign underflow_fmul = ( (|fract_trunc) & z & !exp_in_ff ) |
+                       (fract_out_00 & !fract_in_00 & exp_ovf[1]);
+
+assign undeflow_div =  !(exp_ovf[1] &  exp_ovf[0] & rmode_00) & !inf_out & !max_num & exp_out_final!=8'hff & (
+
+                       ((|fract_trunc) & !opb_dn & (
+                                                       ( op_dn & !exp_ovf[1] & exp_ovf[0])     |
+                                                       ( op_dn &  exp_ovf[1])                  |
+                                                       ( op_dn &  div_shft1_co)                | 
+                                                         exp_out_00                            |
+                                                         exp_ovf[1]
+                                                 )
+
+                       ) |
+
+                       ( exp_ovf[1] & !exp_ovf[0] & (
+                                                       (  op_dn & exp_in>8'h16 & fi_ldz<23) |
+                                                       (  op_dn & exp_in<23 & fi_ldz<23 & !rem_00) |
+                                                       ( !op_dn & (exp_in[7]==exp_div[7]) & !rem_00) |
+                                                       ( !op_dn & exp_in_00 & (exp_div[7:1]==7'h7f) ) |
+                                                       ( !op_dn & exp_in<8'h7f & exp_in>8'h20 )
+                                                       )
+                       ) |
+
+                       (!exp_ovf[1] & !exp_ovf[0] & (
+                                                       ( op_dn & fi_ldz<23 & exp_out_00) |
+                                                       ( exp_in_00 & !rem_00) |
+                                                       ( !op_dn & ldz_all<23 & exp_in==1 & exp_out_00 & !rem_00)
+                                                       )
+                       )
+
+                       );
+
+assign underflow = op_div ? undeflow_div : op_mul ? underflow_fmul : (!fract_in[47] & exp_out1_co) & !dn;
+
+assign overflow_fdiv = inf_out |
+                       (!rmode_00 & max_num) |
+                       (exp_in[7] & op_dn & exp_out_ff) |
+                       (exp_ovf[0] & (exp_ovf[1] | exp_out_ff) );
+
+assign overflow  = op_div ? overflow_fdiv : (ovf0 | ovf1);
+
+wire           f2i_ine;
+
+assign f2i_ine =       (f2i_zero & !fract_in_00 & !opas) |
+                       (|fract_trunc) |
+                       (f2i_zero & (exp_in<8'h80) & opas & !fract_in_00) |
+                       (f2i_max & rmode_11 & (exp_in<8'h80));
+
+
+
+assign ine =   op_f2i ? f2i_ine :
+               op_i2f ? (|fract_trunc) :
+               ((r & !dn) | (s & !dn) | max_num | (op_div & !rem_00));
+
+// ---------------------------------------------------------------------
+// Debugging Stuff
+
+// synopsys translate_off
+
+wire   [26:0]  fracta_del, fractb_del;
+wire   [2:0]   grs_del;
+wire           dn_del;
+wire   [7:0]   exp_in_del;
+wire   [7:0]   exp_out_del;
+wire   [22:0]  fract_out_del;
+wire   [47:0]  fract_in_del;
+wire           overflow_del;
+wire   [1:0]   exp_ovf_del;
+wire   [22:0]  fract_out_x_del, fract_out_rnd2a_del;
+wire   [24:0]  trunc_xx_del;
+wire           exp_rnd_adj2a_del;
+wire   [22:0]  fract_dn_del;
+wire   [4:0]   div_opa_ldz_del;
+wire   [23:0]  fracta_div_del;
+wire   [23:0]  fractb_div_del;
+wire           div_inf_del;
+wire   [7:0]   fi_ldz_2_del;
+wire           inf_out_del, max_out_del;
+wire   [5:0]   fi_ldz_del;
+wire           rx_del;
+wire           ez_del;
+wire           lr;
+wire   [7:0]   shr, shl, exp_div_del;
+
+delay2 #26 ud000(clk, test.u0.fracta, fracta_del);
+delay2 #26 ud001(clk, test.u0.fractb, fractb_del);
+delay1  #2 ud002(clk, {g,r,s}, grs_del);
+delay1  #0 ud004(clk, dn, dn_del);
+delay1  #7 ud005(clk, exp_in, exp_in_del);
+delay1  #7 ud007(clk, exp_out_rnd, exp_out_del);
+delay1 #47 ud009(clk, fract_in, fract_in_del);
+delay1  #0 ud010(clk, overflow, overflow_del);
+delay1  #1 ud011(clk, exp_ovf, exp_ovf_del);
+delay1 #22 ud014(clk, fract_out, fract_out_x_del);
+delay1 #24 ud015(clk, fract_trunc, trunc_xx_del);
+delay1         #0 ud017(clk, exp_rnd_adj2a, exp_rnd_adj2a_del);
+delay1  #4 ud019(clk, div_opa_ldz, div_opa_ldz_del);
+delay3 #23 ud020(clk, test.u0.fdiv_opa[49:26], fracta_div_del);
+delay3 #23 ud021(clk, test.u0.fractb_mul,      fractb_div_del);
+delay1         #0 ud023(clk, div_inf, div_inf_del);
+delay1  #7 ud024(clk, fi_ldz_2, fi_ldz_2_del);
+delay1         #0 ud025(clk, inf_out, inf_out_del);
+delay1         #0 ud026(clk, max_num, max_num_del);
+delay1         #5 ud027(clk, fi_ldz, fi_ldz_del);
+delay1  #0 ud028(clk, rem_00, rx_del);
+
+delay1  #0 ud029(clk, left_right, lr);
+delay1  #7 ud030(clk, shift_right, shr);
+delay1  #7 ud031(clk, shift_left, shl);
+delay1 #22 ud032(clk, fract_out_rnd2a, fract_out_rnd2a_del);
+
+delay1  #7 ud033(clk, exp_div, exp_div_del);
+
+always @(test.error_event)
+   begin
+
+       $display("\n----------------------------------------------");
+
+       $display("ERROR: GRS: %b exp_ovf: %b dn: %h exp_in: %h exp_out: %h, exp_rnd_adj2a: %b",
+                       grs_del, exp_ovf_del, dn_del, exp_in_del, exp_out_del, exp_rnd_adj2a_del);
+
+       $display("      div_opa: %b, div_opb: %b, rem_00: %b, exp_div: %h",
+                       fracta_div_del, fractb_div_del, rx_del, exp_div_del);
+
+       $display("      lr: %b, shl: %h, shr: %h",
+                       lr, shl, shr);
+
+
+       $display("       overflow: %b, fract_in=%b  fa:%h fb:%h",
+                       overflow_del, fract_in_del, fracta_del, fractb_del);
+
+       $display("       div_opa_ldz: %h, div_inf: %b, inf_out: %b, max_num: %b, fi_ldz: %h, fi_ldz_2: %h",
+                       div_opa_ldz_del, div_inf_del, inf_out_del, max_num_del, fi_ldz_del, fi_ldz_2_del);
+
+       $display("       fract_out_x: %b, fract_out_rnd2a_del: %h, fract_trunc: %b\n",
+                       fract_out_x_del, fract_out_rnd2a_del, trunc_xx_del);
+   end
+
+
+// synopsys translate_on
+
+endmodule
+
+// synopsys translate_off
+
+module delay1(clk, in, out);
+parameter      N = 1;
+input  [N:0]   in;
+output [N:0]   out;
+input          clk;
+
+reg    [N:0]   out;
+
+always @(posedge clk)
+       out <= #1 in;
+
+endmodule
+
+
+module delay2(clk, in, out);
+parameter      N = 1;
+input  [N:0]   in;
+output [N:0]   out;
+input          clk;
+
+reg    [N:0]   out, r1;
+
+always @(posedge clk)
+       r1 <= #1 in;
+
+always @(posedge clk)
+       out <= #1 r1;
+
+endmodule
+
+module delay3(clk, in, out);
+parameter      N = 1;
+input  [N:0]   in;
+output [N:0]   out;
+input          clk;
+
+reg    [N:0]   out, r1, r2;
+
+always @(posedge clk)
+       r1 <= #1 in;
+
+always @(posedge clk)
+       r2 <= #1 r1;
+
+always @(posedge clk)
+       out <= #1 r2;
+
+endmodule
+
+// synopsys translate_on
\ No newline at end of file
diff --git a/tests/iwls2005/fpu/pre_norm.v b/tests/iwls2005/fpu/pre_norm.v
new file mode 100644 (file)
index 0000000..c54c71f
--- /dev/null
@@ -0,0 +1,270 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  Pre Normalize                                              ////
+////  Pre Normalization Unit for Add/Sub Operations              ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000 Rudolf Usselmann                         ////
+////                    rudi@asics.ws                            ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+`timescale 1ns / 100ps
+
+
+module pre_norm(clk, rmode, add, opa, opb, opa_nan, opb_nan, fracta_out,
+               fractb_out, exp_dn_out, sign, nan_sign, result_zero_sign,
+               fasu_op);
+input          clk;
+input  [1:0]   rmode;
+input          add;
+input  [31:0]  opa, opb;
+input          opa_nan, opb_nan;
+output [26:0]  fracta_out, fractb_out;
+output [7:0]   exp_dn_out;
+output         sign;
+output         nan_sign, result_zero_sign;
+output         fasu_op;                        // Operation Output
+
+////////////////////////////////////////////////////////////////////////
+//
+// Local Wires and registers
+//
+
+wire           signa, signb;           // alias to opX sign
+wire   [7:0]   expa, expb;             // alias to opX exponent
+wire   [22:0]  fracta, fractb;         // alias to opX fraction
+wire           expa_lt_expb;           // expa is larger than expb indicator
+wire           fractb_lt_fracta;       // fractb is larger than fracta indicator
+reg    [7:0]   exp_dn_out;             // de normalized exponent output
+wire   [7:0]   exp_small, exp_large;
+wire   [7:0]   exp_diff;               // Numeric difference of the two exponents
+wire   [22:0]  adj_op;                 // Fraction adjustment: input
+wire   [26:0]  adj_op_tmp;
+wire   [26:0]  adj_op_out;             // Fraction adjustment: output
+wire   [26:0]  fracta_n, fractb_n;     // Fraction selection after normalizing
+wire   [26:0]  fracta_s, fractb_s;     // Fraction Sorting out
+reg    [26:0]  fracta_out, fractb_out; // Fraction Output
+reg            sign, sign_d;           // Sign Output
+reg            add_d;                  // operation (add/sub)
+reg            fasu_op;                // operation (add/sub) register
+wire           expa_dn, expb_dn;
+reg            sticky;
+reg            result_zero_sign;
+reg            add_r, signa_r, signb_r;
+wire   [4:0]   exp_diff_sft;
+wire           exp_lt_27;
+wire           op_dn;
+wire   [26:0]  adj_op_out_sft;
+reg            fracta_lt_fractb, fracta_eq_fractb;
+wire           nan_sign1;
+reg            nan_sign;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Aliases
+//
+
+assign  signa = opa[31];
+assign  signb = opb[31];
+assign   expa = opa[30:23];
+assign   expb = opb[30:23];
+assign fracta = opa[22:0];
+assign fractb = opb[22:0];
+
+////////////////////////////////////////////////////////////////////////
+//
+// Pre-Normalize exponents (and fractions)
+//
+
+assign expa_lt_expb = expa > expb;             // expa is larger than expb
+
+// ---------------------------------------------------------------------
+// Normalize
+
+assign expa_dn = !(|expa);                     // opa denormalized
+assign expb_dn = !(|expb);                     // opb denormalized
+
+// ---------------------------------------------------------------------
+// Calculate the difference between the smaller and larger exponent
+
+wire   [7:0]   exp_diff1, exp_diff1a, exp_diff2;
+
+assign exp_small  = expa_lt_expb ? expb : expa;
+assign exp_large  = expa_lt_expb ? expa : expb;
+assign exp_diff1  = exp_large - exp_small;
+assign exp_diff1a = exp_diff1-1;
+assign exp_diff2  = (expa_dn | expb_dn) ? exp_diff1a : exp_diff1;
+assign  exp_diff  = (expa_dn & expb_dn) ? 8'h0 : exp_diff2;
+
+always @(posedge clk)  // If numbers are equal we should return zero
+       exp_dn_out <= #1 (!add_d & expa==expb & fracta==fractb) ? 8'h0 : exp_large;
+
+// ---------------------------------------------------------------------
+// Adjust the smaller fraction
+
+
+assign op_dn     = expa_lt_expb ? expb_dn : expa_dn;
+assign adj_op     = expa_lt_expb ? fractb : fracta;
+assign adj_op_tmp = { ~op_dn, adj_op, 3'b0 };  // recover hidden bit (op_dn) 
+
+// adj_op_out is 27 bits wide, so can only be shifted 27 bits to the right
+assign exp_lt_27       = exp_diff  > 8'd27;
+assign exp_diff_sft    = exp_lt_27 ? 5'd27 : exp_diff[4:0];
+assign adj_op_out_sft  = adj_op_tmp >> exp_diff_sft;
+assign adj_op_out      = {adj_op_out_sft[26:1], adj_op_out_sft[0] | sticky };
+
+// ---------------------------------------------------------------------
+// Get truncated portion (sticky bit)
+
+always @(exp_diff_sft or adj_op_tmp)
+   case(exp_diff_sft)          // synopsys full_case parallel_case
+       00: sticky = 1'h0;
+       01: sticky =  adj_op_tmp[0]; 
+       02: sticky = |adj_op_tmp[01:0];
+       03: sticky = |adj_op_tmp[02:0];
+       04: sticky = |adj_op_tmp[03:0];
+       05: sticky = |adj_op_tmp[04:0];
+       06: sticky = |adj_op_tmp[05:0];
+       07: sticky = |adj_op_tmp[06:0];
+       08: sticky = |adj_op_tmp[07:0];
+       09: sticky = |adj_op_tmp[08:0];
+       10: sticky = |adj_op_tmp[09:0];
+       11: sticky = |adj_op_tmp[10:0];
+       12: sticky = |adj_op_tmp[11:0];
+       13: sticky = |adj_op_tmp[12:0];
+       14: sticky = |adj_op_tmp[13:0];
+       15: sticky = |adj_op_tmp[14:0];
+       16: sticky = |adj_op_tmp[15:0];
+       17: sticky = |adj_op_tmp[16:0];
+       18: sticky = |adj_op_tmp[17:0];
+       19: sticky = |adj_op_tmp[18:0];
+       20: sticky = |adj_op_tmp[19:0];
+       21: sticky = |adj_op_tmp[20:0];
+       22: sticky = |adj_op_tmp[21:0];
+       23: sticky = |adj_op_tmp[22:0];
+       24: sticky = |adj_op_tmp[23:0];
+       25: sticky = |adj_op_tmp[24:0];
+       26: sticky = |adj_op_tmp[25:0];
+       27: sticky = |adj_op_tmp[26:0];
+   endcase
+
+// ---------------------------------------------------------------------
+// Select operands for add/sub (recover hidden bit)
+
+assign fracta_n = expa_lt_expb ? {~expa_dn, fracta, 3'b0} : adj_op_out;
+assign fractb_n = expa_lt_expb ? adj_op_out : {~expb_dn, fractb, 3'b0};
+
+// ---------------------------------------------------------------------
+// Sort operands (for sub only)
+
+assign fractb_lt_fracta = fractb_n > fracta_n; // fractb is larger than fracta
+assign fracta_s = fractb_lt_fracta ? fractb_n : fracta_n;
+assign fractb_s = fractb_lt_fracta ? fracta_n : fractb_n;
+
+always @(posedge clk)
+       fracta_out <= #1 fracta_s;
+
+always @(posedge clk)
+       fractb_out <= #1 fractb_s;
+
+// ---------------------------------------------------------------------
+// Determine sign for the output
+
+// sign: 0=Positive Number; 1=Negative Number
+always @(signa or signb or add or fractb_lt_fracta)
+   case({signa, signb, add})           // synopsys full_case parallel_case
+
+       // Add
+       3'b0_0_1: sign_d = 0;
+       3'b0_1_1: sign_d = fractb_lt_fracta;
+       3'b1_0_1: sign_d = !fractb_lt_fracta;
+       3'b1_1_1: sign_d = 1;
+
+       // Sub
+       3'b0_0_0: sign_d = fractb_lt_fracta;
+       3'b0_1_0: sign_d = 0;
+       3'b1_0_0: sign_d = 1;
+       3'b1_1_0: sign_d = !fractb_lt_fracta;
+   endcase
+
+always @(posedge clk)
+       sign <= #1 sign_d;
+
+// Fix sign for ZERO result
+always @(posedge clk)
+       signa_r <= #1 signa;
+
+always @(posedge clk)
+       signb_r <= #1 signb;
+
+always @(posedge clk)
+       add_r <= #1 add;
+
+always @(posedge clk)
+       result_zero_sign <= #1  ( add_r &  signa_r &  signb_r) |
+                               (!add_r &  signa_r & !signb_r) |
+                               ( add_r & (signa_r |  signb_r) & (rmode==3)) |
+                               (!add_r & (signa_r == signb_r) & (rmode==3));
+
+// Fix sign for NAN result
+always @(posedge clk)
+       fracta_lt_fractb <= #1 fracta < fractb;
+
+always @(posedge clk)
+       fracta_eq_fractb <= #1 fracta == fractb;
+
+assign nan_sign1 = fracta_eq_fractb ? (signa_r & signb_r) : fracta_lt_fractb ? signb_r : signa_r;
+
+always @(posedge clk)
+       nan_sign <= #1 (opa_nan & opb_nan) ? nan_sign1 : opb_nan ? signb_r : signa_r;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Decode Add/Sub operation
+//
+
+// add: 1=Add; 0=Subtract
+always @(signa or signb or add)
+   case({signa, signb, add})           // synopsys full_case parallel_case
+   
+       // Add
+       3'b0_0_1: add_d = 1;
+       3'b0_1_1: add_d = 0;
+       3'b1_0_1: add_d = 0;
+       3'b1_1_1: add_d = 1;
+       
+       // Sub
+       3'b0_0_0: add_d = 0;
+       3'b0_1_0: add_d = 1;
+       3'b1_0_0: add_d = 1;
+       3'b1_1_0: add_d = 0;
+   endcase
+
+always @(posedge clk)
+       fasu_op <= #1 add_d;
+
+endmodule
diff --git a/tests/iwls2005/fpu/pre_norm_fmul.v b/tests/iwls2005/fpu/pre_norm_fmul.v
new file mode 100644 (file)
index 0000000..26ddfeb
--- /dev/null
@@ -0,0 +1,150 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  Pre Normalize                                              ////
+////  Floating Point Pre Normalization Unit for FMUL             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000 Rudolf Usselmann                         ////
+////                    rudi@asics.ws                            ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+`timescale 1ns / 100ps
+
+module pre_norm_fmul(clk, fpu_op, opa, opb, fracta, fractb, exp_out, sign,
+               sign_exe, inf, exp_ovf, underflow);
+input          clk;
+input  [2:0]   fpu_op;
+input  [31:0]  opa, opb;
+output [23:0]  fracta, fractb;
+output [7:0]   exp_out;
+output         sign, sign_exe;
+output         inf;
+output [1:0]   exp_ovf;
+output [2:0]   underflow;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Local Wires and registers
+//
+
+reg    [7:0]   exp_out;
+wire           signa, signb;
+reg            sign, sign_d;
+reg            sign_exe;
+reg            inf;
+wire   [1:0]   exp_ovf_d;
+reg    [1:0]   exp_ovf;
+wire   [7:0]   expa, expb;
+wire   [7:0]   exp_tmp1, exp_tmp2;
+wire           co1, co2;
+wire           expa_dn, expb_dn;
+wire   [7:0]   exp_out_a;
+wire           opa_00, opb_00, fracta_00, fractb_00;
+wire   [7:0]   exp_tmp3, exp_tmp4, exp_tmp5;
+wire   [2:0]   underflow_d;
+reg    [2:0]   underflow;
+wire           op_div = (fpu_op == 3'b011);
+wire   [7:0]   exp_out_mul, exp_out_div;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Aliases
+//
+
+assign  signa = opa[31];
+assign  signb = opb[31];
+assign   expa = opa[30:23];
+assign   expb = opb[30:23];
+
+////////////////////////////////////////////////////////////////////////
+//
+// Calculate Exponenet
+//
+
+assign expa_dn   = !(|expa);
+assign expb_dn   = !(|expb);
+assign opa_00    = !(|opa[30:0]);
+assign opb_00    = !(|opb[30:0]);
+assign fracta_00 = !(|opa[22:0]);
+assign fractb_00 = !(|opb[22:0]);
+
+assign fracta = {!expa_dn,opa[22:0]};  // Recover hidden bit
+assign fractb = {!expb_dn,opb[22:0]};  // Recover hidden bit
+
+assign {co1,exp_tmp1} = op_div ? (expa - expb)            : (expa + expb);
+assign {co2,exp_tmp2} = op_div ? ({co1,exp_tmp1} + 8'h7f) : ({co1,exp_tmp1} - 8'h7f);
+
+assign exp_tmp3 = exp_tmp2 + 1;
+assign exp_tmp4 = 8'h7f - exp_tmp1;
+assign exp_tmp5 = op_div ? (exp_tmp4+1) : (exp_tmp4-1);
+
+
+always@(posedge clk)
+       exp_out <= #1 op_div ? exp_out_div : exp_out_mul;
+
+assign exp_out_div = (expa_dn | expb_dn) ? (co2 ? exp_tmp5 : exp_tmp3 ) : co2 ? exp_tmp4 : exp_tmp2;
+assign exp_out_mul = exp_ovf_d[1] ? exp_out_a : (expa_dn | expb_dn) ? exp_tmp3 : exp_tmp2;
+assign exp_out_a   = (expa_dn | expb_dn) ? exp_tmp5 : exp_tmp4;
+assign exp_ovf_d[0] = op_div ? (expa[7] & !expb[7]) : (co2 & expa[7] & expb[7]);
+assign exp_ovf_d[1] = op_div ? co2                  : ((!expa[7] & !expb[7] & exp_tmp2[7]) | co2);
+
+always @(posedge clk)
+       exp_ovf <= #1 exp_ovf_d;
+
+assign underflow_d[0] =        (exp_tmp1 < 8'h7f) & !co1 & !(opa_00 | opb_00 | expa_dn | expb_dn);
+assign underflow_d[1] =        ((expa[7] | expb[7]) & !opa_00 & !opb_00) |
+                        (expa_dn & !fracta_00) | (expb_dn & !fractb_00);
+assign underflow_d[2] =         !opa_00 & !opb_00 & (exp_tmp1 == 8'h7f);
+
+always @(posedge clk)
+       underflow <= #1 underflow_d;
+
+always @(posedge clk)
+       inf <= #1 op_div ? (expb_dn & !expa[7]) : ({co1,exp_tmp1} > 9'h17e) ;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Determine sign for the output
+//
+
+// sign: 0=Posetive Number; 1=Negative Number
+always @(signa or signb)
+   case({signa, signb})                // synopsys full_case parallel_case
+       2'b0_0: sign_d = 0;
+       2'b0_1: sign_d = 1;
+       2'b1_0: sign_d = 1;
+       2'b1_1: sign_d = 0;
+   endcase
+
+always @(posedge clk)
+       sign <= #1 sign_d;
+
+always @(posedge clk)
+       sign_exe <= #1 signa & signb;
+
+endmodule
\ No newline at end of file
diff --git a/tests/iwls2005/fpu/primitives.v b/tests/iwls2005/fpu/primitives.v
new file mode 100644 (file)
index 0000000..2e7f050
--- /dev/null
@@ -0,0 +1,103 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  Primitives                                                 ////
+////  FPU Primitives                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000 Rudolf Usselmann                         ////
+////                    rudi@asics.ws                            ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+
+`timescale 1ns / 100ps
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Add/Sub
+//
+
+module add_sub27(add, opa, opb, sum, co);
+input          add;
+input  [26:0]  opa, opb;
+output [26:0]  sum;
+output         co;
+
+
+
+assign {co, sum} = add ? (opa + opb) : (opa - opb);
+
+endmodule
+
+////////////////////////////////////////////////////////////////////////
+//
+// Multiply
+//
+
+module mul_r2(clk, opa, opb, prod);
+input          clk;
+input  [23:0]  opa, opb;
+output [47:0]  prod;
+
+reg    [47:0]  prod1, prod;
+
+always @(posedge clk)
+       prod1 <= #1 opa * opb;
+
+always @(posedge clk)
+       prod <= #1 prod1;
+
+endmodule
+
+////////////////////////////////////////////////////////////////////////
+//
+// Divide
+//
+
+module div_r2(clk, opa, opb, quo, rem);
+input          clk;
+input  [49:0]  opa;
+input  [23:0]  opb;
+output [49:0]  quo, rem;
+
+reg    [49:0]  quo, rem, quo1, remainder;
+
+always @(posedge clk)
+       quo1 <= #1 opa / opb;
+
+always @(posedge clk)
+       quo <= #1 quo1;
+
+always @(posedge clk)
+       remainder <= #1 opa % opb;
+
+always @(posedge clk)
+       rem <= #1 remainder;
+
+endmodule
+
+
diff --git a/tests/iwls2005/i2c/i2c_master_bit_ctrl.v b/tests/iwls2005/i2c/i2c_master_bit_ctrl.v
new file mode 100644 (file)
index 0000000..17b2c8b
--- /dev/null
@@ -0,0 +1,535 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE rev.B2 compliant I2C Master bit-controller        ////
+////                                                             ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: i2c_master_bit_ctrl.v,v 1.11 2004/05/07 11:02:26 rherveille Exp $
+//
+//  $Date: 2004/05/07 11:02:26 $
+//  $Revision: 1.11 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: i2c_master_bit_ctrl.v,v $
+//               Revision 1.11  2004/05/07 11:02:26  rherveille
+//               Fixed a bug where the core would signal an arbitration lost (AL bit set), when another master controls the bus and the other master generates a STOP bit.
+//
+//               Revision 1.10  2003/08/09 07:01:33  rherveille
+//               Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
+//               Fixed a potential bug in the byte controller's host-acknowledge generation.
+//
+//               Revision 1.9  2003/03/10 14:26:37  rherveille
+//               Fixed cmd_ack generation item (no bug).
+//
+//               Revision 1.8  2003/02/05 00:06:10  rherveille
+//               Fixed a bug where the core would trigger an erroneous 'arbitration lost' interrupt after being reset, when the reset pulse width < 3 clk cycles.
+//
+//               Revision 1.7  2002/12/26 16:05:12  rherveille
+//               Small code simplifications
+//
+//               Revision 1.6  2002/12/26 15:02:32  rherveille
+//               Core is now a Multimaster I2C controller
+//
+//               Revision 1.5  2002/11/30 22:24:40  rherveille
+//               Cleaned up code
+//
+//               Revision 1.4  2002/10/30 18:10:07  rherveille
+//               Fixed some reported minor start/stop generation timing issuess.
+//
+//               Revision 1.3  2002/06/15 07:37:03  rherveille
+//               Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment.
+//
+//               Revision 1.2  2001/11/05 11:59:25  rherveille
+//               Fixed wb_ack_o generation bug.
+//               Fixed bug in the byte_controller statemachine.
+//               Added headers.
+//
+
+//
+/////////////////////////////////////
+// Bit controller section
+/////////////////////////////////////
+//
+// Translate simple commands into SCL/SDA transitions
+// Each command has 5 states, A/B/C/D/idle
+//
+// start:      SCL     ~~~~~~~~~~\____
+//     SDA     ~~~~~~~~\______
+//              x | A | B | C | D | i
+//
+// repstart    SCL     ____/~~~~\___
+//     SDA     __/~~~\______
+//              x | A | B | C | D | i
+//
+// stop        SCL     ____/~~~~~~~~
+//     SDA     ==\____/~~~~~
+//              x | A | B | C | D | i
+//
+//- write      SCL     ____/~~~~\____
+//     SDA     ==X=========X=
+//              x | A | B | C | D | i
+//
+//- read       SCL     ____/~~~~\____
+//     SDA     XXXX=====XXXX
+//              x | A | B | C | D | i
+//
+
+// Timing:     Normal mode      Fast mode
+///////////////////////////////////////////////////////////////////////
+// Fscl        100KHz           400KHz
+// Th_scl      4.0us            0.6us   High period of SCL
+// Tl_scl      4.7us            1.3us   Low period of SCL
+// Tsu:sta     4.7us            0.6us   setup time for a repeated start condition
+// Tsu:sto     4.0us            0.6us   setup time for a stop conditon
+// Tbuf        4.7us            1.3us   Bus free time between a stop and start condition
+//
+
+// synopsys translate_off
+`include "timescale.v"
+// synopsys translate_on
+
+`include "i2c_master_defines.v"
+
+module i2c_master_bit_ctrl(
+       clk, rst, nReset, 
+       clk_cnt, ena, cmd, cmd_ack, busy, al, din, dout,
+       scl_i, scl_o, scl_oen, sda_i, sda_o, sda_oen
+       );
+
+       //
+       // inputs & outputs
+       //
+       input clk;
+       input rst;
+       input nReset;
+       input ena;            // core enable signal
+
+       input [15:0] clk_cnt; // clock prescale value
+
+       input  [3:0] cmd;
+       output       cmd_ack; // command complete acknowledge
+       reg cmd_ack;
+       output       busy;    // i2c bus busy
+       reg busy;
+       output       al;      // i2c bus arbitration lost
+       reg al;
+
+       input  din;
+       output dout;
+       reg dout;
+
+       // I2C lines
+       input  scl_i;         // i2c clock line input
+       output scl_o;         // i2c clock line output
+       output scl_oen;       // i2c clock line output enable (active low)
+       reg scl_oen;
+       input  sda_i;         // i2c data line input
+       output sda_o;         // i2c data line output
+       output sda_oen;       // i2c data line output enable (active low)
+       reg sda_oen;
+
+
+       //
+       // variable declarations
+       //
+
+       reg sSCL, sSDA;             // synchronized SCL and SDA inputs
+       reg dscl_oen;               // delayed scl_oen
+       reg sda_chk;                // check SDA output (Multi-master arbitration)
+       reg clk_en;                 // clock generation signals
+       wire slave_wait;
+//     reg [15:0] cnt = clk_cnt;   // clock divider counter (simulation)
+       reg [15:0] cnt;             // clock divider counter (synthesis)
+
+       // state machine variable
+       reg [16:0] c_state; // synopsys enum_state
+
+       //
+       // module body
+       //
+
+       // whenever the slave is not ready it can delay the cycle by pulling SCL low
+       // delay scl_oen
+       always @(posedge clk)
+         dscl_oen <= #1 scl_oen;
+
+       assign slave_wait = dscl_oen && !sSCL;
+
+
+       // generate clk enable signal
+       always @(posedge clk or negedge nReset)
+         if(~nReset)
+           begin
+               cnt    <= #1 16'h0;
+               clk_en <= #1 1'b1;
+           end
+         else if (rst)
+           begin
+               cnt    <= #1 16'h0;
+               clk_en <= #1 1'b1;
+           end
+         else if ( ~|cnt || ~ena)
+           if (~slave_wait)
+             begin
+                 cnt    <= #1 clk_cnt;
+                 clk_en <= #1 1'b1;
+             end
+           else
+             begin
+                 cnt    <= #1 cnt;
+                 clk_en <= #1 1'b0;
+             end
+         else
+           begin
+                cnt    <= #1 cnt - 16'h1;
+               clk_en <= #1 1'b0;
+           end
+
+
+       // generate bus status controller
+       reg dSCL, dSDA;
+       reg sta_condition;
+       reg sto_condition;
+
+       // synchronize SCL and SDA inputs
+       // reduce metastability risc
+       always @(posedge clk or negedge nReset)
+         if (~nReset)
+           begin
+               sSCL <= #1 1'b1;
+               sSDA <= #1 1'b1;
+
+               dSCL <= #1 1'b1;
+               dSDA <= #1 1'b1;
+           end
+         else if (rst)
+           begin
+               sSCL <= #1 1'b1;
+               sSDA <= #1 1'b1;
+
+               dSCL <= #1 1'b1;
+               dSDA <= #1 1'b1;
+           end
+         else
+           begin
+               sSCL <= #1 scl_i;
+               sSDA <= #1 sda_i;
+
+               dSCL <= #1 sSCL;
+               dSDA <= #1 sSDA;
+           end
+
+       // detect start condition => detect falling edge on SDA while SCL is high
+       // detect stop condition => detect rising edge on SDA while SCL is high
+       always @(posedge clk or negedge nReset)
+         if (~nReset)
+           begin
+               sta_condition <= #1 1'b0;
+               sto_condition <= #1 1'b0;
+           end
+         else if (rst)
+           begin
+               sta_condition <= #1 1'b0;
+               sto_condition <= #1 1'b0;
+           end
+         else
+           begin
+               sta_condition <= #1 ~sSDA &  dSDA & sSCL;
+               sto_condition <= #1  sSDA & ~dSDA & sSCL;
+           end
+
+       // generate i2c bus busy signal
+       always @(posedge clk or negedge nReset)
+         if(!nReset)
+           busy <= #1 1'b0;
+         else if (rst)
+           busy <= #1 1'b0;
+         else
+           busy <= #1 (sta_condition | busy) & ~sto_condition;
+
+       // generate arbitration lost signal
+       // aribitration lost when:
+       // 1) master drives SDA high, but the i2c bus is low
+       // 2) stop detected while not requested
+       reg cmd_stop;
+       always @(posedge clk or negedge nReset)
+         if (~nReset)
+           cmd_stop <= #1 1'b0;
+         else if (rst)
+           cmd_stop <= #1 1'b0;
+         else if (clk_en)
+           cmd_stop <= #1 cmd == `I2C_CMD_STOP;
+
+       always @(posedge clk or negedge nReset)
+         if (~nReset)
+           al <= #1 1'b0;
+         else if (rst)
+           al <= #1 1'b0;
+         else
+           al <= #1 (sda_chk & ~sSDA & sda_oen) | (|c_state & sto_condition & ~cmd_stop);
+
+
+       // generate dout signal (store SDA on rising edge of SCL)
+       always @(posedge clk)
+         if(sSCL & ~dSCL)
+           dout <= #1 sSDA;
+
+       // generate statemachine
+
+       // nxt_state decoder
+       parameter [16:0] idle    = 17'b0_0000_0000_0000_0000;
+       parameter [16:0] start_a = 17'b0_0000_0000_0000_0001;
+       parameter [16:0] start_b = 17'b0_0000_0000_0000_0010;
+       parameter [16:0] start_c = 17'b0_0000_0000_0000_0100;
+       parameter [16:0] start_d = 17'b0_0000_0000_0000_1000;
+       parameter [16:0] start_e = 17'b0_0000_0000_0001_0000;
+       parameter [16:0] stop_a  = 17'b0_0000_0000_0010_0000;
+       parameter [16:0] stop_b  = 17'b0_0000_0000_0100_0000;
+       parameter [16:0] stop_c  = 17'b0_0000_0000_1000_0000;
+       parameter [16:0] stop_d  = 17'b0_0000_0001_0000_0000;
+       parameter [16:0] rd_a    = 17'b0_0000_0010_0000_0000;
+       parameter [16:0] rd_b    = 17'b0_0000_0100_0000_0000;
+       parameter [16:0] rd_c    = 17'b0_0000_1000_0000_0000;
+       parameter [16:0] rd_d    = 17'b0_0001_0000_0000_0000;
+       parameter [16:0] wr_a    = 17'b0_0010_0000_0000_0000;
+       parameter [16:0] wr_b    = 17'b0_0100_0000_0000_0000;
+       parameter [16:0] wr_c    = 17'b0_1000_0000_0000_0000;
+       parameter [16:0] wr_d    = 17'b1_0000_0000_0000_0000;
+
+       always @(posedge clk or negedge nReset)
+         if (!nReset)
+           begin
+               c_state <= #1 idle;
+               cmd_ack <= #1 1'b0;
+               scl_oen <= #1 1'b1;
+               sda_oen <= #1 1'b1;
+               sda_chk <= #1 1'b0;
+           end
+         else if (rst | al)
+           begin
+               c_state <= #1 idle;
+               cmd_ack <= #1 1'b0;
+               scl_oen <= #1 1'b1;
+               sda_oen <= #1 1'b1;
+               sda_chk <= #1 1'b0;
+           end
+         else
+           begin
+               cmd_ack   <= #1 1'b0; // default no command acknowledge + assert cmd_ack only 1clk cycle
+
+               if (clk_en)
+                 case (c_state) // synopsys full_case parallel_case
+                   // idle state
+                   idle:
+                   begin
+                       case (cmd) // synopsys full_case parallel_case
+                         `I2C_CMD_START:
+                            c_state <= #1 start_a;
+
+                         `I2C_CMD_STOP:
+                            c_state <= #1 stop_a;
+
+                         `I2C_CMD_WRITE:
+                            c_state <= #1 wr_a;
+
+                         `I2C_CMD_READ:
+                            c_state <= #1 rd_a;
+
+                         default:
+                           c_state <= #1 idle;
+                       endcase
+
+                       scl_oen <= #1 scl_oen; // keep SCL in same state
+                       sda_oen <= #1 sda_oen; // keep SDA in same state
+                       sda_chk <= #1 1'b0;    // don't check SDA output
+                   end
+
+                   // start
+                   start_a:
+                   begin
+                       c_state <= #1 start_b;
+                       scl_oen <= #1 scl_oen; // keep SCL in same state
+                       sda_oen <= #1 1'b1;    // set SDA high
+                       sda_chk <= #1 1'b0;    // don't check SDA output
+                   end
+
+                   start_b:
+                   begin
+                       c_state <= #1 start_c;
+                       scl_oen <= #1 1'b1; // set SCL high
+                       sda_oen <= #1 1'b1; // keep SDA high
+                       sda_chk <= #1 1'b0; // don't check SDA output
+                   end
+
+                   start_c:
+                   begin
+                       c_state <= #1 start_d;
+                       scl_oen <= #1 1'b1; // keep SCL high
+                       sda_oen <= #1 1'b0; // set SDA low
+                       sda_chk <= #1 1'b0; // don't check SDA output
+                   end
+
+                   start_d:
+                   begin
+                       c_state <= #1 start_e;
+                       scl_oen <= #1 1'b1; // keep SCL high
+                       sda_oen <= #1 1'b0; // keep SDA low
+                       sda_chk <= #1 1'b0; // don't check SDA output
+                   end
+
+                   start_e:
+                   begin
+                       c_state <= #1 idle;
+                       cmd_ack <= #1 1'b1;
+                       scl_oen <= #1 1'b0; // set SCL low
+                       sda_oen <= #1 1'b0; // keep SDA low
+                       sda_chk <= #1 1'b0; // don't check SDA output
+                   end
+
+                   // stop
+                   stop_a:
+                   begin
+                       c_state <= #1 stop_b;
+                       scl_oen <= #1 1'b0; // keep SCL low
+                       sda_oen <= #1 1'b0; // set SDA low
+                       sda_chk <= #1 1'b0; // don't check SDA output
+                   end
+
+                   stop_b:
+                   begin
+                       c_state <= #1 stop_c;
+                       scl_oen <= #1 1'b1; // set SCL high
+                       sda_oen <= #1 1'b0; // keep SDA low
+                       sda_chk <= #1 1'b0; // don't check SDA output
+                   end
+
+                   stop_c:
+                   begin
+                       c_state <= #1 stop_d;
+                       scl_oen <= #1 1'b1; // keep SCL high
+                       sda_oen <= #1 1'b0; // keep SDA low
+                       sda_chk <= #1 1'b0; // don't check SDA output
+                   end
+
+                   stop_d:
+                   begin
+                       c_state <= #1 idle;
+                       cmd_ack <= #1 1'b1;
+                       scl_oen <= #1 1'b1; // keep SCL high
+                       sda_oen <= #1 1'b1; // set SDA high
+                       sda_chk <= #1 1'b0; // don't check SDA output
+                   end
+
+                   // read
+                   rd_a:
+                   begin
+                       c_state <= #1 rd_b;
+                       scl_oen <= #1 1'b0; // keep SCL low
+                       sda_oen <= #1 1'b1; // tri-state SDA
+                       sda_chk <= #1 1'b0; // don't check SDA output
+                   end
+
+                   rd_b:
+                   begin
+                       c_state <= #1 rd_c;
+                       scl_oen <= #1 1'b1; // set SCL high
+                       sda_oen <= #1 1'b1; // keep SDA tri-stated
+                       sda_chk <= #1 1'b0; // don't check SDA output
+                   end
+
+                   rd_c:
+                   begin
+                       c_state <= #1 rd_d;
+                       scl_oen <= #1 1'b1; // keep SCL high
+                       sda_oen <= #1 1'b1; // keep SDA tri-stated
+                       sda_chk <= #1 1'b0; // don't check SDA output
+                   end
+
+                   rd_d:
+                   begin
+                       c_state <= #1 idle;
+                       cmd_ack <= #1 1'b1;
+                       scl_oen <= #1 1'b0; // set SCL low
+                       sda_oen <= #1 1'b1; // keep SDA tri-stated
+                       sda_chk <= #1 1'b0; // don't check SDA output
+                   end
+
+                   // write
+                   wr_a:
+                   begin
+                       c_state <= #1 wr_b;
+                       scl_oen <= #1 1'b0; // keep SCL low
+                       sda_oen <= #1 din;  // set SDA
+                       sda_chk <= #1 1'b0; // don't check SDA output (SCL low)
+                   end
+
+                   wr_b:
+                   begin
+                       c_state <= #1 wr_c;
+                       scl_oen <= #1 1'b1; // set SCL high
+                       sda_oen <= #1 din;  // keep SDA
+                       sda_chk <= #1 1'b1; // check SDA output
+                   end
+
+                   wr_c:
+                   begin
+                       c_state <= #1 wr_d;
+                       scl_oen <= #1 1'b1; // keep SCL high
+                       sda_oen <= #1 din;
+                       sda_chk <= #1 1'b1; // check SDA output
+                   end
+
+                   wr_d:
+                   begin
+                       c_state <= #1 idle;
+                       cmd_ack <= #1 1'b1;
+                       scl_oen <= #1 1'b0; // set SCL low
+                       sda_oen <= #1 din;
+                       sda_chk <= #1 1'b0; // don't check SDA output (SCL low)
+                   end
+
+                 endcase
+           end
+
+
+       // assign scl and sda output (always gnd)
+       assign scl_o = 1'b0;
+       assign sda_o = 1'b0;
+
+endmodule
diff --git a/tests/iwls2005/i2c/i2c_master_byte_ctrl.v b/tests/iwls2005/i2c/i2c_master_byte_ctrl.v
new file mode 100644 (file)
index 0000000..d091d1e
--- /dev/null
@@ -0,0 +1,344 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE rev.B2 compliant I2C Master byte-controller       ////
+////                                                             ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: i2c_master_byte_ctrl.v,v 1.7 2004/02/18 11:40:46 rherveille Exp $
+//
+//  $Date: 2004/02/18 11:40:46 $
+//  $Revision: 1.7 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: i2c_master_byte_ctrl.v,v $
+//               Revision 1.7  2004/02/18 11:40:46  rherveille
+//               Fixed a potential bug in the statemachine. During a 'stop' 2 cmd_ack signals were generated. Possibly canceling a new start command.
+//
+//               Revision 1.6  2003/08/09 07:01:33  rherveille
+//               Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
+//               Fixed a potential bug in the byte controller's host-acknowledge generation.
+//
+//               Revision 1.5  2002/12/26 15:02:32  rherveille
+//               Core is now a Multimaster I2C controller
+//
+//               Revision 1.4  2002/11/30 22:24:40  rherveille
+//               Cleaned up code
+//
+//               Revision 1.3  2001/11/05 11:59:25  rherveille
+//               Fixed wb_ack_o generation bug.
+//               Fixed bug in the byte_controller statemachine.
+//               Added headers.
+//
+
+// synopsys translate_off
+`include "timescale.v"
+// synopsys translate_on
+
+`include "i2c_master_defines.v"
+
+module i2c_master_byte_ctrl (
+       clk, rst, nReset, ena, clk_cnt, start, stop, read, write, ack_in, din,
+       cmd_ack, ack_out, dout, i2c_busy, i2c_al, scl_i, scl_o, scl_oen, sda_i, sda_o, sda_oen );
+
+       //
+       // inputs & outputs
+       //
+       input clk;     // master clock
+       input rst;     // synchronous active high reset
+       input nReset;  // asynchronous active low reset
+       input ena;     // core enable signal
+
+       input [15:0] clk_cnt; // 4x SCL
+
+       // control inputs
+       input       start;
+       input       stop;
+       input       read;
+       input       write;
+       input       ack_in;
+       input [7:0] din;
+
+       // status outputs
+       output       cmd_ack;
+       reg cmd_ack;
+       output       ack_out;
+       reg ack_out;
+       output       i2c_busy;
+       output       i2c_al;
+       output [7:0] dout;
+
+       // I2C signals
+       input  scl_i;
+       output scl_o;
+       output scl_oen;
+       input  sda_i;
+       output sda_o;
+       output sda_oen;
+
+
+       //
+       // Variable declarations
+       //
+
+       // statemachine
+       parameter [4:0] ST_IDLE  = 5'b0_0000;
+       parameter [4:0] ST_START = 5'b0_0001;
+       parameter [4:0] ST_READ  = 5'b0_0010;
+       parameter [4:0] ST_WRITE = 5'b0_0100;
+       parameter [4:0] ST_ACK   = 5'b0_1000;
+       parameter [4:0] ST_STOP  = 5'b1_0000;
+
+       // signals for bit_controller
+       reg  [3:0] core_cmd;
+       reg        core_txd;
+       wire       core_ack, core_rxd;
+
+       // signals for shift register
+       reg [7:0] sr; //8bit shift register
+       reg       shift, ld;
+
+       // signals for state machine
+       wire       go;
+       reg  [2:0] dcnt;
+       wire       cnt_done;
+
+       //
+       // Module body
+       //
+
+       // hookup bit_controller
+       i2c_master_bit_ctrl bit_controller (
+               .clk     ( clk      ),
+               .rst     ( rst      ),
+               .nReset  ( nReset   ),
+               .ena     ( ena      ),
+               .clk_cnt ( clk_cnt  ),
+               .cmd     ( core_cmd ),
+               .cmd_ack ( core_ack ),
+               .busy    ( i2c_busy ),
+               .al      ( i2c_al   ),
+               .din     ( core_txd ),
+               .dout    ( core_rxd ),
+               .scl_i   ( scl_i    ),
+               .scl_o   ( scl_o    ),
+               .scl_oen ( scl_oen  ),
+               .sda_i   ( sda_i    ),
+               .sda_o   ( sda_o    ),
+               .sda_oen ( sda_oen  )
+       );
+
+       // generate go-signal
+       assign go = (read | write | stop) & ~cmd_ack;
+
+       // assign dout output to shift-register
+       assign dout = sr;
+
+       // generate shift register
+       always @(posedge clk or negedge nReset)
+         if (!nReset)
+           sr <= #1 8'h0;
+         else if (rst)
+           sr <= #1 8'h0;
+         else if (ld)
+           sr <= #1 din;
+         else if (shift)
+           sr <= #1 {sr[6:0], core_rxd};
+
+       // generate counter
+       always @(posedge clk or negedge nReset)
+         if (!nReset)
+           dcnt <= #1 3'h0;
+         else if (rst)
+           dcnt <= #1 3'h0;
+         else if (ld)
+           dcnt <= #1 3'h7;
+         else if (shift)
+           dcnt <= #1 dcnt - 3'h1;
+
+       assign cnt_done = ~(|dcnt);
+
+       //
+       // state machine
+       //
+       reg [4:0] c_state; // synopsis enum_state
+
+       always @(posedge clk or negedge nReset)
+         if (!nReset)
+           begin
+               core_cmd <= #1 `I2C_CMD_NOP;
+               core_txd <= #1 1'b0;
+               shift    <= #1 1'b0;
+               ld       <= #1 1'b0;
+               cmd_ack  <= #1 1'b0;
+               c_state  <= #1 ST_IDLE;
+               ack_out  <= #1 1'b0;
+           end
+         else if (rst | i2c_al)
+          begin
+              core_cmd <= #1 `I2C_CMD_NOP;
+              core_txd <= #1 1'b0;
+              shift    <= #1 1'b0;
+              ld       <= #1 1'b0;
+              cmd_ack  <= #1 1'b0;
+              c_state  <= #1 ST_IDLE;
+              ack_out  <= #1 1'b0;
+          end
+       else
+         begin
+             // initially reset all signals
+             core_txd <= #1 sr[7];
+             shift    <= #1 1'b0;
+             ld       <= #1 1'b0;
+             cmd_ack  <= #1 1'b0;
+
+             case (c_state) // synopsys full_case parallel_case
+               ST_IDLE:
+                 if (go)
+                   begin
+                       if (start)
+                         begin
+                             c_state  <= #1 ST_START;
+                             core_cmd <= #1 `I2C_CMD_START;
+                         end
+                       else if (read)
+                         begin
+                             c_state  <= #1 ST_READ;
+                             core_cmd <= #1 `I2C_CMD_READ;
+                         end
+                       else if (write)
+                         begin
+                             c_state  <= #1 ST_WRITE;
+                             core_cmd <= #1 `I2C_CMD_WRITE;
+                         end
+                       else // stop
+                         begin
+                             c_state  <= #1 ST_STOP;
+                             core_cmd <= #1 `I2C_CMD_STOP;
+                         end
+
+                       ld <= #1 1'b1;
+                   end
+
+               ST_START:
+                 if (core_ack)
+                   begin
+                       if (read)
+                         begin
+                             c_state  <= #1 ST_READ;
+                             core_cmd <= #1 `I2C_CMD_READ;
+                         end
+                       else
+                         begin
+                             c_state  <= #1 ST_WRITE;
+                             core_cmd <= #1 `I2C_CMD_WRITE;
+                         end
+
+                       ld <= #1 1'b1;
+                   end
+
+               ST_WRITE:
+                 if (core_ack)
+                   if (cnt_done)
+                     begin
+                         c_state  <= #1 ST_ACK;
+                         core_cmd <= #1 `I2C_CMD_READ;
+                     end
+                   else
+                     begin
+                         c_state  <= #1 ST_WRITE;       // stay in same state
+                         core_cmd <= #1 `I2C_CMD_WRITE; // write next bit
+                         shift    <= #1 1'b1;
+                     end
+
+               ST_READ:
+                 if (core_ack)
+                   begin
+                       if (cnt_done)
+                         begin
+                             c_state  <= #1 ST_ACK;
+                             core_cmd <= #1 `I2C_CMD_WRITE;
+                         end
+                       else
+                         begin
+                             c_state  <= #1 ST_READ;       // stay in same state
+                             core_cmd <= #1 `I2C_CMD_READ; // read next bit
+                         end
+
+                       shift    <= #1 1'b1;
+                       core_txd <= #1 ack_in;
+                   end
+
+               ST_ACK:
+                 if (core_ack)
+                   begin
+                      if (stop)
+                        begin
+                            c_state  <= #1 ST_STOP;
+                            core_cmd <= #1 `I2C_CMD_STOP;
+                        end
+                      else
+                        begin
+                            c_state  <= #1 ST_IDLE;
+                            core_cmd <= #1 `I2C_CMD_NOP;
+
+                            // generate command acknowledge signal
+                            cmd_ack  <= #1 1'b1;
+                        end
+
+                        // assign ack_out output to bit_controller_rxd (contains last received bit)
+                        ack_out <= #1 core_rxd;
+
+                        core_txd <= #1 1'b1;
+                    end
+                  else
+                    core_txd <= #1 ack_in;
+
+               ST_STOP:
+                 if (core_ack)
+                   begin
+                       c_state  <= #1 ST_IDLE;
+                       core_cmd <= #1 `I2C_CMD_NOP;
+
+                       // generate command acknowledge signal
+                       cmd_ack  <= #1 1'b1;
+                   end
+
+             endcase
+         end
+endmodule
diff --git a/tests/iwls2005/i2c/i2c_master_defines.v b/tests/iwls2005/i2c/i2c_master_defines.v
new file mode 100644 (file)
index 0000000..ee3b694
--- /dev/null
@@ -0,0 +1,64 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE rev.B2 compliant I2C Master controller defines    ////
+////                                                             ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: i2c_master_defines.v,v 1.3 2001/11/05 11:59:25 rherveille Exp $
+//
+//  $Date: 2001/11/05 11:59:25 $
+//  $Revision: 1.3 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: i2c_master_defines.v,v $
+//               Revision 1.3  2001/11/05 11:59:25  rherveille
+//               Fixed wb_ack_o generation bug.
+//               Fixed bug in the byte_controller statemachine.
+//               Added headers.
+//
+
+
+// I2C registers wishbone addresses
+
+// bitcontroller states
+`define I2C_CMD_NOP   4'b0000
+`define I2C_CMD_START 4'b0001
+`define I2C_CMD_STOP  4'b0010
+`define I2C_CMD_WRITE 4'b0100
+`define I2C_CMD_READ  4'b1000
diff --git a/tests/iwls2005/i2c/i2c_master_top.v b/tests/iwls2005/i2c/i2c_master_top.v
new file mode 100644 (file)
index 0000000..30689bd
--- /dev/null
@@ -0,0 +1,301 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE revB.2 compliant I2C Master controller Top-level  ////
+////                                                             ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: i2c_master_top.v,v 1.11 2005/02/27 09:26:24 rherveille Exp $
+//
+//  $Date: 2005/02/27 09:26:24 $
+//  $Revision: 1.11 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: i2c_master_top.v,v $
+//               Revision 1.11  2005/02/27 09:26:24  rherveille
+//               Fixed register overwrite issue.
+//               Removed full_case pragma, replaced it by a default statement.
+//
+//               Revision 1.10  2003/09/01 10:34:38  rherveille
+//               Fix a blocking vs. non-blocking error in the wb_dat output mux.
+//
+//               Revision 1.9  2003/01/09 16:44:45  rherveille
+//               Fixed a bug in the Command Register declaration.
+//
+//               Revision 1.8  2002/12/26 16:05:12  rherveille
+//               Small code simplifications
+//
+//               Revision 1.7  2002/12/26 15:02:32  rherveille
+//               Core is now a Multimaster I2C controller
+//
+//               Revision 1.6  2002/11/30 22:24:40  rherveille
+//               Cleaned up code
+//
+//               Revision 1.5  2001/11/10 10:52:55  rherveille
+//               Changed PRER reset value from 0x0000 to 0xffff, conform specs.
+//
+
+// synopsys translate_off
+`include "timescale.v"
+// synopsys translate_on
+
+`include "i2c_master_defines.v"
+
+module i2c_master_top(
+       wb_clk_i, wb_rst_i, arst_i, wb_adr_i, wb_dat_i, wb_dat_o,
+       wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_inta_o,
+       scl_pad_i, scl_pad_o, scl_padoen_o, sda_pad_i, sda_pad_o, sda_padoen_o );
+
+       // parameters
+       parameter ARST_LVL = 1'b0; // asynchronous reset level
+
+       //
+       // inputs & outputs
+       //
+
+       // wishbone signals
+       input        wb_clk_i;     // master clock input
+       input        wb_rst_i;     // synchronous active high reset
+       input        arst_i;       // asynchronous reset
+       input  [2:0] wb_adr_i;     // lower address bits
+       input  [7:0] wb_dat_i;     // databus input
+       output [7:0] wb_dat_o;     // databus output
+       input        wb_we_i;      // write enable input
+       input        wb_stb_i;     // stobe/core select signal
+       input        wb_cyc_i;     // valid bus cycle input
+       output       wb_ack_o;     // bus cycle acknowledge output
+       output       wb_inta_o;    // interrupt request signal output
+
+       reg [7:0] wb_dat_o;
+       reg wb_ack_o;
+       reg wb_inta_o;
+
+       // I2C signals
+       // i2c clock line
+       input  scl_pad_i;       // SCL-line input
+       output scl_pad_o;       // SCL-line output (always 1'b0)
+       output scl_padoen_o;    // SCL-line output enable (active low)
+
+       // i2c data line
+       input  sda_pad_i;       // SDA-line input
+       output sda_pad_o;       // SDA-line output (always 1'b0)
+       output sda_padoen_o;    // SDA-line output enable (active low)
+
+
+       //
+       // variable declarations
+       //
+
+       // registers
+       reg  [15:0] prer; // clock prescale register
+       reg  [ 7:0] ctr;  // control register
+       reg  [ 7:0] txr;  // transmit register
+       wire [ 7:0] rxr;  // receive register
+       reg  [ 7:0] cr;   // command register
+       wire [ 7:0] sr;   // status register
+
+       // done signal: command completed, clear command register
+       wire done;
+
+       // core enable signal
+       wire core_en;
+       wire ien;
+
+       // status register signals
+       wire irxack;
+       reg  rxack;       // received aknowledge from slave
+       reg  tip;         // transfer in progress
+       reg  irq_flag;    // interrupt pending flag
+       wire i2c_busy;    // bus busy (start signal detected)
+       wire i2c_al;      // i2c bus arbitration lost
+       reg  al;          // status register arbitration lost bit
+
+       //
+       // module body
+       //
+
+       // generate internal reset
+       wire rst_i = arst_i ^ ARST_LVL;
+
+       // generate wishbone signals
+       wire wb_wacc = wb_cyc_i & wb_stb_i & wb_we_i;
+
+       // generate acknowledge output signal
+       always @(posedge wb_clk_i)
+         wb_ack_o <= #1 wb_cyc_i & wb_stb_i & ~wb_ack_o; // because timing is always honored
+
+       // assign DAT_O
+       always @(posedge wb_clk_i)
+       begin
+         case (wb_adr_i) // synopsis parallel_case
+           3'b000: wb_dat_o <= #1 prer[ 7:0];
+           3'b001: wb_dat_o <= #1 prer[15:8];
+           3'b010: wb_dat_o <= #1 ctr;
+           3'b011: wb_dat_o <= #1 rxr; // write is transmit register (txr)
+           3'b100: wb_dat_o <= #1 sr;  // write is command register (cr)
+           3'b101: wb_dat_o <= #1 txr;
+           3'b110: wb_dat_o <= #1 cr;
+           3'b111: wb_dat_o <= #1 0;   // reserved
+         endcase
+       end
+
+       // generate registers
+       always @(posedge wb_clk_i or negedge rst_i)
+         if (!rst_i)
+           begin
+               prer <= #1 16'hffff;
+               ctr  <= #1  8'h0;
+               txr  <= #1  8'h0;
+           end
+         else if (wb_rst_i)
+           begin
+               prer <= #1 16'hffff;
+               ctr  <= #1  8'h0;
+               txr  <= #1  8'h0;
+           end
+         else
+           if (wb_wacc)
+             case (wb_adr_i) // synopsis parallel_case
+                3'b000 : prer [ 7:0] <= #1 wb_dat_i;
+                3'b001 : prer [15:8] <= #1 wb_dat_i;
+                3'b010 : ctr         <= #1 wb_dat_i;
+                3'b011 : txr         <= #1 wb_dat_i;
+                default: ;
+             endcase
+
+       // generate command register (special case)
+       always @(posedge wb_clk_i or negedge rst_i)
+         if (~rst_i)
+           cr <= #1 8'h0;
+         else if (wb_rst_i)
+           cr <= #1 8'h0;
+         else if (wb_wacc)
+           begin
+               if (core_en & (wb_adr_i == 3'b100) )
+                 cr <= #1 wb_dat_i;
+           end
+         else
+           begin
+               if (done | i2c_al)
+                 cr[7:4] <= #1 4'h0;           // clear command bits when done
+                                               // or when aribitration lost
+               cr[2:1] <= #1 2'b0;             // reserved bits
+               cr[0]   <= #1 2'b0;             // clear IRQ_ACK bit
+           end
+
+
+       // decode command register
+       wire sta  = cr[7];
+       wire sto  = cr[6];
+       wire rd   = cr[5];
+       wire wr   = cr[4];
+       wire ack  = cr[3];
+       wire iack = cr[0];
+
+       // decode control register
+       assign core_en = ctr[7];
+       assign ien = ctr[6];
+
+       // hookup byte controller block
+       i2c_master_byte_ctrl byte_controller (
+               .clk      ( wb_clk_i     ),
+               .rst      ( wb_rst_i     ),
+               .nReset   ( rst_i        ),
+               .ena      ( core_en      ),
+               .clk_cnt  ( prer         ),
+               .start    ( sta          ),
+               .stop     ( sto          ),
+               .read     ( rd           ),
+               .write    ( wr           ),
+               .ack_in   ( ack          ),
+               .din      ( txr          ),
+               .cmd_ack  ( done         ),
+               .ack_out  ( irxack       ),
+               .dout     ( rxr          ),
+               .i2c_busy ( i2c_busy     ),
+               .i2c_al   ( i2c_al       ),
+               .scl_i    ( scl_pad_i    ),
+               .scl_o    ( scl_pad_o    ),
+               .scl_oen  ( scl_padoen_o ),
+               .sda_i    ( sda_pad_i    ),
+               .sda_o    ( sda_pad_o    ),
+               .sda_oen  ( sda_padoen_o )
+       );
+
+       // status register block + interrupt request signal
+       always @(posedge wb_clk_i or negedge rst_i)
+         if (!rst_i)
+           begin
+               al       <= #1 1'b0;
+               rxack    <= #1 1'b0;
+               tip      <= #1 1'b0;
+               irq_flag <= #1 1'b0;
+           end
+         else if (wb_rst_i)
+           begin
+               al       <= #1 1'b0;
+               rxack    <= #1 1'b0;
+               tip      <= #1 1'b0;
+               irq_flag <= #1 1'b0;
+           end
+         else
+           begin
+               al       <= #1 i2c_al | (al & ~sta);
+               rxack    <= #1 irxack;
+               tip      <= #1 (rd | wr);
+               irq_flag <= #1 (done | i2c_al | irq_flag) & ~iack; // interrupt request flag is always generated
+           end
+
+       // generate interrupt request signals
+       always @(posedge wb_clk_i or negedge rst_i)
+         if (!rst_i)
+           wb_inta_o <= #1 1'b0;
+         else if (wb_rst_i)
+           wb_inta_o <= #1 1'b0;
+         else
+           wb_inta_o <= #1 irq_flag && ien; // interrupt signal is only generated when IEN (interrupt enable bit is set)
+
+       // assign status register bits
+       assign sr[7]   = rxack;
+       assign sr[6]   = i2c_busy;
+       assign sr[5]   = al;
+       assign sr[4:2] = 3'h0; // reserved
+       assign sr[1]   = tip;
+       assign sr[0]   = irq_flag;
+
+endmodule
diff --git a/tests/iwls2005/i2c/timescale.v b/tests/iwls2005/i2c/timescale.v
new file mode 100644 (file)
index 0000000..60d4ecb
--- /dev/null
@@ -0,0 +1,2 @@
+`timescale 1ns / 10ps
+
diff --git a/tests/iwls2005/run-fm.sh b/tests/iwls2005/run-fm.sh
new file mode 100755 (executable)
index 0000000..14bb4e8
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+if [ -n "$REMOTE_YOSYS_ROOT" ]; then
+       rsync --exclude=".svn" --exclude="synth.log" --exclude="run-fm.sh" -rv -e "${REMOTE_YOSYS_SSH:-ssh}" "$REMOTE_YOSYS_ROOT"/tests/iwls2005/. .
+fi
+
+exec_fm()
+{
+       dir=$1; top=$2; shift; shift
+       cat > $dir/fm.do <<- EOT
+               set hdlin_ignore_full_case false
+               set hdlin_warn_on_mismatch_message "FMR_ELAB-115 FMR_ELAB-146 FMR_ELAB-147"
+               read_verilog -container r -libname WORK -01 { $* } 
+               set_top r:/WORK/$top
+               read_verilog -container i -libname WORK -01 synth.v
+               # read_verilog -container i -technology_library -libname TECH_WORK -01 ../../../techlibs/stdcells_sim.v
+               set_top i:/WORK/$top
+               if ![verify] start_gui exit
+       EOT
+       ( cd $dir; fm_shell -64 -file fm.do 2>&1 | tee fm.log; )
+}
+
+# cores that validated
+exec_fm aes_core aes_cipher_top aes_cipher_top.v aes_inv_cipher_top.v aes_inv_sbox.v aes_key_expand_128.v aes_rcon.v aes_sbox.v
+exec_fm i2c i2c_master_top i2c_master_top.v i2c_master_bit_ctrl.v i2c_master_byte_ctrl.v
+exec_fm sasc sasc_top sasc_top.v sasc_brg.v sasc_fifo4.v
+exec_fm simple_spi simple_spi_top simple_spi_top.v fifo4.v
+exec_fm spi spi_top spi_top.v spi_clgen.v spi_shift.v
+exec_fm ss_pcm pcm_slv_top pcm_slv_top.v
+exec_fm systemcaes aes aes.v byte_mixcolum.v keysched.v mixcolum.v sbox.v subbytes.v word_mixcolum.v
+exec_fm usb_phy usb_phy usb_phy.v usb_rx_phy.v usb_tx_phy.v
+
+# cores with known problems (the fpu core unfortunately was designed with logic loops)
+#exec_fm fpu fpu fpu.v except.v post_norm.v pre_norm_fmul.v pre_norm.v primitives.v
+
+# summary
+echo; echo
+for x in */fm.log; do
+       echo -e "${x%/*}\\t$( egrep '^Verification (SUCCEEDED|FAILED)' $x; )"
+done | expand -t15
+echo; echo
+
diff --git a/tests/iwls2005/run-synth.sh b/tests/iwls2005/run-synth.sh
new file mode 100755 (executable)
index 0000000..2f1e306
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+make -C ../..
+set -x
+
+vg=""
+# vg="valgrind --leak-check=full --show-reachable=yes --log-file=valgrind.log"
+
+cd aes_core
+time $vg ../../../yosys -qt -l synth.log -o synth.v -s ../run-synth.ys \
+       aes_cipher_top.v aes_inv_cipher_top.v aes_inv_sbox.v \
+       aes_key_expand_128.v aes_rcon.v aes_sbox.v
+
+cd ../fpu
+time $vg ../../../yosys -qt -l synth.log -o synth.v -f "verilog -nolatches" -s ../run-synth.ys \
+       fpu.v except.v post_norm.v pre_norm_fmul.v pre_norm.v primitives.v
+
+cd ../i2c
+time $vg ../../../yosys -qt -l synth.log -o synth.v -s ../run-synth.ys \
+       i2c_master_top.v i2c_master_bit_ctrl.v i2c_master_byte_ctrl.v
+
+cd ../sasc
+time $vg ../../../yosys -qt -l synth.log -o synth.v -s ../run-synth.ys \
+       sasc_top.v sasc_brg.v sasc_fifo4.v
+
+cd ../simple_spi
+time $vg ../../../yosys -qt -l synth.log -o synth.v -s ../run-synth.ys \
+       simple_spi_top.v fifo4.v
+
+cd ../spi
+time $vg ../../../yosys -qt -l synth.log -o synth.v -s ../run-synth.ys \
+       spi_top.v spi_clgen.v spi_shift.v
+
+cd ../ss_pcm
+time $vg ../../../yosys -qt -l synth.log -o synth.v -s ../run-synth.ys \
+       pcm_slv_top.v
+
+cd ../systemcaes
+time $vg ../../../yosys -qt -l synth.log -o synth.v -s ../run-synth.ys \
+       aes.v byte_mixcolum.v keysched.v mixcolum.v sbox.v subbytes.v word_mixcolum.v
+
+cd ../usb_phy
+time $vg ../../../yosys -qt -l synth.log -o synth.v -s ../run-synth.ys \
+       usb_phy.v usb_rx_phy.v usb_tx_phy.v
+
diff --git a/tests/iwls2005/run-synth.ys b/tests/iwls2005/run-synth.ys
new file mode 100644 (file)
index 0000000..f3253d5
--- /dev/null
@@ -0,0 +1,11 @@
+hierarchy
+proc
+opt
+memory
+opt
+# fsm -norecode
+# opt
+techmap
+opt
+abc
+opt
diff --git a/tests/iwls2005/sasc/sasc_brg.v b/tests/iwls2005/sasc/sasc_brg.v
new file mode 100644 (file)
index 0000000..74a7cc5
--- /dev/null
@@ -0,0 +1,160 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  Simple Baud Rate Generator                                 ////
+////                                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/cores/sasc/      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws                       ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: sasc_brg.v,v 1.2 2002/11/08 15:22:49 rudi Exp $
+//
+//  $Date: 2002/11/08 15:22:49 $
+//  $Revision: 1.2 $
+//  $Author: rudi $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: sasc_brg.v,v $
+//               Revision 1.2  2002/11/08 15:22:49  rudi
+//
+//               Fixed a typo in brg
+//
+//               Revision 1.1.1.1  2002/09/16 16:16:40  rudi
+//               Initial Checkin
+//
+//
+//
+//
+//
+//
+//
+//
+
+`include "timescale.v"
+
+/*
+       Baud rate Generator
+       ==================
+
+       div0 -  is the first stage divider
+               Set this to the desired number of cycles less two
+       div1 -  is the second stage divider
+               Set this to the actual number of cycles
+
+       Remember you have to generate a baud rate that is 4 higher than what
+       you really want. This is because of the DPLL in the RX section ...
+
+       Example:
+       If your system clock is 50MHz and you want to generate a 9.6 Kbps baud rate:
+       9600*4 = 38400KHz
+       50MHz/38400KHz=1302 or 6*217
+       set div0=4 (6-2) and set div1=217
+
+*/
+
+module sasc_brg(clk, rst, div0, div1, sio_ce, sio_ce_x4);
+input          clk;
+input          rst;
+input  [7:0]   div0, div1;
+output         sio_ce, sio_ce_x4;
+
+///////////////////////////////////////////////////////////////////
+//
+// Local Wires and Registers
+//
+
+reg    [7:0]   ps;
+reg            ps_clr;
+reg    [7:0]   br_cnt;
+reg            br_clr;
+reg            sio_ce_x4_r;
+reg    [1:0]   cnt;
+reg            sio_ce, sio_ce_x4;
+reg            sio_ce_r ;
+reg            sio_ce_x4_t;
+
+///////////////////////////////////////////////////////////////////
+//
+// Boud Rate Generator
+//
+
+// -----------------------------------------------------
+// Prescaler
+always @(posedge clk)
+       if(!rst)        ps <= #1 8'h0;
+       else
+       if(ps_clr)      ps <= #1 8'h0;
+       else            ps <= #1 ps + 8'h1;
+
+always @(posedge clk)
+       ps_clr <= #1 (ps == div0);      // Desired number of cycles less 2
+
+// -----------------------------------------------------
+// Oversampled Boud Rate (x4)
+always @(posedge clk)
+       if(!rst)        br_cnt <= #1 8'h0;
+       else
+       if(br_clr)      br_cnt <= #1 8'h0;
+       else
+       if(ps_clr)      br_cnt <= #1 br_cnt + 8'h1;
+
+always @(posedge clk)
+       br_clr <= #1 (br_cnt == div1); // Prciese number of PS cycles
+
+always @(posedge clk)
+       sio_ce_x4_r <= #1 br_clr;
+
+always @(posedge clk)
+       sio_ce_x4_t <= #1 !sio_ce_x4_r & br_clr;
+
+always @(posedge clk)
+       sio_ce_x4 <= #1 sio_ce_x4_t;
+
+// -----------------------------------------------------
+// Actual Boud rate
+always @(posedge clk)
+       if(!rst)                        cnt <= #1 2'h0;
+       else
+       if(!sio_ce_x4_r & br_clr)       cnt <= #1 cnt + 2'h1;
+
+always @(posedge clk)
+       sio_ce_r <= #1 (cnt == 2'h0);
+
+always @(posedge clk)
+       sio_ce <= #1 !sio_ce_r & (cnt == 2'h0);
+
+endmodule
+
diff --git a/tests/iwls2005/sasc/sasc_fifo4.v b/tests/iwls2005/sasc/sasc_fifo4.v
new file mode 100644 (file)
index 0000000..ab9b9fe
--- /dev/null
@@ -0,0 +1,135 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  FIFO 4 entries deep                                        ////
+////                                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/cores/sasc/      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws                       ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: sasc_fifo4.v,v 1.1.1.1 2002/09/16 16:16:41 rudi Exp $
+//
+//  $Date: 2002/09/16 16:16:41 $
+//  $Revision: 1.1.1.1 $
+//  $Author: rudi $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: sasc_fifo4.v,v $
+//               Revision 1.1.1.1  2002/09/16 16:16:41  rudi
+//               Initial Checkin
+//
+//
+//
+//
+//
+//
+
+`include "timescale.v"
+
+// 4 entry deep fast fifo
+module sasc_fifo4(clk, rst, clr,  din, we, dout, re, full, empty);
+
+input          clk, rst;
+input          clr;
+input   [7:0]  din;
+input          we;
+output  [7:0]  dout;
+input          re;
+output         full, empty;
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Local Wires
+//
+
+reg     [7:0]  mem[0:3];
+reg     [1:0]   wp;
+reg     [1:0]   rp;
+wire    [1:0]   wp_p1;
+wire    [1:0]   wp_p2;
+wire    [1:0]   rp_p1;
+wire           full, empty;
+reg            gb;
+
+////////////////////////////////////////////////////////////////////
+//
+// Misc Logic
+//
+
+always @(posedge clk or negedge rst)
+        if(!rst)       wp <= #1 2'h0;
+        else
+        if(clr)                wp <= #1 2'h0;
+        else
+        if(we)         wp <= #1 wp_p1;
+
+assign wp_p1 = wp + 2'h1;
+assign wp_p2 = wp + 2'h2;
+
+always @(posedge clk or negedge rst)
+        if(!rst)       rp <= #1 2'h0;
+        else
+        if(clr)                rp <= #1 2'h0;
+        else
+        if(re)         rp <= #1 rp_p1;
+
+assign rp_p1 = rp + 2'h1;
+
+// Fifo Output
+assign  dout = mem[ rp ];
+
+// Fifo Input 
+always @(posedge clk)
+        if(we)     mem[ wp ] <= #1 din;
+
+// Status
+assign empty = (wp == rp) & !gb;
+assign full  = (wp == rp) &  gb;
+
+// Guard Bit ...
+always @(posedge clk)
+       if(!rst)                        gb <= #1 1'b0;
+       else
+       if(clr)                         gb <= #1 1'b0;
+       else
+       if((wp_p1 == rp) & we)          gb <= #1 1'b1;
+       else
+       if(re)                          gb <= #1 1'b0;
+
+endmodule
+
+
diff --git a/tests/iwls2005/sasc/sasc_top.v b/tests/iwls2005/sasc/sasc_top.v
new file mode 100644 (file)
index 0000000..a59329a
--- /dev/null
@@ -0,0 +1,301 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  Simple Asynchronous Serial Comm. Device                    ////
+////                                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/cores/sasc/      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws                       ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: sasc_top.v,v 1.1.1.1 2002/09/16 16:16:42 rudi Exp $
+//
+//  $Date: 2002/09/16 16:16:42 $
+//  $Revision: 1.1.1.1 $
+//  $Author: rudi $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: sasc_top.v,v $
+//               Revision 1.1.1.1  2002/09/16 16:16:42  rudi
+//               Initial Checkin
+//
+//
+//
+//
+//
+//
+//
+//
+
+`include "timescale.v"
+
+/*
+Serial IO Interface
+===============================
+RTS I Request To Send
+CTS O Clear to send
+TD  I Transmit Data
+RD  O Receive Data
+*/
+
+module sasc_top(       clk, rst,
+       
+                       // SIO
+                       rxd_i, txd_o, cts_i, rts_o, 
+
+                       // External Baud Rate Generator
+                       sio_ce, sio_ce_x4,
+
+                       // Internal Interface
+                       din_i, dout_o, re_i, we_i, full_o, empty_o);
+
+input          clk;
+input          rst;
+input          rxd_i;
+output         txd_o;
+input          cts_i;
+output         rts_o; 
+input          sio_ce;
+input          sio_ce_x4;
+input  [7:0]   din_i;
+output [7:0]   dout_o;
+input          re_i, we_i;
+output         full_o, empty_o;
+
+///////////////////////////////////////////////////////////////////
+//
+// Local Wires and Registers
+//
+
+parameter      START_BIT       = 1'b0,
+               STOP_BIT        = 1'b1,
+               IDLE_BIT        = 1'b1;
+
+wire   [7:0]   txd_p;
+reg            load;
+reg            load_r;
+wire           load_e;
+reg    [9:0]   hold_reg;
+wire           txf_empty;
+reg            txd_o;
+reg            shift_en;
+reg    [3:0]   tx_bit_cnt;
+reg            rxd_s, rxd_r;
+wire           start;
+reg    [3:0]   rx_bit_cnt;
+reg            rx_go;
+reg    [9:0]   rxr;
+reg            rx_valid, rx_valid_r;
+wire           rx_we;
+wire           rxf_full;
+reg            rts_o;
+reg            txf_empty_r;
+reg            shift_en_r;
+reg            rxd_r1, rxd_r2;
+wire           lock_en;
+reg            change;
+reg            rx_sio_ce_d, rx_sio_ce_r1, rx_sio_ce_r2, rx_sio_ce;
+reg    [1:0]   dpll_state, dpll_next_state;
+
+///////////////////////////////////////////////////////////////////
+//
+// IO Fifo's
+//
+
+sasc_fifo4 tx_fifo(    .clk(           clk             ),
+                       .rst(           rst             ),
+                       .clr(           1'b0            ),
+                       .din(           din_i           ),
+                       .we(            we_i            ),
+                       .dout(          txd_p           ),
+                       .re(            load_e          ),
+                       .full(          full_o          ),
+                       .empty(         txf_empty       )
+                       );
+
+sasc_fifo4 rx_fifo(    .clk(           clk             ),
+                       .rst(           rst             ),
+                       .clr(           1'b0            ),
+                       .din(           rxr[9:2]        ),
+                       .we(            rx_we           ),
+                       .dout(          dout_o          ),
+                       .re(            re_i            ),
+                       .full(          rxf_full        ),
+                       .empty(         empty_o         )
+                       );
+
+///////////////////////////////////////////////////////////////////
+//
+// Transmit Logic
+//
+always @(posedge clk)
+       if(!rst)        txf_empty_r <= #1 1'b1;
+       else
+       if(sio_ce)      txf_empty_r <= #1 txf_empty;
+
+always @(posedge clk)
+       load <= #1 !txf_empty_r & !shift_en & !cts_i;
+
+always @(posedge clk)
+       load_r <= #1 load;
+
+assign load_e = load & sio_ce;
+
+always @(posedge clk)
+       if(load_e)              hold_reg <= #1 {STOP_BIT, txd_p, START_BIT};
+       else
+       if(shift_en & sio_ce)   hold_reg <= #1 {IDLE_BIT, hold_reg[9:1]};
+
+always @(posedge clk)
+       if(!rst)                                txd_o <= #1 IDLE_BIT;
+       else
+       if(sio_ce)
+               if(shift_en | shift_en_r)       txd_o <= #1 hold_reg[0];
+               else                            txd_o <= #1 IDLE_BIT;
+
+always @(posedge clk)
+        if(!rst)               tx_bit_cnt <= #1 4'h9;
+       else
+       if(load_e)              tx_bit_cnt <= #1 4'h0;
+       else
+       if(shift_en & sio_ce)   tx_bit_cnt <= #1 tx_bit_cnt + 4'h1;
+
+always @(posedge clk)
+       shift_en <= #1 (tx_bit_cnt != 4'h9);
+
+always @(posedge clk)
+       if(!rst)        shift_en_r <= #1 1'b0;
+       else
+       if(sio_ce)      shift_en_r <= #1 shift_en;
+
+///////////////////////////////////////////////////////////////////
+//
+// Recieve Logic
+//
+
+always @(posedge clk)
+       rxd_s <= #1 rxd_i;
+
+always @(posedge clk)
+       rxd_r <= #1 rxd_s;
+
+assign start = (rxd_r == IDLE_BIT) & (rxd_s == START_BIT);
+
+always @(posedge clk)
+        if(!rst)               rx_bit_cnt <= #1 4'ha;
+       else
+       if(!rx_go & start)      rx_bit_cnt <= #1 4'h0;
+       else
+       if(rx_go & rx_sio_ce)   rx_bit_cnt <= #1 rx_bit_cnt + 4'h1;
+
+always @(posedge clk)
+       rx_go <= #1 (rx_bit_cnt != 4'ha);
+
+always @(posedge clk)
+       rx_valid <= #1 (rx_bit_cnt == 4'h9);
+
+always @(posedge clk)
+       rx_valid_r <= #1 rx_valid;
+
+assign rx_we = !rx_valid_r & rx_valid & !rxf_full;
+
+always @(posedge clk)
+       if(rx_go & rx_sio_ce)   rxr <= {rxd_s, rxr[9:1]};
+
+always @(posedge clk)
+       rts_o <= #1 rxf_full;
+
+///////////////////////////////////////////////////////////////////
+//
+// Reciever DPLL
+//
+
+// Uses 4x baud clock to lock to incoming stream
+
+// Edge detector
+always @(posedge clk)
+       if(sio_ce_x4)   rxd_r1 <= #1 rxd_s;
+
+always @(posedge clk)
+       if(sio_ce_x4)   rxd_r2 <= #1 rxd_r1;
+
+always @(posedge clk)
+       if(!rst)                change <= #1 1'b0;
+       else
+       if(rxd_r != rxd_s)      change <= #1 1'b1;
+       else
+       if(sio_ce_x4)           change <= #1 1'b0;
+
+// DPLL FSM
+always @(posedge clk or negedge rst)
+       if(!rst)        dpll_state <= #1 2'h1;
+       else
+       if(sio_ce_x4)   dpll_state <= #1 dpll_next_state;
+
+always @(dpll_state or change)
+   begin
+       rx_sio_ce_d = 1'b0;
+       case(dpll_state)
+          2'h0:
+               if(change)      dpll_next_state = 3'h0;
+               else            dpll_next_state = 3'h1;
+          2'h1:begin
+               rx_sio_ce_d = 1'b1;
+               if(change)      dpll_next_state = 3'h3;
+               else            dpll_next_state = 3'h2;
+               end
+          2'h2:
+               if(change)      dpll_next_state = 3'h0;
+               else            dpll_next_state = 3'h3;
+          2'h3:
+               if(change)      dpll_next_state = 3'h0;
+               else            dpll_next_state = 3'h0;
+       endcase
+   end
+
+// Compensate for sync registers at the input - allign sio 
+// clock enable to be in the middle between two bit changes ...
+always @(posedge clk)
+       rx_sio_ce_r1 <= #1 rx_sio_ce_d;
+
+always @(posedge clk)
+       rx_sio_ce_r2 <= #1 rx_sio_ce_r1;
+
+always @(posedge clk)
+       rx_sio_ce <= #1 rx_sio_ce_r1 & !rx_sio_ce_r2;
+
+endmodule
+
+
diff --git a/tests/iwls2005/sasc/timescale.v b/tests/iwls2005/sasc/timescale.v
new file mode 100644 (file)
index 0000000..ff9e265
--- /dev/null
@@ -0,0 +1 @@
+`timescale 1ns / 10ps
diff --git a/tests/iwls2005/simple_spi/fifo4.v b/tests/iwls2005/simple_spi/fifo4.v
new file mode 100644 (file)
index 0000000..f041c7d
--- /dev/null
@@ -0,0 +1,134 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// FIFO 4 entries deep                                         ////
+////                                                             ////
+//// Authors: Rudolf Usselmann, Richard Herveille                ////
+////          rudi@asics.ws     richard@asics.ws                 ////
+////                                                             ////
+////                                                             ////
+//// Download from: http://www.opencores.org/projects/sasc       ////
+////                http://www.opencores.org/projects/simple_spi ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann, Richard Herveille ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws, richard@asics.ws     ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: fifo4.v,v 1.1.1.1 2002/12/22 16:07:14 rherveille Exp $
+//
+//  $Date: 2002/12/22 16:07:14 $
+//  $Revision: 1.1.1.1 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: fifo4.v,v $
+//               Revision 1.1.1.1  2002/12/22 16:07:14  rherveille
+//               Initial release
+//
+//
+
+// synopsys translate_off
+`include "timescale.v"
+// synopsys translate_on
+
+
+// 4 entry deep fast fifo
+module fifo4(clk, rst, clr,  din, we, dout, re, full, empty);
+
+parameter dw = 8;
+
+input          clk, rst;
+input          clr;
+input   [dw:1] din;
+input          we;
+output  [dw:1] dout;
+input          re;
+output         full, empty;
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Local Wires
+//
+
+reg     [dw:1] mem[0:3];
+reg     [1:0]   wp;
+reg     [1:0]   rp;
+wire    [1:0]   wp_p1;
+wire    [1:0]   wp_p2;
+wire    [1:0]   rp_p1;
+wire           full, empty;
+reg            gb;
+
+////////////////////////////////////////////////////////////////////
+//
+// Misc Logic
+//
+
+always @(posedge clk or negedge rst)
+        if(!rst)       wp <= #1 2'h0;
+        else
+        if(clr)                wp <= #1 2'h0;
+        else
+        if(we)         wp <= #1 wp_p1;
+
+assign wp_p1 = wp + 2'h1;
+assign wp_p2 = wp + 2'h2;
+
+always @(posedge clk or negedge rst)
+        if(!rst)       rp <= #1 2'h0;
+        else
+        if(clr)                rp <= #1 2'h0;
+        else
+        if(re)         rp <= #1 rp_p1;
+
+assign rp_p1 = rp + 2'h1;
+
+// Fifo Output
+assign  dout = mem[ rp ];
+
+// Fifo Input
+always @(posedge clk)
+        if(we) mem[ wp ] <= #1 din;
+
+// Status
+assign empty = (wp == rp) & !gb;
+assign full  = (wp == rp) &  gb;
+
+// Guard Bit ...
+always @(posedge clk)
+       if(!rst)                        gb <= #1 1'b0;
+       else
+       if(clr)                         gb <= #1 1'b0;
+       else
+       if((wp_p1 == rp) & we)          gb <= #1 1'b1;
+       else
+       if(re)                          gb <= #1 1'b0;
+
+endmodule
diff --git a/tests/iwls2005/simple_spi/simple_spi_top.v b/tests/iwls2005/simple_spi/simple_spi_top.v
new file mode 100644 (file)
index 0000000..e952f4b
--- /dev/null
@@ -0,0 +1,329 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  OpenCores                    MC68HC11E based SPI interface ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2002 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: simple_spi_top.v,v 1.5 2004/02/28 15:59:50 rherveille Exp $
+//
+//  $Date: 2004/02/28 15:59:50 $
+//  $Revision: 1.5 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: simple_spi_top.v,v $
+//               Revision 1.5  2004/02/28 15:59:50  rherveille
+//               Fixed SCK_O generation bug.
+//               This resulted in a major rewrite of the serial interface engine.
+//
+//               Revision 1.4  2003/08/01 11:41:54  rherveille
+//               Fixed some timing bugs.
+//
+//               Revision 1.3  2003/01/09 16:47:59  rherveille
+//               Updated clkcnt size and decoding due to new SPR bit assignments.
+//
+//               Revision 1.2  2003/01/07 13:29:52  rherveille
+//               Changed SPR bits coding.
+//
+//               Revision 1.1.1.1  2002/12/22 16:07:15  rherveille
+//               Initial release
+//
+//
+
+
+
+//
+// Motorola MC68HC11E based SPI interface
+//
+// Currently only MASTER mode is supported
+//
+
+// synopsys translate_off
+`include "timescale.v"
+// synopsys translate_on
+
+module simple_spi_top(
+  // 8bit WISHBONE bus slave interface
+  input  wire       clk_i,         // clock
+  input  wire       rst_i,         // reset (asynchronous active low)
+  input  wire       cyc_i,         // cycle
+  input  wire       stb_i,         // strobe
+  input  wire [1:0] adr_i,         // address
+  input  wire       we_i,          // write enable
+  input  wire [7:0] dat_i,         // data input
+  output reg  [7:0] dat_o,         // data output
+  output reg        ack_o,         // normal bus termination
+  output reg        inta_o,        // interrupt output
+
+  // SPI port
+  output reg        sck_o,         // serial clock output
+  output wire       mosi_o,        // MasterOut SlaveIN
+  input  wire       miso_i         // MasterIn SlaveOut
+);
+
+  //
+  // Module body
+  //
+  reg  [7:0] spcr;       // Serial Peripheral Control Register ('HC11 naming)
+  wire [7:0] spsr;       // Serial Peripheral Status register ('HC11 naming)
+  reg  [7:0] sper;       // Serial Peripheral Extension register
+  reg  [7:0] treg, rreg; // Transmit/Receive register
+
+  // fifo signals
+  wire [7:0] rfdout;
+  reg        wfre, rfwe;
+  wire       rfre, rffull, rfempty;
+  wire [7:0] wfdout;
+  wire       wfwe, wffull, wfempty;
+
+  // misc signals
+  wire      tirq;     // transfer interrupt (selected number of transfers done)
+  wire      wfov;     // write fifo overrun (writing while fifo full)
+  reg [1:0] state;    // statemachine state
+  reg [2:0] bcnt;
+
+  //
+  // Wishbone interface
+  wire wb_acc = cyc_i & stb_i;       // WISHBONE access
+  wire wb_wr  = wb_acc & we_i;       // WISHBONE write access
+
+  // dat_i
+  always @(posedge clk_i or negedge rst_i)
+    if (~rst_i)
+      begin
+          spcr <= #1 8'h10;  // set master bit
+          sper <= #1 8'h00;
+      end
+    else if (wb_wr)
+      begin
+        if (adr_i == 2'b00)
+          spcr <= #1 dat_i | 8'h10; // always set master bit
+
+        if (adr_i == 2'b11)
+          sper <= #1 dat_i;
+      end
+
+  // write fifo
+  assign wfwe = wb_acc & (adr_i == 2'b10) & ack_o &  we_i;
+  assign wfov = wfwe & wffull;
+
+  // dat_o
+  always @(posedge clk_i)
+    case(adr_i) // synopsys full_case parallel_case
+      2'b00: dat_o <= #1 spcr;
+      2'b01: dat_o <= #1 spsr;
+      2'b10: dat_o <= #1 rfdout;
+      2'b11: dat_o <= #1 sper;
+    endcase
+
+  // read fifo
+  assign rfre = wb_acc & (adr_i == 2'b10) & ack_o & ~we_i;
+
+  // ack_o
+  always @(posedge clk_i or negedge rst_i)
+    if (~rst_i)
+      ack_o <= #1 1'b0;
+    else
+      ack_o <= #1 wb_acc & !ack_o;
+
+  // decode Serial Peripheral Control Register
+  wire       spie = spcr[7];   // Interrupt enable bit
+  wire       spe  = spcr[6];   // System Enable bit
+  wire       dwom = spcr[5];   // Port D Wired-OR Mode Bit
+  wire       mstr = spcr[4];   // Master Mode Select Bit
+  wire       cpol = spcr[3];   // Clock Polarity Bit
+  wire       cpha = spcr[2];   // Clock Phase Bit
+  wire [1:0] spr  = spcr[1:0]; // Clock Rate Select Bits
+
+  // decode Serial Peripheral Extension Register
+  wire [1:0] icnt = sper[7:6]; // interrupt on transfer count
+  wire [1:0] spre = sper[1:0]; // extended clock rate select
+
+  wire [3:0] espr = {spre, spr};
+
+  // generate status register
+  wire wr_spsr = wb_wr & (adr_i == 2'b01);
+
+  reg spif;
+  always @(posedge clk_i)
+    if (~spe)
+      spif <= #1 1'b0;
+    else
+      spif <= #1 (tirq | spif) & ~(wr_spsr & dat_i[7]);
+
+  reg wcol;
+  always @(posedge clk_i)
+    if (~spe)
+      wcol <= #1 1'b0;
+    else
+      wcol <= #1 (wfov | wcol) & ~(wr_spsr & dat_i[6]);
+
+  assign spsr[7]   = spif;
+  assign spsr[6]   = wcol;
+  assign spsr[5:4] = 2'b00;
+  assign spsr[3]   = wffull;
+  assign spsr[2]   = wfempty;
+  assign spsr[1]   = rffull;
+  assign spsr[0]   = rfempty;
+  
+
+  // generate IRQ output (inta_o)
+  always @(posedge clk_i)
+    inta_o <= #1 spif & spie;
+
+  //
+  // hookup read/write buffer fifo
+  fifo4 #(8)
+  rfifo(
+       .clk   ( clk_i   ),
+       .rst   ( rst_i   ),
+       .clr   ( ~spe    ),
+       .din   ( treg    ),
+       .we    ( rfwe    ),
+       .dout  ( rfdout  ),
+       .re    ( rfre    ),
+       .full  ( rffull  ),
+       .empty ( rfempty )
+  ),
+  wfifo(
+       .clk   ( clk_i   ),
+       .rst   ( rst_i   ),
+       .clr   ( ~spe    ),
+       .din   ( dat_i   ),
+       .we    ( wfwe    ),
+       .dout  ( wfdout  ),
+       .re    ( wfre    ),
+       .full  ( wffull  ),
+       .empty ( wfempty )
+  );
+
+  //
+  // generate clk divider
+  reg [11:0] clkcnt;
+  always @(posedge clk_i)
+    if(spe & (|clkcnt & |state))
+      clkcnt <= #1 clkcnt - 11'h1;
+    else
+      case (espr) // synopsys full_case parallel_case
+        4'b0000: clkcnt <= #1 12'h0;   // 2   -- original M68HC11 coding
+        4'b0001: clkcnt <= #1 12'h1;   // 4   -- original M68HC11 coding
+        4'b0010: clkcnt <= #1 12'h3;   // 16  -- original M68HC11 coding
+        4'b0011: clkcnt <= #1 12'hf;   // 32  -- original M68HC11 coding
+        4'b0100: clkcnt <= #1 12'h1f;  // 8
+        4'b0101: clkcnt <= #1 12'h7;   // 64
+        4'b0110: clkcnt <= #1 12'h3f;  // 128
+        4'b0111: clkcnt <= #1 12'h7f;  // 256
+        4'b1000: clkcnt <= #1 12'hff;  // 512
+        4'b1001: clkcnt <= #1 12'h1ff; // 1024
+        4'b1010: clkcnt <= #1 12'h3ff; // 2048
+        4'b1011: clkcnt <= #1 12'h7ff; // 4096
+      endcase
+
+  // generate clock enable signal
+  wire ena = ~|clkcnt;
+
+  // transfer statemachine
+  always @(posedge clk_i)
+    if (~spe)
+      begin
+          state <= #1 2'b00; // idle
+          bcnt  <= #1 3'h0;
+          treg  <= #1 8'h00;
+          wfre  <= #1 1'b0;
+          rfwe  <= #1 1'b0;
+          sck_o <= #1 1'b0;
+      end
+    else
+      begin
+         wfre <= #1 1'b0;
+         rfwe <= #1 1'b0;
+
+         case (state) //synopsys full_case parallel_case
+           2'b00: // idle state
+              begin
+                  bcnt  <= #1 3'h7;   // set transfer counter
+                  treg  <= #1 wfdout; // load transfer register
+                  sck_o <= #1 cpol;   // set sck
+
+                  if (~wfempty) begin
+                    wfre  <= #1 1'b1;
+                    state <= #1 2'b01;
+                    if (cpha) sck_o <= #1 ~sck_o;
+                  end
+              end
+
+           2'b01: // clock-phase2, next data
+              if (ena) begin
+                sck_o   <= #1 ~sck_o;
+                state   <= #1 2'b11;
+              end
+
+           2'b11: // clock phase1
+              if (ena) begin
+                treg <= #1 {treg[6:0], miso_i};
+                bcnt <= #1 bcnt -3'h1;
+
+                if (~|bcnt) begin
+                  state <= #1 2'b00;
+                  sck_o <= #1 cpol;
+                  rfwe  <= #1 1'b1;
+                end else begin
+                  state <= #1 2'b01;
+                  sck_o <= #1 ~sck_o;
+                end
+              end
+
+           2'b10: state <= #1 2'b00;
+         endcase
+      end
+
+  assign mosi_o = treg[7];
+
+
+  // count number of transfers (for interrupt generation)
+  reg [1:0] tcnt; // transfer count
+  always @(posedge clk_i)
+    if (~spe)
+      tcnt <= #1 icnt;
+    else if (rfwe) // rfwe gets asserted when all bits have been transfered
+      if (|tcnt)
+        tcnt <= #1 tcnt - 2'h1;
+      else
+        tcnt <= #1 icnt;
+
+  assign tirq = ~|tcnt & rfwe;
+
+endmodule
+
diff --git a/tests/iwls2005/spi/spi_clgen.v b/tests/iwls2005/spi/spi_clgen.v
new file mode 100644 (file)
index 0000000..7bc4f6e
--- /dev/null
@@ -0,0 +1,108 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  spi_clgen.v                                                 ////
+////                                                              ////
+////  This file is part of the SPI IP core project                ////
+////  http://www.opencores.org/projects/spi/                      ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Simon Srot (simons@opencores.org)                     ////
+////                                                              ////
+////  All additional information is avaliable in the Readme.txt   ////
+////  file.                                                       ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2002 Authors                                   ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+
+`include "spi_defines.v"
+`include "timescale.v"
+
+module spi_clgen (clk_in, rst, go, enable, last_clk, divider, clk_out, pos_edge, neg_edge); 
+
+  parameter Tp = 1;
+  
+  input                            clk_in;   // input clock (system clock)
+  input                            rst;      // reset
+  input                            enable;   // clock enable
+  input                            go;       // start transfer
+  input                            last_clk; // last clock
+  input     [`SPI_DIVIDER_LEN-1:0] divider;  // clock divider (output clock is divided by this value)
+  output                           clk_out;  // output clock
+  output                           pos_edge; // pulse marking positive edge of clk_out
+  output                           neg_edge; // pulse marking negative edge of clk_out
+                            
+  reg                              clk_out;
+  reg                              pos_edge;
+  reg                              neg_edge;
+                            
+  reg       [`SPI_DIVIDER_LEN-1:0] cnt;      // clock counter 
+  wire                             cnt_zero; // conter is equal to zero
+  wire                             cnt_one;  // conter is equal to one
+  
+  
+  assign cnt_zero = cnt == {`SPI_DIVIDER_LEN{1'b0}};
+  assign cnt_one  = cnt == {{`SPI_DIVIDER_LEN-1{1'b0}}, 1'b1};
+  
+  // Counter counts half period
+  always @(posedge clk_in or posedge rst)
+  begin
+    if(rst)
+      cnt <= #Tp {`SPI_DIVIDER_LEN{1'b1}};
+    else
+      begin
+        if(!enable || cnt_zero)
+          cnt <= #Tp divider;
+        else
+          cnt <= #Tp cnt - {{`SPI_DIVIDER_LEN-1{1'b0}}, 1'b1};
+      end
+  end
+  
+  // clk_out is asserted every other half period
+  always @(posedge clk_in or posedge rst)
+  begin
+    if(rst)
+      clk_out <= #Tp 1'b0;
+    else
+      clk_out <= #Tp (enable && cnt_zero && (!last_clk || clk_out)) ? ~clk_out : clk_out;
+  end
+   
+  // Pos and neg edge signals
+  always @(posedge clk_in or posedge rst)
+  begin
+    if(rst)
+      begin
+        pos_edge  <= #Tp 1'b0;
+        neg_edge  <= #Tp 1'b0;
+      end
+    else
+      begin
+        pos_edge  <= #Tp (enable && !clk_out && cnt_one) || (!(|divider) && clk_out) || (!(|divider) && go && !enable);
+        neg_edge  <= #Tp (enable && clk_out && cnt_one) || (!(|divider) && !clk_out && enable);
+      end
+  end
+endmodule
diff --git a/tests/iwls2005/spi/spi_defines.v b/tests/iwls2005/spi/spi_defines.v
new file mode 100644 (file)
index 0000000..a692591
--- /dev/null
@@ -0,0 +1,159 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  spi_define.v                                                ////
+////                                                              ////
+////  This file is part of the SPI IP core project                ////
+////  http://www.opencores.org/projects/spi/                      ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Simon Srot (simons@opencores.org)                     ////
+////                                                              ////
+////  All additional information is avaliable in the Readme.txt   ////
+////  file.                                                       ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2002 Authors                                   ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+
+//
+// Number of bits used for devider register. If used in system with
+// low frequency of system clock this can be reduced.
+// Use SPI_DIVIDER_LEN for fine tuning theexact number.
+//
+//`define SPI_DIVIDER_LEN_8
+`define SPI_DIVIDER_LEN_16
+//`define SPI_DIVIDER_LEN_24
+//`define SPI_DIVIDER_LEN_32
+
+`ifdef SPI_DIVIDER_LEN_8
+  `define SPI_DIVIDER_LEN       8    // Can be set from 1 to 8
+`endif                                                          
+`ifdef SPI_DIVIDER_LEN_16                                       
+  `define SPI_DIVIDER_LEN       16   // Can be set from 9 to 16
+`endif                                                          
+`ifdef SPI_DIVIDER_LEN_24                                       
+  `define SPI_DIVIDER_LEN       24   // Can be set from 17 to 24
+`endif                                                          
+`ifdef SPI_DIVIDER_LEN_32                                       
+  `define SPI_DIVIDER_LEN       32   // Can be set from 25 to 32 
+`endif
+
+//
+// Maximum nuber of bits that can be send/received at once. 
+// Use SPI_MAX_CHAR for fine tuning the exact number, when using
+// SPI_MAX_CHAR_32, SPI_MAX_CHAR_24, SPI_MAX_CHAR_16, SPI_MAX_CHAR_8.
+//
+`define SPI_MAX_CHAR_128
+//`define SPI_MAX_CHAR_64
+//`define SPI_MAX_CHAR_32
+//`define SPI_MAX_CHAR_24
+//`define SPI_MAX_CHAR_16
+//`define SPI_MAX_CHAR_8
+
+`ifdef SPI_MAX_CHAR_128
+  `define SPI_MAX_CHAR          128  // Can only be set to 128 
+  `define SPI_CHAR_LEN_BITS     7
+`endif
+`ifdef SPI_MAX_CHAR_64
+  `define SPI_MAX_CHAR          64   // Can only be set to 64 
+  `define SPI_CHAR_LEN_BITS     6
+`endif
+`ifdef SPI_MAX_CHAR_32
+  `define SPI_MAX_CHAR          32   // Can be set from 25 to 32 
+  `define SPI_CHAR_LEN_BITS     5
+`endif
+`ifdef SPI_MAX_CHAR_24
+  `define SPI_MAX_CHAR          24   // Can be set from 17 to 24 
+  `define SPI_CHAR_LEN_BITS     5
+`endif
+`ifdef SPI_MAX_CHAR_16
+  `define SPI_MAX_CHAR          16   // Can be set from 9 to 16 
+  `define SPI_CHAR_LEN_BITS     4
+`endif
+`ifdef SPI_MAX_CHAR_8
+  `define SPI_MAX_CHAR          8    // Can be set from 1 to 8 
+  `define SPI_CHAR_LEN_BITS     3
+`endif
+
+//
+// Number of device select signals. Use SPI_SS_NB for fine tuning the 
+// exact number.
+//
+`define SPI_SS_NB_8
+//`define SPI_SS_NB_16
+//`define SPI_SS_NB_24
+//`define SPI_SS_NB_32
+
+`ifdef SPI_SS_NB_8
+  `define SPI_SS_NB             8    // Can be set from 1 to 8
+`endif
+`ifdef SPI_SS_NB_16
+  `define SPI_SS_NB             16   // Can be set from 9 to 16
+`endif
+`ifdef SPI_SS_NB_24
+  `define SPI_SS_NB             24   // Can be set from 17 to 24
+`endif
+`ifdef SPI_SS_NB_32
+  `define SPI_SS_NB             32   // Can be set from 25 to 32
+`endif
+
+//
+// Bits of WISHBONE address used for partial decoding of SPI registers.
+//
+`define SPI_OFS_BITS             4:2
+
+//
+// Register offset
+//
+`define SPI_RX_0                0
+`define SPI_RX_1                1
+`define SPI_RX_2                2
+`define SPI_RX_3                3
+`define SPI_TX_0                0
+`define SPI_TX_1                1
+`define SPI_TX_2                2
+`define SPI_TX_3                3
+`define SPI_CTRL                4
+`define SPI_DEVIDE              5
+`define SPI_SS                  6
+
+//
+// Number of bits in ctrl register
+//
+`define SPI_CTRL_BIT_NB         14
+
+//
+// Control register bit position
+//
+`define SPI_CTRL_ASS            13
+`define SPI_CTRL_IE             12
+`define SPI_CTRL_LSB            11
+`define SPI_CTRL_TX_NEGEDGE     10
+`define SPI_CTRL_RX_NEGEDGE     9
+`define SPI_CTRL_GO             8
+`define SPI_CTRL_RES_1          7
+`define SPI_CTRL_CHAR_LEN       6:0
+
diff --git a/tests/iwls2005/spi/spi_shift.v b/tests/iwls2005/spi/spi_shift.v
new file mode 100644 (file)
index 0000000..b17ac8b
--- /dev/null
@@ -0,0 +1,238 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  spi_shift.v                                                 ////
+////                                                              ////
+////  This file is part of the SPI IP core project                ////
+////  http://www.opencores.org/projects/spi/                      ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Simon Srot (simons@opencores.org)                     ////
+////                                                              ////
+////  All additional information is avaliable in the Readme.txt   ////
+////  file.                                                       ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2002 Authors                                   ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+
+`include "spi_defines.v"
+`include "timescale.v"
+
+module spi_shift (clk, rst, latch, byte_sel, len, lsb, go,
+                  pos_edge, neg_edge, rx_negedge, tx_negedge,
+                  tip, last, 
+                  p_in, p_out, s_clk, s_in, s_out);
+
+  parameter Tp = 1;
+  
+  input                          clk;          // system clock
+  input                          rst;          // reset
+  input                    [3:0] latch;        // latch signal for storing the data in shift register
+  input                    [3:0] byte_sel;     // byte select signals for storing the data in shift register
+  input [`SPI_CHAR_LEN_BITS-1:0] len;          // data len in bits (minus one)
+  input                          lsb;          // lbs first on the line
+  input                          go;           // start stansfer
+  input                          pos_edge;     // recognize posedge of sclk
+  input                          neg_edge;     // recognize negedge of sclk
+  input                          rx_negedge;   // s_in is sampled on negative edge 
+  input                          tx_negedge;   // s_out is driven on negative edge
+  output                         tip;          // transfer in progress
+  output                         last;         // last bit
+  input                   [31:0] p_in;         // parallel in
+  output     [`SPI_MAX_CHAR-1:0] p_out;        // parallel out
+  input                          s_clk;        // serial clock
+  input                          s_in;         // serial in
+  output                         s_out;        // serial out
+                                               
+  reg                            s_out;        
+  reg                            tip;
+                              
+  reg     [`SPI_CHAR_LEN_BITS:0] cnt;          // data bit count
+  reg        [`SPI_MAX_CHAR-1:0] data;         // shift register
+  wire    [`SPI_CHAR_LEN_BITS:0] tx_bit_pos;   // next bit position
+  wire    [`SPI_CHAR_LEN_BITS:0] rx_bit_pos;   // next bit position
+  wire                           rx_clk;       // rx clock enable
+  wire                           tx_clk;       // tx clock enable
+  
+  assign p_out = data;
+  
+  assign tx_bit_pos = lsb ? {!(|len), len} - cnt : cnt - {{`SPI_CHAR_LEN_BITS{1'b0}},1'b1};
+  assign rx_bit_pos = lsb ? {!(|len), len} - (rx_negedge ? cnt + {{`SPI_CHAR_LEN_BITS{1'b0}},1'b1} : cnt) : 
+                            (rx_negedge ? cnt : cnt - {{`SPI_CHAR_LEN_BITS{1'b0}},1'b1});
+  
+  assign last = !(|cnt);
+  
+  assign rx_clk = (rx_negedge ? neg_edge : pos_edge) && (!last || s_clk);
+  assign tx_clk = (tx_negedge ? neg_edge : pos_edge) && !last;
+  
+  // Character bit counter
+  always @(posedge clk or posedge rst)
+  begin
+    if(rst)
+      cnt <= #Tp {`SPI_CHAR_LEN_BITS+1{1'b0}};
+    else
+      begin
+        if(tip)
+          cnt <= #Tp pos_edge ? (cnt - {{`SPI_CHAR_LEN_BITS{1'b0}}, 1'b1}) : cnt;
+        else
+          cnt <= #Tp !(|len) ? {1'b1, {`SPI_CHAR_LEN_BITS{1'b0}}} : {1'b0, len};
+      end
+  end
+  
+  // Transfer in progress
+  always @(posedge clk or posedge rst)
+  begin
+    if(rst)
+      tip <= #Tp 1'b0;
+  else if(go && ~tip)
+    tip <= #Tp 1'b1;
+  else if(tip && last && pos_edge)
+    tip <= #Tp 1'b0;
+  end
+  
+  // Sending bits to the line
+  always @(posedge clk or posedge rst)
+  begin
+    if (rst)
+      s_out   <= #Tp 1'b0;
+    else
+      s_out <= #Tp (tx_clk || !tip) ? data[tx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]] : s_out;
+  end
+  
+  // Receiving bits from the line
+  always @(posedge clk or posedge rst)
+  begin
+    if (rst)
+      data   <= #Tp {`SPI_MAX_CHAR{1'b0}};
+`ifdef SPI_MAX_CHAR_128
+    else if (latch[0] && !tip)
+      begin
+        if (byte_sel[3])
+          data[31:24] <= #Tp p_in[31:24];
+        if (byte_sel[2])
+          data[23:16] <= #Tp p_in[23:16];
+        if (byte_sel[1])
+          data[15:8] <= #Tp p_in[15:8];
+        if (byte_sel[0])
+          data[7:0] <= #Tp p_in[7:0];
+      end
+    else if (latch[1] && !tip)
+      begin
+        if (byte_sel[3])
+          data[63:56] <= #Tp p_in[31:24];
+        if (byte_sel[2])
+          data[55:48] <= #Tp p_in[23:16];
+        if (byte_sel[1])
+          data[47:40] <= #Tp p_in[15:8];
+        if (byte_sel[0])
+          data[39:32] <= #Tp p_in[7:0];
+      end
+    else if (latch[2] && !tip)
+      begin
+        if (byte_sel[3])
+          data[95:88] <= #Tp p_in[31:24];
+        if (byte_sel[2])
+          data[87:80] <= #Tp p_in[23:16];
+        if (byte_sel[1])
+          data[79:72] <= #Tp p_in[15:8];
+        if (byte_sel[0])
+          data[71:64] <= #Tp p_in[7:0];
+      end
+    else if (latch[3] && !tip)
+      begin
+        if (byte_sel[3])
+          data[127:120] <= #Tp p_in[31:24];
+        if (byte_sel[2])
+          data[119:112] <= #Tp p_in[23:16];
+        if (byte_sel[1])
+          data[111:104] <= #Tp p_in[15:8];
+        if (byte_sel[0])
+          data[103:96] <= #Tp p_in[7:0];
+      end
+`else
+`ifdef SPI_MAX_CHAR_64
+    else if (latch[0] && !tip)
+      begin
+        if (byte_sel[3])
+          data[31:24] <= #Tp p_in[31:24];
+        if (byte_sel[2])
+          data[23:16] <= #Tp p_in[23:16];
+        if (byte_sel[1])
+          data[15:8] <= #Tp p_in[15:8];
+        if (byte_sel[0])
+          data[7:0] <= #Tp p_in[7:0];
+      end
+    else if (latch[1] && !tip)
+      begin
+        if (byte_sel[3])
+          data[63:56] <= #Tp p_in[31:24];
+        if (byte_sel[2])
+          data[55:48] <= #Tp p_in[23:16];
+        if (byte_sel[1])
+          data[47:40] <= #Tp p_in[15:8];
+        if (byte_sel[0])
+          data[39:32] <= #Tp p_in[7:0];
+      end
+`else
+    else if (latch[0] && !tip)
+      begin
+      `ifdef SPI_MAX_CHAR_8
+        if (byte_sel[0])
+          data[`SPI_MAX_CHAR-1:0] <= #Tp p_in[`SPI_MAX_CHAR-1:0];
+      `endif
+      `ifdef SPI_MAX_CHAR_16
+        if (byte_sel[0])
+          data[7:0] <= #Tp p_in[7:0];
+        if (byte_sel[1])
+          data[`SPI_MAX_CHAR-1:8] <= #Tp p_in[`SPI_MAX_CHAR-1:8];
+      `endif
+      `ifdef SPI_MAX_CHAR_24
+        if (byte_sel[0])
+          data[7:0] <= #Tp p_in[7:0];
+        if (byte_sel[1])
+          data[15:8] <= #Tp p_in[15:8];
+        if (byte_sel[2])
+          data[`SPI_MAX_CHAR-1:16] <= #Tp p_in[`SPI_MAX_CHAR-1:16];
+      `endif
+      `ifdef SPI_MAX_CHAR_32
+        if (byte_sel[0])
+          data[7:0] <= #Tp p_in[7:0];
+        if (byte_sel[1])
+          data[15:8] <= #Tp p_in[15:8];
+        if (byte_sel[2])
+          data[23:16] <= #Tp p_in[23:16];
+        if (byte_sel[3])
+          data[`SPI_MAX_CHAR-1:24] <= #Tp p_in[`SPI_MAX_CHAR-1:24];
+      `endif
+      end
+`endif
+`endif
+    else
+      data[rx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]] <= #Tp rx_clk ? s_in : data[rx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]];
+  end
+  
+endmodule
+
diff --git a/tests/iwls2005/spi/spi_top.v b/tests/iwls2005/spi/spi_top.v
new file mode 100644 (file)
index 0000000..09b2e50
--- /dev/null
@@ -0,0 +1,287 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  spi_top.v                                                   ////
+////                                                              ////
+////  This file is part of the SPI IP core project                ////
+////  http://www.opencores.org/projects/spi/                      ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Simon Srot (simons@opencores.org)                     ////
+////                                                              ////
+////  All additional information is avaliable in the Readme.txt   ////
+////  file.                                                       ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2002 Authors                                   ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+
+
+`include "spi_defines.v"
+`include "timescale.v"
+
+module spi_top
+(
+  // Wishbone signals
+  wb_clk_i, wb_rst_i, wb_adr_i, wb_dat_i, wb_dat_o, wb_sel_i,
+  wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_err_o, wb_int_o,
+
+  // SPI signals
+  ss_pad_o, sclk_pad_o, mosi_pad_o, miso_pad_i
+);
+
+  parameter Tp = 1;
+
+  // Wishbone signals
+  input                            wb_clk_i;         // master clock input
+  input                            wb_rst_i;         // synchronous active high reset
+  input                      [4:0] wb_adr_i;         // lower address bits
+  input                   [32-1:0] wb_dat_i;         // databus input
+  output                  [32-1:0] wb_dat_o;         // databus output
+  input                      [3:0] wb_sel_i;         // byte select inputs
+  input                            wb_we_i;          // write enable input
+  input                            wb_stb_i;         // stobe/core select signal
+  input                            wb_cyc_i;         // valid bus cycle input
+  output                           wb_ack_o;         // bus cycle acknowledge output
+  output                           wb_err_o;         // termination w/ error
+  output                           wb_int_o;         // interrupt request signal output
+                                                     
+  // SPI signals                                     
+  output          [`SPI_SS_NB-1:0] ss_pad_o;         // slave select
+  output                           sclk_pad_o;       // serial clock
+  output                           mosi_pad_o;       // master out slave in
+  input                            miso_pad_i;       // master in slave out
+                                                     
+  reg                     [32-1:0] wb_dat_o;
+  reg                              wb_ack_o;
+  reg                              wb_int_o;
+                                               
+  // Internal signals
+  reg       [`SPI_DIVIDER_LEN-1:0] divider;          // Divider register
+  reg       [`SPI_CTRL_BIT_NB-1:0] ctrl;             // Control and status register
+  reg             [`SPI_SS_NB-1:0] ss;               // Slave select register
+  reg                     [32-1:0] wb_dat;           // wb data out
+  wire         [`SPI_MAX_CHAR-1:0] rx;               // Rx register
+  wire                             rx_negedge;       // miso is sampled on negative edge
+  wire                             tx_negedge;       // mosi is driven on negative edge
+  wire    [`SPI_CHAR_LEN_BITS-1:0] char_len;         // char len
+  wire                             go;               // go
+  wire                             lsb;              // lsb first on line
+  wire                             ie;               // interrupt enable
+  wire                             ass;              // automatic slave select
+  wire                             spi_divider_sel;  // divider register select
+  wire                             spi_ctrl_sel;     // ctrl register select
+  wire                       [3:0] spi_tx_sel;       // tx_l register select
+  wire                             spi_ss_sel;       // ss register select
+  wire                             tip;              // transfer in progress
+  wire                             pos_edge;         // recognize posedge of sclk
+  wire                             neg_edge;         // recognize negedge of sclk
+  wire                             last_bit;         // marks last character bit
+  
+  // Address decoder
+  assign spi_divider_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_DEVIDE);
+  assign spi_ctrl_sel    = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_CTRL);
+  assign spi_tx_sel[0]   = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_0);
+  assign spi_tx_sel[1]   = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_1);
+  assign spi_tx_sel[2]   = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_2);
+  assign spi_tx_sel[3]   = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_3);
+  assign spi_ss_sel      = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_SS);
+  
+  // Read from registers
+  always @(wb_adr_i or rx or ctrl or divider or ss)
+  begin
+    case (wb_adr_i[`SPI_OFS_BITS])
+`ifdef SPI_MAX_CHAR_128
+      `SPI_RX_0:    wb_dat = rx[31:0];
+      `SPI_RX_1:    wb_dat = rx[63:32];
+      `SPI_RX_2:    wb_dat = rx[95:64];
+      `SPI_RX_3:    wb_dat = {{128-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:96]};
+`else
+`ifdef SPI_MAX_CHAR_64
+      `SPI_RX_0:    wb_dat = rx[31:0];
+      `SPI_RX_1:    wb_dat = {{64-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:32]};
+      `SPI_RX_2:    wb_dat = 32'b0;
+      `SPI_RX_3:    wb_dat = 32'b0;
+`else
+      `SPI_RX_0:    wb_dat = {{32-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:0]};
+      `SPI_RX_1:    wb_dat = 32'b0;
+      `SPI_RX_2:    wb_dat = 32'b0;
+      `SPI_RX_3:    wb_dat = 32'b0;
+`endif
+`endif
+      `SPI_CTRL:    wb_dat = {{32-`SPI_CTRL_BIT_NB{1'b0}}, ctrl};
+      `SPI_DEVIDE:  wb_dat = {{32-`SPI_DIVIDER_LEN{1'b0}}, divider};
+      `SPI_SS:      wb_dat = {{32-`SPI_SS_NB{1'b0}}, ss};
+      default:      wb_dat = 32'bx;
+    endcase
+  end
+  
+  // Wb data out
+  always @(posedge wb_clk_i or posedge wb_rst_i)
+  begin
+    if (wb_rst_i)
+      wb_dat_o <= #Tp 32'b0;
+    else
+      wb_dat_o <= #Tp wb_dat;
+  end
+  
+  // Wb acknowledge
+  always @(posedge wb_clk_i or posedge wb_rst_i)
+  begin
+    if (wb_rst_i)
+      wb_ack_o <= #Tp 1'b0;
+    else
+      wb_ack_o <= #Tp wb_cyc_i & wb_stb_i & ~wb_ack_o;
+  end
+  
+  // Wb error
+  assign wb_err_o = 1'b0;
+  
+  // Interrupt
+  always @(posedge wb_clk_i or posedge wb_rst_i)
+  begin
+    if (wb_rst_i)
+      wb_int_o <= #Tp 1'b0;
+    else if (ie && tip && last_bit && pos_edge)
+      wb_int_o <= #Tp 1'b1;
+    else if (wb_ack_o)
+      wb_int_o <= #Tp 1'b0;
+  end
+  
+  // Divider register
+  always @(posedge wb_clk_i or posedge wb_rst_i)
+  begin
+    if (wb_rst_i)
+        divider <= #Tp {`SPI_DIVIDER_LEN{1'b0}};
+    else if (spi_divider_sel && wb_we_i && !tip)
+      begin
+      `ifdef SPI_DIVIDER_LEN_8
+        if (wb_sel_i[0])
+          divider <= #Tp wb_dat_i[`SPI_DIVIDER_LEN-1:0];
+      `endif
+      `ifdef SPI_DIVIDER_LEN_16
+        if (wb_sel_i[0])
+          divider[7:0] <= #Tp wb_dat_i[7:0];
+        if (wb_sel_i[1])
+          divider[`SPI_DIVIDER_LEN-1:8] <= #Tp wb_dat_i[`SPI_DIVIDER_LEN-1:8];
+      `endif
+      `ifdef SPI_DIVIDER_LEN_24
+        if (wb_sel_i[0])
+          divider[7:0] <= #Tp wb_dat_i[7:0];
+        if (wb_sel_i[1])
+          divider[15:8] <= #Tp wb_dat_i[15:8];
+        if (wb_sel_i[2])
+          divider[`SPI_DIVIDER_LEN-1:16] <= #Tp wb_dat_i[`SPI_DIVIDER_LEN-1:16];
+      `endif
+      `ifdef SPI_DIVIDER_LEN_32
+        if (wb_sel_i[0])
+          divider[7:0] <= #Tp wb_dat_i[7:0];
+        if (wb_sel_i[1])
+          divider[15:8] <= #Tp wb_dat_i[15:8];
+        if (wb_sel_i[2])
+          divider[23:16] <= #Tp wb_dat_i[23:16];
+        if (wb_sel_i[3])
+          divider[`SPI_DIVIDER_LEN-1:24] <= #Tp wb_dat_i[`SPI_DIVIDER_LEN-1:24];
+      `endif
+      end
+  end
+  
+  // Ctrl register
+  always @(posedge wb_clk_i or posedge wb_rst_i)
+  begin
+    if (wb_rst_i)
+      ctrl <= #Tp {`SPI_CTRL_BIT_NB{1'b0}};
+    else if(spi_ctrl_sel && wb_we_i && !tip)
+      begin
+        if (wb_sel_i[0])
+          ctrl[7:0] <= #Tp wb_dat_i[7:0] | {7'b0, ctrl[0]};
+        if (wb_sel_i[1])
+          ctrl[`SPI_CTRL_BIT_NB-1:8] <= #Tp wb_dat_i[`SPI_CTRL_BIT_NB-1:8];
+      end
+    else if(tip && last_bit && pos_edge)
+      ctrl[`SPI_CTRL_GO] <= #Tp 1'b0;
+  end
+  
+  assign rx_negedge = ctrl[`SPI_CTRL_RX_NEGEDGE];
+  assign tx_negedge = ctrl[`SPI_CTRL_TX_NEGEDGE];
+  assign go         = ctrl[`SPI_CTRL_GO];
+  assign char_len   = ctrl[`SPI_CTRL_CHAR_LEN];
+  assign lsb        = ctrl[`SPI_CTRL_LSB];
+  assign ie         = ctrl[`SPI_CTRL_IE];
+  assign ass        = ctrl[`SPI_CTRL_ASS];
+  
+  // Slave select register
+  always @(posedge wb_clk_i or posedge wb_rst_i)
+  begin
+    if (wb_rst_i)
+      ss <= #Tp {`SPI_SS_NB{1'b0}};
+    else if(spi_ss_sel && wb_we_i && !tip)
+      begin
+      `ifdef SPI_SS_NB_8
+        if (wb_sel_i[0])
+          ss <= #Tp wb_dat_i[`SPI_SS_NB-1:0];
+      `endif
+      `ifdef SPI_SS_NB_16
+        if (wb_sel_i[0])
+          ss[7:0] <= #Tp wb_dat_i[7:0];
+        if (wb_sel_i[1])
+          ss[`SPI_SS_NB-1:8] <= #Tp wb_dat_i[`SPI_SS_NB-1:8];
+      `endif
+      `ifdef SPI_SS_NB_24
+        if (wb_sel_i[0])
+          ss[7:0] <= #Tp wb_dat_i[7:0];
+        if (wb_sel_i[1])
+          ss[15:8] <= #Tp wb_dat_i[15:8];
+        if (wb_sel_i[2])
+          ss[`SPI_SS_NB-1:16] <= #Tp wb_dat_i[`SPI_SS_NB-1:16];
+      `endif
+      `ifdef SPI_SS_NB_32
+        if (wb_sel_i[0])
+          ss[7:0] <= #Tp wb_dat_i[7:0];
+        if (wb_sel_i[1])
+          ss[15:8] <= #Tp wb_dat_i[15:8];
+        if (wb_sel_i[2])
+          ss[23:16] <= #Tp wb_dat_i[23:16];
+        if (wb_sel_i[3])
+          ss[`SPI_SS_NB-1:24] <= #Tp wb_dat_i[`SPI_SS_NB-1:24];
+      `endif
+      end
+  end
+  
+  assign ss_pad_o = ~((ss & {`SPI_SS_NB{tip & ass}}) | (ss & {`SPI_SS_NB{!ass}}));
+  
+  spi_clgen clgen (.clk_in(wb_clk_i), .rst(wb_rst_i), .go(go), .enable(tip), .last_clk(last_bit),
+                   .divider(divider), .clk_out(sclk_pad_o), .pos_edge(pos_edge), 
+                   .neg_edge(neg_edge));
+  
+  spi_shift shift (.clk(wb_clk_i), .rst(wb_rst_i), .len(char_len[`SPI_CHAR_LEN_BITS-1:0]),
+                   .latch(spi_tx_sel[3:0] & {4{wb_we_i}}), .byte_sel(wb_sel_i), .lsb(lsb), 
+                   .go(go), .pos_edge(pos_edge), .neg_edge(neg_edge), 
+                   .rx_negedge(rx_negedge), .tx_negedge(tx_negedge),
+                   .tip(tip), .last(last_bit), 
+                   .p_in(wb_dat_i), .p_out(rx), 
+                   .s_clk(sclk_pad_o), .s_in(miso_pad_i), .s_out(mosi_pad_o));
+endmodule
+  
diff --git a/tests/iwls2005/spi/timescale.v b/tests/iwls2005/spi/timescale.v
new file mode 100644 (file)
index 0000000..60d4ecb
--- /dev/null
@@ -0,0 +1,2 @@
+`timescale 1ns / 10ps
+
diff --git a/tests/iwls2005/ss_pcm/pcm_slv_top.v b/tests/iwls2005/ss_pcm/pcm_slv_top.v
new file mode 100644 (file)
index 0000000..2548d35
--- /dev/null
@@ -0,0 +1,222 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  PCM IO Slave Module                                        ////
+////                                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/cores/ss_pcm/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws                       ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: pcm_slv_top.v,v 1.2 2002/09/17 15:32:50 rudi Exp $
+//
+//  $Date: 2002/09/17 15:32:50 $
+//  $Revision: 1.2 $
+//  $Author: rudi $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: pcm_slv_top.v,v $
+//               Revision 1.2  2002/09/17 15:32:50  rudi
+//               *** empty log message ***
+//
+//               Revision 1.1.1.1  2002/09/17 15:17:25  rudi
+//               Initial Checkin
+//
+//
+//
+//
+//
+//
+//
+//
+
+`include "timescale.v"
+
+/*
+PCM Interface
+===============================
+PCM_CLK
+PCM_SYNC
+PCM_DIN
+PCM_DOUT
+*/
+
+module pcm_slv_top(    clk, rst,
+       
+                       ssel,
+
+                       // PCM
+                       pcm_clk_i, pcm_sync_i, pcm_din_i, pcm_dout_o,
+
+                       // Internal Interface
+                       din_i, dout_o, re_i, we_i);
+
+input          clk, rst;
+input  [2:0]   ssel;   // Number of bits to delay (0-7)
+input          pcm_clk_i, pcm_sync_i, pcm_din_i;
+output         pcm_dout_o;
+input  [7:0]   din_i;
+output [7:0]   dout_o;
+input          re_i;
+input  [1:0]   we_i;
+
+///////////////////////////////////////////////////////////////////
+//
+// Local Wires and Registers
+//
+
+reg            pclk_t, pclk_s, pclk_r;
+wire           pclk_ris, pclk_fal;
+reg            psync;
+reg            pcm_sync_r1, pcm_sync_r2, pcm_sync_r3;
+reg            tx_go;
+wire           tx_data_le;
+reg    [15:0]  tx_hold_reg;
+reg    [7:0]   tx_hold_byte_h, tx_hold_byte_l;
+reg    [3:0]   tx_cnt;
+wire           tx_done;
+reg    [15:0]  rx_hold_reg, rx_reg;
+wire           rx_data_le;
+reg            rxd_t, rxd;
+reg            tx_go_r1, tx_go_r2;
+reg    [7:0]   psa;
+
+///////////////////////////////////////////////////////////////////
+//
+// Misc Logic
+//
+
+always @(posedge clk)
+       pclk_t <= #1 pcm_clk_i;
+
+always @(posedge clk)
+       pclk_s <= #1 pclk_t;
+
+always @(posedge clk)
+       pclk_r <= #1 pclk_s;
+
+assign pclk_ris = !pclk_r &  pclk_s;
+assign pclk_fal =  pclk_r & !pclk_s;
+
+///////////////////////////////////////////////////////////////////
+//
+// Retrieve Sync Signal
+//
+
+always @(posedge clk)  // Latch it at falling edge
+       if(pclk_fal)    pcm_sync_r1 <= #1 pcm_sync_i;
+
+always @(posedge clk)  // resync to rising edge
+       if(pclk_ris)    psa <= #1 {psa[6:0], pcm_sync_r1};
+
+always @(posedge clk)  //delay bit N
+       pcm_sync_r2 <= #1 psa[ssel];
+
+always @(posedge clk)  // edge detector
+       pcm_sync_r3 <= #1 pcm_sync_r2;
+
+always @(posedge clk)
+       psync <= #1 !pcm_sync_r3 & pcm_sync_r2;
+
+///////////////////////////////////////////////////////////////////
+//
+// Transmit Logic
+//
+
+assign tx_data_le = tx_go & pclk_ris;
+
+always @(posedge clk)
+       if(we_i[1])     tx_hold_byte_h <= #1 din_i;
+
+always @(posedge clk)
+       if(we_i[0])     tx_hold_byte_l <= #1 din_i;
+
+always @(posedge clk)
+       if(!rst)        tx_go <= #1 1'b0;
+       else
+       if(psync)       tx_go <= #1 1'b1;
+       else
+       if(tx_done)     tx_go <= #1 1'b0;
+
+always @(posedge clk)
+       if(!rst)        tx_hold_reg <= #1 16'h0;
+       else
+       if(psync)       tx_hold_reg <= #1 {tx_hold_byte_h, tx_hold_byte_l};
+       else
+       if(tx_data_le)  tx_hold_reg <= #1 {tx_hold_reg[14:0],1'b0};
+
+assign pcm_dout_o = tx_hold_reg[15];
+       
+always @(posedge clk)
+       if(!rst)        tx_cnt <= #1 4'h0;
+       else
+       if(tx_data_le)  tx_cnt <= tx_cnt + 4'h1;
+
+assign tx_done = (tx_cnt == 4'hf) & tx_data_le;
+
+///////////////////////////////////////////////////////////////////
+//
+// Recieve Logic
+//
+
+always @(posedge clk)
+       if(pclk_ris)    tx_go_r1 <= #1 tx_go;
+
+always @(posedge clk)
+       if(pclk_ris)    tx_go_r2 <= #1 tx_go_r1;
+
+// Receive is in sync with transmit ...
+always @(posedge clk)
+       if(pclk_fal)    rxd_t <= #1 pcm_din_i;
+
+always @(posedge clk)
+       rxd <= #1 rxd_t;
+
+assign rx_data_le = (tx_go_r1 | tx_go) & pclk_fal;
+
+always @(posedge clk)
+       if(!rst)        rx_hold_reg <= #1 16'h0;
+       else
+       if(rx_data_le)  rx_hold_reg <= #1 {rx_hold_reg[14:0], rxd};
+
+always @(posedge clk)
+       if(!rst)                                rx_reg <= #1 16'h0;
+       else
+       if(tx_go_r1 & !tx_go & pclk_ris)        rx_reg <= #1 rx_hold_reg;
+
+assign dout_o = re_i ? rx_reg[15:8] : rx_reg[7:0];
+
+endmodule
+
diff --git a/tests/iwls2005/ss_pcm/timescale.v b/tests/iwls2005/ss_pcm/timescale.v
new file mode 100644 (file)
index 0000000..ff9e265
--- /dev/null
@@ -0,0 +1 @@
+`timescale 1ns / 10ps
diff --git a/tests/iwls2005/systemcaes/aes.v b/tests/iwls2005/systemcaes/aes.v
new file mode 100644 (file)
index 0000000..e5021ed
--- /dev/null
@@ -0,0 +1,358 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  AES top file                                                ////
+////                                                              ////
+////  This file is part of the SystemC AES                        ////
+////                                                              ////
+////  Description:                                                ////
+////  AES top                                                     ////
+////                                                              ////
+////  Generated automatically using SystemC to Verilog translator ////
+////                                                              ////
+////  To Do:                                                      ////
+////   - done                                                     ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Javier Castillo, jcastilo@opencores.org               ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2000 Authors and OPENCORES.ORG                 ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+//
+// CVS Revision History
+//
+// $Log: aes.v,v $
+// Revision 1.1.1.1  2004/07/05 09:46:23  jcastillo
+// First import
+//
+
+module aes(clk,reset,load_i,decrypt_i,data_i,key_i,ready_o,data_o);
+input clk;
+input reset;
+input load_i;
+input decrypt_i;
+input [127:0] data_i;
+input [127:0] key_i;
+output ready_o;
+output [127:0] data_o;
+
+reg ready_o;
+reg [127:0] data_o;
+
+reg next_ready_o;
+reg keysched_start_i;
+reg [3:0] keysched_round_i;
+reg [127:0] keysched_last_key_i;
+wire [127:0] keysched_new_key_o;
+
+wire keysched_ready_o;
+
+wire keysched_sbox_access_o;
+
+wire [7:0] keysched_sbox_data_o;
+
+wire keysched_sbox_decrypt_o;
+
+reg mixcol_start_i;
+reg [127:0] mixcol_data_i;
+wire mixcol_ready_o;
+
+wire [127:0] mixcol_data_o;
+
+reg subbytes_start_i;
+reg [127:0] subbytes_data_i;
+wire subbytes_ready_o;
+
+wire [127:0] subbytes_data_o;
+
+wire [7:0] subbytes_sbox_data_o;
+
+wire subbytes_sbox_decrypt_o;
+
+wire [7:0] sbox_data_o;
+
+reg [7:0] sbox_data_i;
+reg sbox_decrypt_i;
+reg state;
+reg next_state;
+reg [3:0] round;
+reg [3:0] next_round;
+reg [127:0] addroundkey_data_o;
+reg [127:0] next_addroundkey_data_reg;
+reg [127:0] addroundkey_data_reg;
+reg [127:0] addroundkey_data_i;
+reg addroundkey_ready_o;
+reg next_addroundkey_ready_o;
+reg addroundkey_start_i;
+reg next_addroundkey_start_i;
+reg [3:0] addroundkey_round;
+reg [3:0] next_addroundkey_round;
+reg first_round_reg;
+reg next_first_round_reg;
+
+sbox sbox1 (.clk(clk), .reset(reset), .data_i(sbox_data_i), .decrypt_i(sbox_decrypt_i), .data_o(sbox_data_o));
+subbytes sub1 (.clk(clk), .reset(reset), .start_i(subbytes_start_i), .decrypt_i(decrypt_i), .data_i(subbytes_data_i), .ready_o(subbytes_ready_o), .data_o(subbytes_data_o), .sbox_data_o(subbytes_sbox_data_o), .sbox_data_i(sbox_data_o), .sbox_decrypt_o(subbytes_sbox_decrypt_o));
+mixcolum mix1 (.clk(clk), .reset(reset), .decrypt_i(decrypt_i), .start_i(mixcol_start_i), .data_i(mixcol_data_i), .ready_o(mixcol_ready_o), .data_o(mixcol_data_o));
+keysched ks1 (.clk(clk), .reset(reset), .start_i(keysched_start_i), .round_i(keysched_round_i), .last_key_i(keysched_last_key_i), .new_key_o(keysched_new_key_o), .ready_o(keysched_ready_o), .sbox_access_o(keysched_sbox_access_o), .sbox_data_o(keysched_sbox_data_o), .sbox_data_i(sbox_data_o), .sbox_decrypt_o(keysched_sbox_decrypt_o));
+
+//registers:
+always @(posedge clk or negedge reset)
+
+begin
+
+       if(!reset)
+begin
+
+               state = (0);
+               ready_o = (0);
+               round = (0);
+        addroundkey_round = (0);
+               addroundkey_data_reg = (0);
+               addroundkey_ready_o = (0);
+               addroundkey_start_i = (0);
+               first_round_reg = (0);
+       
+end
+else
+begin
+
+               state = (next_state);
+               ready_o = (next_ready_o);
+               round = (next_round);
+               addroundkey_round = (next_addroundkey_round);
+               addroundkey_data_reg = (next_addroundkey_data_reg);
+               addroundkey_ready_o = (next_addroundkey_ready_o);
+               first_round_reg = (next_first_round_reg);
+               addroundkey_start_i = (next_addroundkey_start_i);
+       
+end
+
+
+end
+//control:
+always @(  state or   round or   addroundkey_data_o or   data_i or   load_i or   decrypt_i or   addroundkey_ready_o or   mixcol_ready_o or   subbytes_ready_o or   subbytes_data_o or   mixcol_data_o or   first_round_reg)
+
+begin
+
+       
+       next_state = (state);
+       next_round = (round);
+       data_o = (addroundkey_data_o);
+       next_ready_o = (0);
+       
+       //Tokeyschedulemodule
+                               
+       next_first_round_reg = (0);
+               
+       
+       subbytes_data_i = (0);  
+       mixcol_data_i = (0);
+       addroundkey_data_i = (0);
+       next_addroundkey_start_i = (first_round_reg);
+    mixcol_start_i = ((addroundkey_ready_o&decrypt_i&round!=10)|(subbytes_ready_o&!decrypt_i));
+    subbytes_start_i = ((addroundkey_ready_o&!decrypt_i)|(mixcol_ready_o&decrypt_i)|(addroundkey_ready_o&decrypt_i&round==10));        
+               
+    if(decrypt_i&&round!=10)
+    begin
+          addroundkey_data_i = (subbytes_data_o);
+          subbytes_data_i = (mixcol_data_o);
+       mixcol_data_i = (addroundkey_data_o);
+    end
+    else if(!decrypt_i&&round!=0)
+    begin
+          addroundkey_data_i = (mixcol_data_o);        
+          subbytes_data_i = (addroundkey_data_o);
+       mixcol_data_i = (subbytes_data_o);
+    end
+    else
+    begin
+          mixcol_data_i = (subbytes_data_o);
+          subbytes_data_i = (addroundkey_data_o);
+          addroundkey_data_i = (data_i);
+    end
+
+
+    case(state)
+               
+               0:
+        begin
+                if(load_i)
+         begin
+                       next_state = (1);
+                       if(decrypt_i)
+                               next_round = (10);
+                       else
+                               next_round = (0);
+                           next_first_round_reg = (1);
+                       end
+               end
+                       
+               1:
+        begin
+       
+               //Counter       
+               if(!decrypt_i&&mixcol_ready_o)
+        begin
+                 next_addroundkey_start_i = (1);
+                 addroundkey_data_i = (mixcol_data_o); 
+                 next_round = (round+1);
+               end
+        else if(decrypt_i&&subbytes_ready_o)
+        begin
+                 next_addroundkey_start_i = (1);
+                 addroundkey_data_i = (subbytes_data_o);
+                 next_round = (round-1);
+               end
+
+               //Output
+               if((round==9&&!decrypt_i)||(round==0&&decrypt_i))
+        begin
+                 next_addroundkey_start_i = (0);
+                 mixcol_start_i = (0);
+               if(subbytes_ready_o)
+        begin
+                 addroundkey_data_i = (subbytes_data_o);
+                 next_addroundkey_start_i = (1);
+                 next_round = (round+1);
+        end
+        end
+
+               if((round==10&&!decrypt_i)||(round==0&&decrypt_i))
+        begin
+                 addroundkey_data_i = (subbytes_data_o);
+                 subbytes_start_i = (0);
+               if(addroundkey_ready_o)
+        begin
+                 next_ready_o = (1);
+                 next_state = (0);
+                 next_addroundkey_start_i = (0);
+                 next_round = (0);
+               end
+       
+               end
+
+                       
+               end
+                       
+               default:
+begin
+                       next_state = (0);
+                       end
+       endcase
+
+
+end
+//addroundkey:
+reg[127:0] data_var,round_data_var,round_key_var;
+always @(  addroundkey_data_i or   addroundkey_start_i or   addroundkey_data_reg or   addroundkey_round or   keysched_new_key_o or   keysched_ready_o or   key_i or   round)
+
+begin
+
+       
+       
+       round_data_var=addroundkey_data_reg;
+       next_addroundkey_data_reg = (addroundkey_data_reg);
+next_addroundkey_ready_o = (0);
+       next_addroundkey_round = (addroundkey_round);
+       addroundkey_data_o = (addroundkey_data_reg);
+       
+       if(addroundkey_round==1||addroundkey_round==0)
+       keysched_last_key_i = (key_i);
+else
+       keysched_last_key_i = (keysched_new_key_o);
+       
+       keysched_start_i = (0);
+       
+       keysched_round_i = (addroundkey_round);
+               
+       if(round==0&&addroundkey_start_i)
+begin
+
+       //Taketheinputandxorthemwithdataifround==0;
+       data_var=addroundkey_data_i;    
+       round_key_var=key_i;
+       round_data_var=round_key_var^data_var;
+       next_addroundkey_data_reg = (round_data_var);
+next_addroundkey_ready_o = (1);
+       
+end
+else if(addroundkey_start_i&&round!=0)
+begin
+
+       keysched_last_key_i = (key_i);  
+       keysched_start_i = (1);
+       keysched_round_i = (1);
+       next_addroundkey_round = (1);
+       
+end
+else if(addroundkey_round!=round&&keysched_ready_o)
+begin
+
+next_addroundkey_round = (addroundkey_round+1);
+       keysched_last_key_i = (keysched_new_key_o);
+       keysched_start_i = (1);
+       keysched_round_i = (addroundkey_round+1);
+       
+end
+else if(addroundkey_round==round&&keysched_ready_o)
+begin
+
+       data_var=addroundkey_data_i;    
+       round_key_var=keysched_new_key_o;
+       round_data_var=round_key_var^data_var;
+       next_addroundkey_data_reg = (round_data_var);
+next_addroundkey_ready_o = (1);
+       next_addroundkey_round = (0);
+
+end
+               
+
+end
+//sbox_muxes:
+always @(  keysched_sbox_access_o or   keysched_sbox_decrypt_o or   keysched_sbox_data_o or   subbytes_sbox_decrypt_o or   subbytes_sbox_data_o)
+
+begin
+
+       
+       if(keysched_sbox_access_o)
+begin
+
+               sbox_decrypt_i = (keysched_sbox_decrypt_o);
+               sbox_data_i = (keysched_sbox_data_o);
+       
+end
+else
+begin
+
+               sbox_decrypt_i = (subbytes_sbox_decrypt_o);
+sbox_data_i = (subbytes_sbox_data_o);
+       
+end
+
+
+end
+
+endmodule
diff --git a/tests/iwls2005/systemcaes/byte_mixcolum.v b/tests/iwls2005/systemcaes/byte_mixcolum.v
new file mode 100644 (file)
index 0000000..b248cc4
--- /dev/null
@@ -0,0 +1,92 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  Mixcolumns for 8 bit                                        ////
+////                                                              ////
+////  This file is part of the SystemC AES                        ////
+////                                                              ////
+////  Description:                                                ////
+////  Mixcolum for a byte                                         ////
+////                                                              ////
+////  Generated automatically using SystemC to Verilog translator ////
+////                                                              ////
+////  To Do:                                                      ////
+////   - done                                                     ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Javier Castillo, jcastilo@opencores.org               ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2000 Authors and OPENCORES.ORG                 ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+//
+// CVS Revision History
+//
+// $Log: byte_mixcolum.v,v $
+// Revision 1.1.1.1  2004/07/05 09:46:23  jcastillo
+// First import
+//
+
+module byte_mixcolum(a,b,c,d,outx,outy);
+
+input [7:0] a,b,c,d;
+output [7:0] outx, outy;
+
+reg [7:0] outx, outy;
+
+function [7:0] xtime;
+input [7:0] in;
+reg [3:0] xtime_t;
+
+begin
+xtime[7:5] = in[6:4];
+xtime_t[3] = in[7];
+xtime_t[2] = in[7];
+xtime_t[1] = 0;
+xtime_t[0] = in[7];
+xtime[4:1] =xtime_t^in[3:0];
+xtime[0] = in[7];
+end
+endfunction
+
+reg [7:0] w1,w2,w3,w4,w5,w6,w7,w8,outx_var;
+always @ (a, b, c, d)
+begin
+w1 = a ^b;
+w2 = a ^c;
+w3 = c ^d;
+w4 = xtime(w1);
+w5 = xtime(w3);
+w6 = w2 ^w4 ^w5;
+w7 = xtime(w6);
+w8 = xtime(w7);
+
+outx_var = b^w3^w4;
+outx=outx_var;
+outy=w8^outx_var;
+
+end
+
+endmodule
diff --git a/tests/iwls2005/systemcaes/keysched.v b/tests/iwls2005/systemcaes/keysched.v
new file mode 100644 (file)
index 0000000..f242c56
--- /dev/null
@@ -0,0 +1,248 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  Key schedule                                                ////
+////                                                              ////
+////  This file is part of the SystemC AES                        ////
+////                                                              ////
+////  Description:                                                ////
+////  Generate the next round key from the previous one           ////
+////                                                              ////
+////  Generated automatically using SystemC to Verilog translator ////
+////                                                              ////
+////  To Do:                                                      ////
+////   - done                                                     ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Javier Castillo, jcastilo@opencores.org               ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2000 Authors and OPENCORES.ORG                 ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+//
+// CVS Revision History
+//
+// $Log: keysched.v,v $
+// Revision 1.1.1.1  2004/07/05 09:46:23  jcastillo
+// First import
+//
+
+module keysched(clk,reset,start_i,round_i,last_key_i,new_key_o,ready_o,sbox_access_o,sbox_data_o,sbox_data_i,sbox_decrypt_o);
+input clk;
+input reset;
+input start_i;
+input [3:0] round_i;
+input [127:0] last_key_i;
+output [127:0] new_key_o;
+output ready_o;
+output sbox_access_o;
+output [7:0] sbox_data_o;
+input [7:0] sbox_data_i;
+output sbox_decrypt_o;
+
+reg [127:0] new_key_o;
+reg ready_o;
+reg sbox_access_o;
+reg [7:0] sbox_data_o;
+reg sbox_decrypt_o;
+
+reg [2:0] next_state;
+reg [2:0] state;
+reg [7:0] rcon_o;
+reg [31:0] next_col;
+reg [31:0] col;
+reg [127:0] key_reg;
+reg [127:0] next_key_reg;
+reg next_ready_o;
+
+
+//rcon:
+always @(  round_i)
+
+begin
+
+       
+       case(round_i)
+       1:
+begin
+rcon_o = (1);
+end
+       2:
+begin
+rcon_o = (2);
+end
+       3:
+begin
+rcon_o = (4);
+end
+       4:
+begin
+rcon_o = (8);
+end
+       5:
+begin
+rcon_o = ('h10);
+end
+       6:
+begin
+rcon_o = ('h20);
+end
+       7:
+begin
+rcon_o = ('h40);
+end
+       8:
+begin
+rcon_o = ('h80);
+end
+       9:
+begin
+rcon_o = ('h1B);
+end
+       10:
+begin
+rcon_o = ('h36);
+end
+default:
+begin
+                       rcon_o = (0);
+end
+       endcase
+
+
+end
+//registers:
+always @(posedge clk or negedge reset)
+
+begin
+
+       if(!reset)
+       begin
+               state = (0);
+               col = (0);
+               key_reg = (0);
+               ready_o = (0);
+       end
+else
+       begin
+               state = (next_state);   
+               col = (next_col);
+               key_reg = (next_key_reg);
+               ready_o = (next_ready_o);
+       end
+
+
+end
+//generate_key:
+reg[127:0] K_var,W_var;
+       reg[31:0] col_t;
+       reg[23:0] zero;
+       
+always @(  start_i or   last_key_i or   sbox_data_i or   state or   rcon_o or   col or   key_reg)
+
+begin
+
+       
+       zero=0;
+       
+       col_t=col;
+       W_var=0;
+       
+       next_state = (state);
+       next_col = (col);
+       
+       next_ready_o = (0);
+       next_key_reg = (key_reg);
+       new_key_o = (key_reg);
+       
+sbox_decrypt_o = (0);
+       sbox_access_o = (0);
+       sbox_data_o = (0);
+       K_var=last_key_i;
+               
+       case(state)
+       //Substitutethebyteswhilerotatingthem
+               //FouraccessestoSBoxareneeded
+               0:
+begin
+               if(start_i)
+begin
+       
+                       col_t=0;
+               sbox_access_o = (1);
+                       sbox_data_o = (K_var[31:24]);
+                       next_state = (1);
+               
+end
+
+               end
+       1:
+begin
+               sbox_access_o = (1);
+       sbox_data_o = (K_var[23:16]);
+       col_t[7:0]=sbox_data_i;
+       next_col = (col_t);
+               next_state = (2);
+       end
+       2:
+begin
+               sbox_access_o = (1);
+       sbox_data_o = (K_var[15:8]);
+       col_t[31:24]=sbox_data_i;
+       next_col = (col_t);
+               next_state = (3);
+       end
+       3:
+begin
+               sbox_access_o = (1);
+       sbox_data_o = (K_var[7:0]);     
+       col_t[23:16]=sbox_data_i;
+       next_col = (col_t);
+       next_state = (4);
+       end
+       4:
+begin
+               sbox_access_o = (1);
+               col_t[15:8]=sbox_data_i;
+       next_col = (col_t);
+               W_var[127:96]=col_t^K_var[127:96]^{rcon_o,zero};                
+       W_var[95:64]=W_var[127:96]^K_var[95:64];
+       W_var[63:32]=W_var[95:64]^K_var[63:32];
+       W_var[31:0]=W_var[63:32]^K_var[31:0];
+next_ready_o = (1);
+next_key_reg = (W_var);        
+       next_state = (0);
+               end
+
+default:
+begin
+               next_state = (0);
+       end
+endcase
+
+
+end
+
+endmodule
diff --git a/tests/iwls2005/systemcaes/mixcolum.v b/tests/iwls2005/systemcaes/mixcolum.v
new file mode 100644 (file)
index 0000000..ab6dc1e
--- /dev/null
@@ -0,0 +1,188 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  Mixcolumns module implementation                            ////
+////                                                              ////
+////  This file is part of the SystemC AES                        ////
+////                                                              ////
+////  Description:                                                ////
+////  Mixcolum module                                             ////
+////                                                              ////
+////  Generated automatically using SystemC to Verilog translator ////
+////                                                              ////
+////  To Do:                                                      ////
+////   - done                                                     ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Javier Castillo, jcastilo@opencores.org               ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2000 Authors and OPENCORES.ORG                 ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+//
+// CVS Revision History
+//
+// $Log: mixcolum.v,v $
+// Revision 1.1.1.1  2004/07/05 09:46:23  jcastillo
+// First import
+//
+
+
+module mixcolum(clk,reset,decrypt_i,start_i,data_i,ready_o,data_o);
+input clk;
+input reset;
+input decrypt_i;
+input start_i;
+input [127:0] data_i;
+output ready_o;
+output [127:0] data_o;
+
+reg ready_o;
+reg [127:0] data_o;
+
+reg [127:0] data_reg;
+reg [127:0] next_data_reg;
+reg [127:0] data_o_reg;
+reg [127:0] next_data_o;
+reg next_ready_o;
+reg [1:0] state;
+reg [1:0] next_state;
+wire [31:0] outx;
+
+wire [31:0] outy;
+
+reg [31:0] mix_word;
+reg [31:0] outmux;
+
+word_mixcolum w1 (.in(mix_word), .outx(outx), .outy(outy));
+
+//assign_data_o:
+always @(  data_o_reg)
+
+begin
+
+       data_o = (data_o_reg);
+
+end
+//mux:
+always @(  outx or   outy or decrypt_i)
+
+begin
+
+       outmux = (decrypt_i?outy:outx);
+
+end
+//registers:
+always @(posedge clk or negedge reset)
+
+begin
+
+if(!reset)
+       begin
+               data_reg = (0);
+               state = (0);
+               ready_o = (0);
+               data_o_reg = (0);
+       end
+else                     
+       begin
+               data_reg = (next_data_reg);
+               state = (next_state);
+               ready_o = (next_ready_o);
+               data_o_reg = (next_data_o);
+       end
+
+
+end
+//mixcol:
+reg[127:0] data_i_var;
+       reg[31:0] aux;
+       reg[127:0] data_reg_var;
+
+always @(  decrypt_i or   start_i or   state or   data_reg or   outmux or   data_o_reg or data_i)
+
+begin
+
+       
+       data_i_var=data_i;
+       data_reg_var=data_reg;
+       next_data_reg = (data_reg);
+       next_state = (state);
+       
+       mix_word = (0);
+       
+       next_ready_o = (0);
+       next_data_o = (data_o_reg);
+               
+       case(state)
+       
+               0:
+begin
+                       if(start_i)
+begin
+
+                       aux=data_i_var[127:96];
+               mix_word = (aux);
+                       data_reg_var[127:96]=outmux;
+                       next_data_reg = (data_reg_var);
+                       next_state = (1);
+                       
+end
+
+                       end
+               1:
+begin
+                       aux=data_i_var[95:64];
+                       mix_word = (aux);
+               data_reg_var[95:64]=outmux;
+                       next_data_reg = (data_reg_var);
+                       next_state = (2);
+                       end
+               2:
+begin
+                       aux=data_i_var[63:32];
+                       mix_word = (aux);
+               data_reg_var[63:32]=outmux;
+                       next_data_reg = (data_reg_var);
+                       next_state = (3);
+                       end
+       3:
+begin
+                       aux=data_i_var[31:0];
+                       mix_word = (aux);
+                       data_reg_var[31:0]=outmux;
+               next_data_o = (data_reg_var);
+                       next_ready_o = (1);
+                       next_state = (0);
+                       end     
+               default:
+                       begin
+                       end
+       endcase
+                       
+
+end
+
+endmodule
diff --git a/tests/iwls2005/systemcaes/sbox.v b/tests/iwls2005/systemcaes/sbox.v
new file mode 100644 (file)
index 0000000..b5f741c
--- /dev/null
@@ -0,0 +1,392 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  S-Box calculation                                           ////
+////                                                              ////
+////  This file is part of the SystemC AES                        ////
+////                                                              ////
+////  Description:                                                ////
+////  S-box calculation calculating inverse on gallois field      ////
+////                                                              ////
+////  Generated automatically using SystemC to Verilog translator ////
+////                                                              ////
+////  To Do:                                                      ////
+////   - done                                                     ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Javier Castillo, jcastilo@opencores.org               ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2000 Authors and OPENCORES.ORG                 ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+//
+// CVS Revision History
+//
+// $Log: sbox.v,v $
+// Revision 1.1.1.1  2004/07/05 09:46:23  jcastillo
+// First import
+//
+
+module sbox(clk,reset,data_i,decrypt_i,data_o);
+input clk;
+input reset;
+input [7:0] data_i;
+input decrypt_i;
+output [7:0] data_o;
+
+reg [7:0] data_o;
+
+reg [7:0] inva;
+reg [3:0] ah;
+reg [3:0] al;
+reg [3:0] ah2;
+reg [3:0] al2;
+reg [3:0] alxh;
+reg [3:0] alph;
+reg [3:0] d;
+reg [3:0] ahp;
+reg [3:0] alp;
+reg [3:0] to_invert;
+reg [3:0] next_to_invert;
+reg [3:0] ah_reg;
+reg [3:0] next_ah_reg;
+reg [3:0] next_alph;
+
+
+//registers:
+always @(posedge clk or negedge reset)
+
+begin
+
+if(!reset)
+begin
+
+to_invert = (0);
+       ah_reg = (0);
+alph = (0);    
+
+end
+else
+begin
+
+       to_invert = (next_to_invert);
+       ah_reg = (next_ah_reg);
+alph = (next_alph);    
+
+end
+       
+
+end
+//first_mux:
+reg[7:0] first_mux_data_var;
+       reg[7:0] first_mux_InvInput;
+       reg[3:0] first_mux_ah_t,first_mux_al_t;
+       reg first_mux_aA,first_mux_aB,first_mux_aC,first_mux_aD;
+       
+always @(  data_i or   decrypt_i)
+
+begin
+
+       
+       first_mux_data_var=data_i;
+       first_mux_InvInput=first_mux_data_var;
+       
+       case(decrypt_i)
+               1:
+begin
+               //Applyinverseaffinetrasformation
+first_mux_aA=first_mux_data_var[0]^first_mux_data_var[5];first_mux_aB=first_mux_data_var[1]^first_mux_data_var[4];
+               first_mux_aC=first_mux_data_var[2]^first_mux_data_var[7];first_mux_aD=first_mux_data_var[3]^first_mux_data_var[6];
+               first_mux_InvInput[0]=(!first_mux_data_var[5])^first_mux_aC;
+               first_mux_InvInput[1]=first_mux_data_var[0]^first_mux_aD;
+               first_mux_InvInput[2]=(!first_mux_data_var[7])^first_mux_aB;
+               first_mux_InvInput[3]=first_mux_data_var[2]^first_mux_aA;
+               first_mux_InvInput[4]=first_mux_data_var[1]^first_mux_aD;
+               first_mux_InvInput[5]=first_mux_data_var[4]^first_mux_aC;
+               first_mux_InvInput[6]=first_mux_data_var[3]^first_mux_aA;
+               first_mux_InvInput[7]=first_mux_data_var[6]^first_mux_aB;
+               end
+               default:
+begin
+first_mux_InvInput=first_mux_data_var;
+               end
+       endcase
+       
+       
+       //ConvertelementsfromGF(2^8)intotwoelementsofGF(2^4^2)
+       
+       first_mux_aA=first_mux_InvInput[1]^first_mux_InvInput[7];
+       first_mux_aB=first_mux_InvInput[5]^first_mux_InvInput[7];
+       first_mux_aC=first_mux_InvInput[4]^first_mux_InvInput[6];
+       
+       
+       first_mux_al_t[0]=first_mux_aC^first_mux_InvInput[0]^first_mux_InvInput[5];
+       first_mux_al_t[1]=first_mux_InvInput[1]^first_mux_InvInput[2];
+       first_mux_al_t[2]=first_mux_aA;
+       first_mux_al_t[3]=first_mux_InvInput[2]^first_mux_InvInput[4];
+       
+       first_mux_ah_t[0]=first_mux_aC^first_mux_InvInput[5];
+       first_mux_ah_t[1]=first_mux_aA^first_mux_aC;
+       first_mux_ah_t[2]=first_mux_aB^first_mux_InvInput[2]^first_mux_InvInput[3];
+       first_mux_ah_t[3]=first_mux_aB;
+       
+       al = (first_mux_al_t);
+       ah = (first_mux_ah_t);
+       next_ah_reg = (first_mux_ah_t);
+
+end
+//end_mux:
+reg[7:0] end_mux_data_var,end_mux_data_o_var;
+       reg end_mux_aA,end_mux_aB,end_mux_aC,end_mux_aD;
+
+always @(  decrypt_i or   inva)
+
+begin
+       
+       
+
+       //Taketheoutputoftheinverter
+       end_mux_data_var=inva;
+       
+       case(decrypt_i)
+               0:
+begin
+               //Applyaffinetrasformation
+end_mux_aA=end_mux_data_var[0]^end_mux_data_var[1];end_mux_aB=end_mux_data_var[2]^end_mux_data_var[3];
+               end_mux_aC=end_mux_data_var[4]^end_mux_data_var[5];end_mux_aD=end_mux_data_var[6]^end_mux_data_var[7];
+               end_mux_data_o_var[0]=(!end_mux_data_var[0])^end_mux_aC^end_mux_aD;
+               end_mux_data_o_var[1]=(!end_mux_data_var[5])^end_mux_aA^end_mux_aD;
+               end_mux_data_o_var[2]=end_mux_data_var[2]^end_mux_aA^end_mux_aD;
+               end_mux_data_o_var[3]=end_mux_data_var[7]^end_mux_aA^end_mux_aB;
+               end_mux_data_o_var[4]=end_mux_data_var[4]^end_mux_aA^end_mux_aB;
+               end_mux_data_o_var[5]=(!end_mux_data_var[1])^end_mux_aB^end_mux_aC;
+               end_mux_data_o_var[6]=(!end_mux_data_var[6])^end_mux_aB^end_mux_aC;
+               end_mux_data_o_var[7]=end_mux_data_var[3]^end_mux_aC^end_mux_aD;
+               data_o = (end_mux_data_o_var);
+               end
+               default:
+begin
+data_o = (end_mux_data_var);
+               end
+       endcase
+       
+       
+
+end
+//inversemap:
+reg[3:0] aA,aB;
+       reg[3:0] inversemap_alp_t,inversemap_ahp_t;
+       reg[7:0] inversemap_inva_t;
+
+always @(  alp or   ahp)
+begin
+
+       
+       inversemap_alp_t=alp;
+       inversemap_ahp_t=ahp;
+       
+       aA=inversemap_alp_t[1]^inversemap_ahp_t[3];
+       aB=inversemap_ahp_t[0]^inversemap_ahp_t[1];
+       
+       inversemap_inva_t[0]=inversemap_alp_t[0]^inversemap_ahp_t[0];
+       inversemap_inva_t[1]=aB^inversemap_ahp_t[3];
+       inversemap_inva_t[2]=aA^aB;
+       inversemap_inva_t[3]=aB^inversemap_alp_t[1]^inversemap_ahp_t[2];
+       inversemap_inva_t[4]=aA^aB^inversemap_alp_t[3];
+       inversemap_inva_t[5]=aB^inversemap_alp_t[2];
+       inversemap_inva_t[6]=aA^inversemap_alp_t[2]^inversemap_alp_t[3]^inversemap_ahp_t[0];
+       inversemap_inva_t[7]=aB^inversemap_alp_t[2]^inversemap_ahp_t[3];
+       
+       inva = (inversemap_inva_t);
+
+end
+//mul1:
+reg[3:0] mul1_alxh_t;
+       reg[3:0] mul1_aA,mul1_a;
+
+always @(  ah or   al)
+
+begin
+
+       //alxah
+       
+       mul1_aA=al[0]^al[3];
+       mul1_a=al[2]^al[3];
+       
+       mul1_alxh_t[0]=(al[0]&ah[0])^(al[3]&ah[1])^(al[2]&ah[2])^(al[1]&ah[3]);
+       mul1_alxh_t[1]=(al[1]&ah[0])^(mul1_aA&ah[1])^(mul1_a&ah[2])^((al[1]^al[2])&ah[3]);
+       mul1_alxh_t[2]=(al[2]&ah[0])^(al[1]&ah[1])^(mul1_aA&ah[2])^(mul1_a&ah[3]);
+       mul1_alxh_t[3]=(al[3]&ah[0])^(al[2]&ah[1])^(al[1]&ah[2])^(mul1_aA&ah[3]);
+       
+       alxh = (mul1_alxh_t);
+
+end
+//mul2:
+reg[3:0] mul2_ahp_t;
+       reg[3:0] mul2_aA,mul2_aB;
+
+always @(  d or   ah_reg)
+
+begin
+
+       //ahxd
+       
+       mul2_aA=ah_reg[0]^ah_reg[3];
+       mul2_aB=ah_reg[2]^ah_reg[3];
+       
+       mul2_ahp_t[0]=(ah_reg[0]&d[0])^(ah_reg[3]&d[1])^(ah_reg[2]&d[2])^(ah_reg[1]&d[3]);
+       mul2_ahp_t[1]=(ah_reg[1]&d[0])^(mul2_aA&d[1])^(mul2_aB&d[2])^((ah_reg[1]^ah_reg[2])&d[3]);
+       mul2_ahp_t[2]=(ah_reg[2]&d[0])^(ah_reg[1]&d[1])^(mul2_aA&d[2])^(mul2_aB&d[3]);
+       mul2_ahp_t[3]=(ah_reg[3]&d[0])^(ah_reg[2]&d[1])^(ah_reg[1]&d[2])^(mul2_aA&d[3]);
+       
+       ahp = (mul2_ahp_t);
+
+end
+//mul3:
+reg[3:0] mul3_alp_t;
+       reg[3:0] mul3_aA,mul3_aB;
+
+always @(  d or   alph)
+
+begin
+
+       //dxal
+       
+       mul3_aA=d[0]^d[3];
+       mul3_aB=d[2]^d[3];
+       
+       mul3_alp_t[0]=(d[0]&alph[0])^(d[3]&alph[1])^(d[2]&alph[2])^(d[1]&alph[3]);
+       mul3_alp_t[1]=(d[1]&alph[0])^(mul3_aA&alph[1])^(mul3_aB&alph[2])^((d[1]^d[2])&alph[3]);
+       mul3_alp_t[2]=(d[2]&alph[0])^(d[1]&alph[1])^(mul3_aA&alph[2])^(mul3_aB&alph[3]);
+       mul3_alp_t[3]=(d[3]&alph[0])^(d[2]&alph[1])^(d[1]&alph[2])^(mul3_aA&alph[3]);
+       
+       alp = (mul3_alp_t);
+
+end
+//intermediate:
+reg[3:0] intermediate_aA,intermediate_aB;
+       reg[3:0] intermediate_ah2e,intermediate_ah2epl2,intermediate_to_invert_var;
+       
+always @(  ah2 or   al2 or   alxh)
+
+begin
+
+       
+       //ahsquareismultipliedwithe
+       intermediate_aA=ah2[0]^ah2[1];
+       intermediate_aB=ah2[2]^ah2[3];
+       intermediate_ah2e[0]=ah2[1]^intermediate_aB;
+       intermediate_ah2e[1]=intermediate_aA;
+       intermediate_ah2e[2]=intermediate_aA^ah2[2];
+       intermediate_ah2e[3]=intermediate_aA^intermediate_aB;
+       
+       //Additionofintermediate_ah2eplusal2
+       intermediate_ah2epl2[0]=intermediate_ah2e[0]^al2[0];
+       intermediate_ah2epl2[1]=intermediate_ah2e[1]^al2[1];
+       intermediate_ah2epl2[2]=intermediate_ah2e[2]^al2[2];
+       intermediate_ah2epl2[3]=intermediate_ah2e[3]^al2[3];
+       
+       //Additionoflastresultwiththeresultof(alxah)
+       intermediate_to_invert_var[0]=intermediate_ah2epl2[0]^alxh[0];
+       intermediate_to_invert_var[1]=intermediate_ah2epl2[1]^alxh[1];
+       intermediate_to_invert_var[2]=intermediate_ah2epl2[2]^alxh[2];
+       intermediate_to_invert_var[3]=intermediate_ah2epl2[3]^alxh[3];
+
+//Registers
+       next_to_invert = (intermediate_to_invert_var);
+
+end
+//inversion:
+reg[3:0] inversion_to_invert_var;
+       reg[3:0] inversion_aA,inversion_d_t;
+       
+always @(  to_invert)
+
+begin
+
+       
+       inversion_to_invert_var=to_invert;
+       
+       //InverttheresultinGF(2^4)
+       inversion_aA=inversion_to_invert_var[1]^inversion_to_invert_var[2]^inversion_to_invert_var[3]^(inversion_to_invert_var[1]&inversion_to_invert_var[2]&inversion_to_invert_var[3]);
+       inversion_d_t[0]=inversion_aA^inversion_to_invert_var[0]^(inversion_to_invert_var[0]&inversion_to_invert_var[2])^(inversion_to_invert_var[1]&inversion_to_invert_var[2])^(inversion_to_invert_var[0]&inversion_to_invert_var[1]&inversion_to_invert_var[2]);
+       inversion_d_t[1]=(inversion_to_invert_var[0]&inversion_to_invert_var[1])^(inversion_to_invert_var[0]&inversion_to_invert_var[2])^(inversion_to_invert_var[1]&inversion_to_invert_var[2])^inversion_to_invert_var[3]^(inversion_to_invert_var[1]&inversion_to_invert_var[3])^(inversion_to_invert_var[0]&inversion_to_invert_var[1]&inversion_to_invert_var[3]);
+       inversion_d_t[2]=(inversion_to_invert_var[0]&inversion_to_invert_var[1])^inversion_to_invert_var[2]^(inversion_to_invert_var[0]&inversion_to_invert_var[2])^inversion_to_invert_var[3]^(inversion_to_invert_var[0]&inversion_to_invert_var[3])^(inversion_to_invert_var[0]&inversion_to_invert_var[2]&inversion_to_invert_var[3]);
+       inversion_d_t[3]=inversion_aA^(inversion_to_invert_var[0]&inversion_to_invert_var[3])^(inversion_to_invert_var[1]&inversion_to_invert_var[3])^(inversion_to_invert_var[2]&inversion_to_invert_var[3]);
+       
+       d = (inversion_d_t);
+       
+
+end
+//sum1:
+reg[3:0] sum1_alph_t;
+       
+always @(  ah or   al)
+
+begin
+
+       
+       sum1_alph_t[0]=al[0]^ah[0];
+       sum1_alph_t[1]=al[1]^ah[1];
+       sum1_alph_t[2]=al[2]^ah[2];
+       sum1_alph_t[3]=al[3]^ah[3];
+       
+       next_alph = (sum1_alph_t);
+
+end
+//square1:
+reg[3:0] square1_ah_t;
+       
+always @(  ah)
+
+begin
+
+       
+       square1_ah_t[0]=ah[0]^ah[2];
+       square1_ah_t[1]=ah[2];
+       square1_ah_t[2]=ah[1]^ah[3];
+       square1_ah_t[3]=ah[3];
+       
+       ah2 = (square1_ah_t);
+
+end
+//square2:
+reg[3:0] square2_al_t;
+       
+always @(  al)
+
+begin
+
+       
+       square2_al_t[0]=al[0]^al[2];
+       square2_al_t[1]=al[2];
+       square2_al_t[2]=al[1]^al[3];
+       square2_al_t[3]=al[3];
+       
+       al2 = (square2_al_t);
+
+end
+
+endmodule
diff --git a/tests/iwls2005/systemcaes/subbytes.v b/tests/iwls2005/systemcaes/subbytes.v
new file mode 100644 (file)
index 0000000..6c6bd20
--- /dev/null
@@ -0,0 +1,259 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  Subbytes module implementation                              ////
+////                                                              ////
+////  This file is part of the SystemC AES                        ////
+////                                                              ////
+////  Description:                                                ////
+////  Subbytes module implementation                              ////
+////                                                              ////
+////  Generated automatically using SystemC to Verilog translator ////
+////                                                              ////
+////  To Do:                                                      ////
+////   - done                                                     ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Javier Castillo, jcastilo@opencores.org               ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2000 Authors and OPENCORES.ORG                 ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+//
+// CVS Revision History
+//
+// $Log: subbytes.v,v $
+// Revision 1.1.1.1  2004/07/05 09:46:23  jcastillo
+// First import
+//
+
+module subbytes(clk,reset,start_i,decrypt_i,data_i,ready_o,data_o,sbox_data_o,sbox_data_i,sbox_decrypt_o);
+input clk;
+input reset;
+input start_i;
+input decrypt_i;
+input [127:0] data_i;
+output ready_o;
+output [127:0] data_o;
+output [7:0] sbox_data_o;
+input [7:0] sbox_data_i;
+output sbox_decrypt_o;
+
+reg ready_o;
+reg [127:0] data_o;
+reg [7:0] sbox_data_o;
+reg sbox_decrypt_o;
+
+reg [4:0] state;
+reg [4:0] next_state;
+reg [127:0] data_reg;
+reg [127:0] next_data_reg;
+reg next_ready_o;
+
+`define assign_array_to_128 \
+       data_reg_128[127:120]=data_reg_var[0]; \
+       data_reg_128[119:112]=data_reg_var[1];  \
+       data_reg_128[111:104]=data_reg_var[2];   \
+       data_reg_128[103:96]=data_reg_var[3];     \
+       data_reg_128[95:88]=data_reg_var[4];       \
+       data_reg_128[87:80]=data_reg_var[5];        \
+       data_reg_128[79:72]=data_reg_var[6];             \
+       data_reg_128[71:64]=data_reg_var[7];              \
+       data_reg_128[63:56]=data_reg_var[8];               \
+       data_reg_128[55:48]=data_reg_var[9];                \
+       data_reg_128[47:40]=data_reg_var[10];                \
+       data_reg_128[39:32]=data_reg_var[11];                     \
+       data_reg_128[31:24]=data_reg_var[12];                      \
+       data_reg_128[23:16]=data_reg_var[13];                       \
+       data_reg_128[15:8]=data_reg_var[14];                             \
+       data_reg_128[7:0]=data_reg_var[15]; 
+
+`define shift_array_to_128 \
+       data_reg_128[127:120]=data_reg_var[0];   \
+       data_reg_128[119:112]=data_reg_var[5];    \
+       data_reg_128[111:104]=data_reg_var[10];    \
+       data_reg_128[103:96]=data_reg_var[15];      \
+       data_reg_128[95:88]=data_reg_var[4];             \
+       data_reg_128[87:80]=data_reg_var[9];              \
+       data_reg_128[79:72]=data_reg_var[14];              \
+       data_reg_128[71:64]=data_reg_var[3];                \
+       data_reg_128[63:56]=data_reg_var[8];                     \
+       data_reg_128[55:48]=data_reg_var[13];                     \
+       data_reg_128[47:40]=data_reg_var[2];                       \
+       data_reg_128[39:32]=data_reg_var[7];                        \
+       data_reg_128[31:24]=data_reg_var[12];                        \
+       data_reg_128[23:16]=data_reg_var[1];                              \
+       data_reg_128[15:8]=data_reg_var[6];                                \
+       data_reg_128[7:0]=data_reg_var[11]; 
+
+`define invert_shift_array_to_128              \
+       data_reg_128[127:120]=data_reg_var[0];   \
+       data_reg_128[119:112]=data_reg_var[13];    \
+       data_reg_128[111:104]=data_reg_var[10];   \
+       data_reg_128[103:96]=data_reg_var[7];      \
+       data_reg_128[95:88]=data_reg_var[4];        \
+       data_reg_128[87:80]=data_reg_var[1];             \
+       data_reg_128[79:72]=data_reg_var[14];             \
+       data_reg_128[71:64]=data_reg_var[11];              \
+       data_reg_128[63:56]=data_reg_var[8];                \
+       data_reg_128[55:48]=data_reg_var[5];                     \
+       data_reg_128[47:40]=data_reg_var[2];                      \
+       data_reg_128[39:32]=data_reg_var[15];                      \
+       data_reg_128[31:24]=data_reg_var[12];                       \
+       data_reg_128[23:16]=data_reg_var[9];                             \
+       data_reg_128[15:8]=data_reg_var[6];                               \
+       data_reg_128[7:0]=data_reg_var[3];                              
+
+
+//registers:
+always @(posedge clk or negedge reset)
+
+begin
+
+if(!reset)
+begin
+
+               data_reg = (0);
+               state = (0);
+               ready_o = (0);
+       
+end
+else
+begin
+
+               data_reg = (next_data_reg);
+               state = (next_state);
+               ready_o = (next_ready_o);
+       
+end
+
+
+end
+//sub:
+reg[127:0] data_i_var,data_reg_128;
+reg[7:0] data_array[15:0],data_reg_var[15:0];
+
+always @(  decrypt_i or   start_i or   state or   data_i or   sbox_data_i or   data_reg)
+
+begin
+
+       
+       data_i_var=data_i;
+
+       data_array[0]=data_i_var[127:120];
+       data_array[1]=data_i_var[119:112];
+       data_array[2]=data_i_var[111:104];
+       data_array[3]=data_i_var[103:96];
+       data_array[4]=data_i_var[95:88];
+       data_array[5]=data_i_var[87:80];
+       data_array[6]=data_i_var[79:72];
+       data_array[7]=data_i_var[71:64];
+       data_array[8]=data_i_var[63:56];
+       data_array[9]=data_i_var[55:48];
+       data_array[10]=data_i_var[47:40];
+       data_array[11]=data_i_var[39:32];
+       data_array[12]=data_i_var[31:24];
+       data_array[13]=data_i_var[23:16];
+       data_array[14]=data_i_var[15:8];
+       data_array[15]=data_i_var[7:0];
+       
+       data_reg_var[0]=data_reg[127:120];
+       data_reg_var[1]=data_reg[119:112];
+       data_reg_var[2]=data_reg[111:104];
+       data_reg_var[3]=data_reg[103:96];
+       data_reg_var[4]=data_reg[95:88];
+       data_reg_var[5]=data_reg[87:80];
+       data_reg_var[6]=data_reg[79:72];
+       data_reg_var[7]=data_reg[71:64];
+       data_reg_var[8]=data_reg[63:56];
+       data_reg_var[9]=data_reg[55:48];
+       data_reg_var[10]=data_reg[47:40];
+       data_reg_var[11]=data_reg[39:32];
+       data_reg_var[12]=data_reg[31:24];
+       data_reg_var[13]=data_reg[23:16];
+       data_reg_var[14]=data_reg[15:8];
+       data_reg_var[15]=data_reg[7:0];
+       
+               
+       sbox_decrypt_o = (decrypt_i);
+       sbox_data_o = (0);
+       next_state = (state);
+       next_data_reg = (data_reg);
+               
+       next_ready_o = (0);
+       data_o = (data_reg);
+       
+       case(state)
+       
+               0:
+begin
+                       if(start_i)
+begin
+
+sbox_data_o = (data_array[0]);
+                               next_state = (1);
+                       
+end
+
+                       end
+               16:
+begin
+                       data_reg_var[15]=sbox_data_i;
+               //Makeshiftrowsstage
+               case(decrypt_i)
+               0:
+               begin
+               `shift_array_to_128
+               end
+               1:
+               begin                   
+               `invert_shift_array_to_128
+               end
+               endcase
+               
+               next_data_reg = (data_reg_128);
+                       next_ready_o = (1);
+               next_state = (0);
+               end
+               default:
+               begin
+               /* original version (causing troubles with synopsys formality):
+                       sbox_data_o = (data_array[state]);
+                       data_reg_var[state-1]=sbox_data_i;
+                  improved version: */
+                       sbox_data_o = (data_array[state & 15]);
+                       data_reg_var[(state-1) & 15]=sbox_data_i;
+               /* end of improved version */
+               `assign_array_to_128
+                       next_data_reg = (data_reg_128);
+                       next_state = (state+1);
+               end
+       
+endcase
+
+
+end
+
+endmodule
diff --git a/tests/iwls2005/systemcaes/timescale.v b/tests/iwls2005/systemcaes/timescale.v
new file mode 100644 (file)
index 0000000..ff9e265
--- /dev/null
@@ -0,0 +1 @@
+`timescale 1ns / 10ps
diff --git a/tests/iwls2005/systemcaes/word_mixcolum.v b/tests/iwls2005/systemcaes/word_mixcolum.v
new file mode 100644 (file)
index 0000000..9308ccc
--- /dev/null
@@ -0,0 +1,124 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  Mixcolumns for a 16 bit word module implementation          ////
+////                                                              ////
+////  This file is part of the SystemC AES                        ////
+////                                                              ////
+////  Description:                                                ////
+////  Mixcolum for a 16 bit word                                  ////
+////                                                              ////
+////  Generated automatically using SystemC to Verilog translator ////
+////                                                              ////
+////  To Do:                                                      ////
+////   - done                                                     ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Javier Castillo, jcastilo@opencores.org               ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2000 Authors and OPENCORES.ORG                 ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+//
+// CVS Revision History
+//
+// $Log: word_mixcolum.v,v $
+// Revision 1.1.1.1  2004/07/05 09:46:23  jcastillo
+// First import
+//
+
+module word_mixcolum(in,outx,outy);
+input [31:0] in;
+output [31:0] outx;
+output [31:0] outy;
+
+reg [31:0] outx;
+reg [31:0] outy;
+
+reg [7:0] a;
+reg [7:0] b;
+reg [7:0] c;
+reg [7:0] d;
+wire [7:0] x1;
+
+wire [7:0] x2;
+
+wire [7:0] x3;
+
+wire [7:0] x4;
+
+wire [7:0] y1;
+
+wire [7:0] y2;
+
+wire [7:0] y3;
+
+wire [7:0] y4;
+
+
+byte_mixcolum bm1 (.a(a), .b(b), .c(c), .d(d), .outx(x1), .outy(y1));
+byte_mixcolum bm2 (.a(b), .b(c), .c(d), .d(a), .outx(x2), .outy(y2));
+byte_mixcolum bm3 (.a(c), .b(d), .c(a), .d(b), .outx(x3), .outy(y3));
+byte_mixcolum bm4 (.a(d), .b(a), .c(b), .d(c), .outx(x4), .outy(y4));
+
+
+               reg[31:0] in_var;
+               reg[31:0] outx_var,outy_var;
+//split:
+always @(  in)
+
+begin
+
+
+               
+               in_var=in;
+               a = (in_var[31:24]);
+               b = (in_var[23:16]);
+       c = (in_var[15:8]);
+               d = (in_var[7:0]);
+       
+end
+//mix:
+always @(  x1 or   x2 or   x3 or   x4 or   y1 or   y2 or   y3 or   y4)
+
+begin
+
+               
+               
+               outx_var[31:24]=x1;
+               outx_var[23:16]=x2;
+               outx_var[15:8]=x3;
+               outx_var[7:0]=x4;
+               outy_var[31:24]=y1;
+               outy_var[23:16]=y2;
+               outy_var[15:8]=y3;
+               outy_var[7:0]=y4;
+               
+               outx = (outx_var);
+               outy = (outy_var);
+       
+end
+
+endmodule
diff --git a/tests/iwls2005/usb_phy/timescale.v b/tests/iwls2005/usb_phy/timescale.v
new file mode 100644 (file)
index 0000000..ff9e265
--- /dev/null
@@ -0,0 +1 @@
+`timescale 1ns / 10ps
diff --git a/tests/iwls2005/usb_phy/usb_phy.v b/tests/iwls2005/usb_phy/usb_phy.v
new file mode 100644 (file)
index 0000000..4ee345a
--- /dev/null
@@ -0,0 +1,184 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  USB 1.1 PHY                                                ////
+////                                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/cores/usb_phy/   ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws                       ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: usb_phy.v,v 1.4 2003/10/21 05:58:40 rudi Exp $
+//
+//  $Date: 2003/10/21 05:58:40 $
+//  $Revision: 1.4 $
+//  $Author: rudi $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: usb_phy.v,v $
+//               Revision 1.4  2003/10/21 05:58:40  rudi
+//               usb_rst is no longer or'ed with the incomming reset internally.
+//               Now usb_rst is simply an output, the application can decide how
+//               to utilize it.
+//
+//               Revision 1.3  2003/10/19 17:40:13  rudi
+//               - Made core more robust against line noise
+//               - Added Error Checking and Reporting
+//               (See README.txt for more info)
+//
+//               Revision 1.2  2002/09/16 16:06:37  rudi
+//               Changed top level name to be consistent ...
+//
+//               Revision 1.1.1.1  2002/09/16 14:26:59  rudi
+//               Created Directory Structure
+//
+//
+//
+//
+//
+//
+//
+//
+
+`include "timescale.v"
+
+module usb_phy(clk, rst, phy_tx_mode, usb_rst,
+       
+               // Transciever Interface
+               txdp, txdn, txoe,       
+               rxd, rxdp, rxdn,
+
+               // UTMI Interface
+               DataOut_i, TxValid_i, TxReady_o, RxValid_o,
+               RxActive_o, RxError_o, DataIn_o, LineState_o
+               );
+
+input          clk;
+input          rst;
+input          phy_tx_mode;
+output         usb_rst;
+output         txdp, txdn, txoe;
+input          rxd, rxdp, rxdn;
+input  [7:0]   DataOut_i;
+input          TxValid_i;
+output         TxReady_o;
+output [7:0]   DataIn_o;
+output         RxValid_o;
+output         RxActive_o;
+output         RxError_o;
+output [1:0]   LineState_o;
+
+///////////////////////////////////////////////////////////////////
+//
+// Local Wires and Registers
+//
+
+reg    [4:0]   rst_cnt;
+reg            usb_rst;
+wire           fs_ce;
+wire           rst;
+
+///////////////////////////////////////////////////////////////////
+//
+// Misc Logic
+//
+
+///////////////////////////////////////////////////////////////////
+//
+// TX Phy
+//
+
+usb_tx_phy i_tx_phy(
+       .clk(           clk             ),
+       .rst(           rst             ),
+       .fs_ce(         fs_ce           ),
+       .phy_mode(      phy_tx_mode     ),
+
+       // Transciever Interface
+       .txdp(          txdp            ),
+       .txdn(          txdn            ),
+       .txoe(          txoe            ),
+
+       // UTMI Interface
+       .DataOut_i(     DataOut_i       ),
+       .TxValid_i(     TxValid_i       ),
+       .TxReady_o(     TxReady_o       )
+       );
+
+///////////////////////////////////////////////////////////////////
+//
+// RX Phy and DPLL
+//
+
+usb_rx_phy i_rx_phy(
+       .clk(           clk             ),
+       .rst(           rst             ),
+       .fs_ce(         fs_ce           ),
+
+       // Transciever Interface
+       .rxd(           rxd             ),
+       .rxdp(          rxdp            ),
+       .rxdn(          rxdn            ),
+
+       // UTMI Interface
+       .DataIn_o(      DataIn_o        ),
+       .RxValid_o(     RxValid_o       ),
+       .RxActive_o(    RxActive_o      ),
+       .RxError_o(     RxError_o       ),
+       .RxEn_i(        txoe            ),
+       .LineState(     LineState_o     )
+       );
+
+///////////////////////////////////////////////////////////////////
+//
+// Generate an USB Reset is we see SE0 for at least 2.5uS
+//
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)                        rst_cnt <= 5'h0;
+       else
+       if(LineState_o != 2'h0)         rst_cnt <= 5'h0;
+       else    
+       if(!usb_rst && fs_ce)           rst_cnt <= rst_cnt + 5'h1;
+
+always @(posedge clk)
+       usb_rst <= (rst_cnt == 5'h1f);
+
+endmodule
+
diff --git a/tests/iwls2005/usb_phy/usb_rx_phy.v b/tests/iwls2005/usb_phy/usb_rx_phy.v
new file mode 100644 (file)
index 0000000..c0568fb
--- /dev/null
@@ -0,0 +1,452 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  USB 1.1 PHY                                                ////
+////  RX & DPLL                                                  ////
+////                                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/cores/usb_phy/   ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws                       ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: usb_rx_phy.v,v 1.5 2004/10/19 09:29:07 rudi Exp $
+//
+//  $Date: 2004/10/19 09:29:07 $
+//  $Revision: 1.5 $
+//  $Author: rudi $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: usb_rx_phy.v,v $
+//               Revision 1.5  2004/10/19 09:29:07  rudi
+//               Fixed DPLL alignment in the rx_phy and bit stuffing errors in the tx_phy (if last bit bit was a stuff bit in a packet it was omitted).
+//
+//               Revision 1.4  2003/12/02 04:56:00  rudi
+//               Fixed a bug reported by Karl C. Posch from Graz University of Technology. Thanks Karl !
+//
+//               Revision 1.3  2003/10/19 18:07:45  rudi
+//               - Fixed Sync Error to be only checked/generated during the sync phase
+//
+//               Revision 1.2  2003/10/19 17:40:13  rudi
+//               - Made core more robust against line noise
+//               - Added Error Checking and Reporting
+//               (See README.txt for more info)
+//
+//               Revision 1.1.1.1  2002/09/16 14:27:01  rudi
+//               Created Directory Structure
+//
+//
+//
+//
+//
+//
+//
+//
+
+`include "timescale.v"
+
+module usb_rx_phy(     clk, rst, fs_ce,
+       
+                       // Transciever Interface
+                       rxd, rxdp, rxdn,
+
+                       // UTMI Interface
+                       RxValid_o, RxActive_o, RxError_o, DataIn_o,
+                       RxEn_i, LineState);
+
+input          clk;
+input          rst;
+output         fs_ce;
+input          rxd, rxdp, rxdn;
+output [7:0]   DataIn_o;
+output         RxValid_o;
+output         RxActive_o;
+output         RxError_o;
+input          RxEn_i;
+output [1:0]   LineState;
+
+///////////////////////////////////////////////////////////////////
+//
+// Local Wires and Registers
+//
+
+reg            rxd_s0, rxd_s1,  rxd_s;
+reg            rxdp_s0, rxdp_s1, rxdp_s, rxdp_s_r;
+reg            rxdn_s0, rxdn_s1, rxdn_s, rxdn_s_r;
+reg            synced_d;
+wire           k, j, se0;
+reg            rxd_r;
+reg            rx_en;
+reg            rx_active;
+reg    [2:0]   bit_cnt;
+reg            rx_valid1, rx_valid;
+reg            shift_en;
+reg            sd_r;
+reg            sd_nrzi;
+reg    [7:0]   hold_reg;
+wire           drop_bit;       // Indicates a stuffed bit
+reg    [2:0]   one_cnt;
+
+reg    [1:0]   dpll_state, dpll_next_state;
+reg            fs_ce_d;
+reg            fs_ce;
+wire           change;
+wire           lock_en;
+reg    [2:0]   fs_state, fs_next_state;
+reg            rx_valid_r;
+reg            sync_err_d, sync_err;
+reg            bit_stuff_err;
+reg            se0_r, byte_err;
+reg            se0_s;
+
+///////////////////////////////////////////////////////////////////
+//
+// Misc Logic
+//
+
+assign RxActive_o = rx_active;
+assign RxValid_o = rx_valid;
+assign RxError_o = sync_err | bit_stuff_err | byte_err;
+assign DataIn_o = hold_reg;
+assign LineState = {rxdn_s1, rxdp_s1};
+
+always @(posedge clk)  rx_en <= RxEn_i;
+always @(posedge clk)  sync_err <= !rx_active & sync_err_d;
+
+///////////////////////////////////////////////////////////////////
+//
+// Synchronize Inputs
+//
+
+// First synchronize to the local system clock to
+// avoid metastability outside the sync block (*_s0).
+// Then make sure we see the signal for at least two
+// clock cycles stable to avoid glitches and noise
+
+always @(posedge clk)  rxd_s0  <= rxd;
+always @(posedge clk)  rxd_s1  <= rxd_s0;
+always @(posedge clk)                                                  // Avoid detecting Line Glitches and noise
+       if(rxd_s0 && rxd_s1)    rxd_s <= 1'b1;
+       else
+       if(!rxd_s0 && !rxd_s1)  rxd_s <= 1'b0;
+
+always @(posedge clk)  rxdp_s0  <= rxdp;
+always @(posedge clk)  rxdp_s1  <= rxdp_s0;
+always @(posedge clk)  rxdp_s_r <= rxdp_s0 & rxdp_s1;
+always @(posedge clk)  rxdp_s   <= (rxdp_s0 & rxdp_s1) | rxdp_s_r;     // Avoid detecting Line Glitches and noise
+
+always @(posedge clk)  rxdn_s0  <= rxdn;
+always @(posedge clk)  rxdn_s1  <= rxdn_s0;
+always @(posedge clk)  rxdn_s_r <= rxdn_s0 & rxdn_s1;
+always @(posedge clk)  rxdn_s   <= (rxdn_s0 & rxdn_s1) | rxdn_s_r;     // Avoid detecting Line Glitches and noise
+
+assign k = !rxdp_s &  rxdn_s;
+assign j =  rxdp_s & !rxdn_s;
+assign se0 = !rxdp_s & !rxdn_s;
+
+always @(posedge clk)  if(fs_ce)       se0_s <= se0;
+
+///////////////////////////////////////////////////////////////////
+//
+// DPLL
+//
+
+// This design uses a clock enable to do 12Mhz timing and not a
+// real 12Mhz clock. Everything always runs at 48Mhz. We want to
+// make sure however, that the clock enable is always exactly in
+// the middle between two virtual 12Mhz rising edges.
+// We monitor rxdp and rxdn for any changes and do the appropiate
+// adjustments.
+// In addition to the locking done in the dpll FSM, we adjust the
+// final latch enable to compensate for various sync registers ...
+
+// Allow lockinf only when we are receiving
+assign lock_en = rx_en;
+
+always @(posedge clk)  rxd_r <= rxd_s;
+
+// Edge detector
+assign change = rxd_r != rxd_s;
+
+// DPLL FSM
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        dpll_state <= 2'h1;
+       else            dpll_state <= dpll_next_state;
+
+always @(dpll_state or lock_en or change)
+   begin
+       fs_ce_d = 1'b0;
+       case(dpll_state)        // synopsys full_case parallel_case
+          2'h0:
+               if(lock_en && change)   dpll_next_state = 2'h0;
+               else                    dpll_next_state = 2'h1;
+          2'h1:begin
+               fs_ce_d = 1'b1;
+               if(lock_en && change)   dpll_next_state = 2'h3;
+               else                    dpll_next_state = 2'h2;
+               end
+          2'h2:
+               if(lock_en && change)   dpll_next_state = 2'h0;
+               else                    dpll_next_state = 2'h3;
+          2'h3:
+               if(lock_en && change)   dpll_next_state = 2'h0;
+               else                    dpll_next_state = 2'h0;
+       endcase
+   end
+
+// Compensate for sync registers at the input - allign full speed
+// clock enable to be in the middle between two bit changes ...
+reg    fs_ce_r1, fs_ce_r2;
+
+always @(posedge clk)  fs_ce_r1 <= fs_ce_d;
+always @(posedge clk)  fs_ce_r2 <= fs_ce_r1;
+always @(posedge clk)  fs_ce <= fs_ce_r2;
+
+
+///////////////////////////////////////////////////////////////////
+//
+// Find Sync Pattern FSM
+//
+
+parameter      FS_IDLE = 3'h0,
+               K1      = 3'h1,
+               J1      = 3'h2,
+               K2      = 3'h3,
+               J2      = 3'h4,
+               K3      = 3'h5,
+               J3      = 3'h6,
+               K4      = 3'h7;
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        fs_state <= FS_IDLE;
+       else            fs_state <= fs_next_state;
+
+always @(fs_state or fs_ce or k or j or rx_en or rx_active or se0 or se0_s)
+   begin
+       synced_d = 1'b0;
+       sync_err_d = 1'b0;
+       fs_next_state = fs_state;
+       if(fs_ce && !rx_active && !se0 && !se0_s)
+          case(fs_state)       // synopsys full_case parallel_case
+               FS_IDLE:
+                    begin
+                       if(k && rx_en)  fs_next_state = K1;
+                    end
+               K1:
+                    begin
+                       if(j && rx_en)  fs_next_state = J1;
+                       else
+                          begin
+                                       sync_err_d = 1'b1;
+                                       fs_next_state = FS_IDLE;
+                          end
+                    end
+               J1:
+                    begin
+                       if(k && rx_en)  fs_next_state = K2;
+                       else
+                          begin
+                                       sync_err_d = 1'b1;
+                                       fs_next_state = FS_IDLE;
+                          end
+                    end
+               K2:
+                    begin
+                       if(j && rx_en)  fs_next_state = J2;
+                       else
+                          begin
+                                       sync_err_d = 1'b1;
+                                       fs_next_state = FS_IDLE;
+                          end
+                    end
+               J2:
+                    begin
+                       if(k && rx_en)  fs_next_state = K3;
+                       else
+                          begin
+                                       sync_err_d = 1'b1;
+                                       fs_next_state = FS_IDLE;
+                          end
+                    end
+               K3:
+                    begin
+                       if(j && rx_en)  fs_next_state = J3;
+                       else
+                       if(k && rx_en)
+                          begin
+                                       fs_next_state = FS_IDLE;        // Allow missing first K-J
+                                       synced_d = 1'b1;
+                          end
+                       else
+                          begin
+                                       sync_err_d = 1'b1;
+                                       fs_next_state = FS_IDLE;
+                          end
+                    end
+               J3:
+                    begin
+                       if(k && rx_en)  fs_next_state = K4;
+                       else
+                          begin
+                                       sync_err_d = 1'b1;
+                                       fs_next_state = FS_IDLE;
+                          end
+                    end
+               K4:
+                    begin
+                       if(k)   synced_d = 1'b1;
+                       fs_next_state = FS_IDLE;
+                    end
+          endcase
+   end
+
+///////////////////////////////////////////////////////////////////
+//
+// Generate RxActive
+//
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)                rx_active <= 1'b0;
+       else
+       if(synced_d && rx_en)   rx_active <= 1'b1;
+       else
+       if(se0 && rx_valid_r)   rx_active <= 1'b0;
+
+always @(posedge clk)
+       if(rx_valid)    rx_valid_r <= 1'b1;
+       else
+       if(fs_ce)       rx_valid_r <= 1'b0;
+
+///////////////////////////////////////////////////////////////////
+//
+// NRZI Decoder
+//
+
+always @(posedge clk)
+       if(fs_ce)       sd_r <= rxd_s;
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)                sd_nrzi <= 1'b0;
+       else
+       if(!rx_active)          sd_nrzi <= 1'b1;
+       else
+       if(rx_active && fs_ce)  sd_nrzi <= !(rxd_s ^ sd_r);
+
+///////////////////////////////////////////////////////////////////
+//
+// Bit Stuff Detect
+//
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        one_cnt <= 3'h0;
+       else
+       if(!shift_en)   one_cnt <= 3'h0;
+       else
+       if(fs_ce)
+          begin
+               if(!sd_nrzi || drop_bit)        one_cnt <= 3'h0;
+               else                            one_cnt <= one_cnt + 3'h1;
+          end
+
+assign drop_bit = (one_cnt==3'h6);
+
+always @(posedge clk)  bit_stuff_err <= drop_bit & sd_nrzi & fs_ce & !se0 & rx_active; // Bit Stuff Error
+
+///////////////////////////////////////////////////////////////////
+//
+// Serial => Parallel converter
+//
+
+always @(posedge clk)
+       if(fs_ce)       shift_en <= synced_d | rx_active;
+
+always @(posedge clk)
+       if(fs_ce && shift_en && !drop_bit)
+               hold_reg <= {sd_nrzi, hold_reg[7:1]};
+
+///////////////////////////////////////////////////////////////////
+//
+// Generate RxValid
+//
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)                bit_cnt <= 3'b0;
+       else
+       if(!shift_en)           bit_cnt <= 3'h0;
+       else
+       if(fs_ce && !drop_bit)  bit_cnt <= bit_cnt + 3'h1;
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)                                        rx_valid1 <= 1'b0;
+       else
+       if(fs_ce && !drop_bit && (bit_cnt==3'h7))       rx_valid1 <= 1'b1;
+       else
+       if(rx_valid1 && fs_ce && !drop_bit)             rx_valid1 <= 1'b0;
+
+always @(posedge clk)  rx_valid <= !drop_bit & rx_valid1 & fs_ce;
+
+always @(posedge clk)  se0_r <= se0;
+
+always @(posedge clk)  byte_err <= se0 & !se0_r & (|bit_cnt[2:1]) & rx_active;
+
+endmodule
+
diff --git a/tests/iwls2005/usb_phy/usb_tx_phy.v b/tests/iwls2005/usb_phy/usb_tx_phy.v
new file mode 100644 (file)
index 0000000..7f61ffd
--- /dev/null
@@ -0,0 +1,465 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  USB 1.1 PHY                                                ////
+////  TX                                                         ////
+////                                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/cores/usb_phy/   ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000-2002 Rudolf Usselmann                    ////
+////                         www.asics.ws                        ////
+////                         rudi@asics.ws                       ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: usb_tx_phy.v,v 1.4 2004/10/19 09:29:07 rudi Exp $
+//
+//  $Date: 2004/10/19 09:29:07 $
+//  $Revision: 1.4 $
+//  $Author: rudi $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: usb_tx_phy.v,v $
+//               Revision 1.4  2004/10/19 09:29:07  rudi
+//               Fixed DPLL alignment in the rx_phy and bit stuffing errors in the tx_phy (if last bit bit was a stuff bit in a packet it was omitted).
+//
+//               Revision 1.3  2003/10/21 05:58:41  rudi
+//               usb_rst is no longer or'ed with the incomming reset internally.
+//               Now usb_rst is simply an output, the application can decide how
+//               to utilize it.
+//
+//               Revision 1.2  2003/10/19 17:40:13  rudi
+//               - Made core more robust against line noise
+//               - Added Error Checking and Reporting
+//               (See README.txt for more info)
+//
+//               Revision 1.1.1.1  2002/09/16 14:27:02  rudi
+//               Created Directory Structure
+//
+//
+//
+//
+//
+//
+//
+
+`include "timescale.v"
+
+module usb_tx_phy(
+               clk, rst, fs_ce, phy_mode,
+       
+               // Transciever Interface
+               txdp, txdn, txoe,       
+
+               // UTMI Interface
+               DataOut_i, TxValid_i, TxReady_o
+               );
+
+input          clk;
+input          rst;
+input          fs_ce;
+input          phy_mode;
+output         txdp, txdn, txoe;
+input  [7:0]   DataOut_i;
+input          TxValid_i;
+output         TxReady_o;
+
+///////////////////////////////////////////////////////////////////
+//
+// Local Wires and Registers
+//
+
+parameter      IDLE    = 3'd0,
+               SOP     = 3'h1,
+               DATA    = 3'h2,
+               EOP1    = 3'h3,
+               EOP2    = 3'h4,
+               WAIT    = 3'h5;
+
+reg            TxReady_o;
+reg    [2:0]   state, next_state;
+reg            tx_ready_d;
+reg            ld_sop_d;
+reg            ld_data_d;
+reg            ld_eop_d;
+reg            tx_ip;
+reg            tx_ip_sync;
+reg    [2:0]   bit_cnt;
+reg    [7:0]   hold_reg;
+reg    [7:0]   hold_reg_d;
+
+reg            sd_raw_o;
+wire           hold;
+reg            data_done;
+reg            sft_done;
+reg            sft_done_r;
+wire           sft_done_e;
+reg            ld_data;
+wire           eop_done;
+reg    [2:0]   one_cnt;
+wire           stuff;
+reg            sd_bs_o;
+reg            sd_nrzi_o;
+reg            append_eop;
+reg            append_eop_sync1;
+reg            append_eop_sync2;
+reg            append_eop_sync3;
+reg            append_eop_sync4;
+reg            txdp, txdn;
+reg            txoe_r1, txoe_r2;
+reg            txoe;
+
+///////////////////////////////////////////////////////////////////
+//
+// Misc Logic
+//
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        TxReady_o <= 1'b0;
+       else            TxReady_o <= tx_ready_d & TxValid_i;
+
+always @(posedge clk) ld_data <= ld_data_d;
+
+///////////////////////////////////////////////////////////////////
+//
+// Transmit in progress indicator
+//
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        tx_ip <= 1'b0;
+       else
+       if(ld_sop_d)    tx_ip <= 1'b1;
+       else
+       if(eop_done)    tx_ip <= 1'b0;
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)                tx_ip_sync <= 1'b0;
+       else
+       if(fs_ce)               tx_ip_sync <= tx_ip;
+
+// data_done helps us to catch cases where TxValid drops due to
+// packet end and then gets re-asserted as a new packet starts.
+// We might not see this because we are still transmitting.
+// data_done should solve those cases ...
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)                        data_done <= 1'b0;
+       else
+       if(TxValid_i && ! tx_ip)        data_done <= 1'b1;
+       else
+       if(!TxValid_i)                  data_done <= 1'b0;
+
+///////////////////////////////////////////////////////////////////
+//
+// Shift Register
+//
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)                bit_cnt <= 3'h0;
+       else
+       if(!tx_ip_sync)         bit_cnt <= 3'h0;
+       else
+       if(fs_ce && !hold)      bit_cnt <= bit_cnt + 3'h1;
+
+assign hold = stuff;
+
+always @(posedge clk)
+       if(!tx_ip_sync)         sd_raw_o <= 1'b0;
+       else
+       case(bit_cnt)   // synopsys full_case parallel_case
+          3'h0: sd_raw_o <= hold_reg_d[0];
+          3'h1: sd_raw_o <= hold_reg_d[1];
+          3'h2: sd_raw_o <= hold_reg_d[2];
+          3'h3: sd_raw_o <= hold_reg_d[3];
+          3'h4: sd_raw_o <= hold_reg_d[4];
+          3'h5: sd_raw_o <= hold_reg_d[5];
+          3'h6: sd_raw_o <= hold_reg_d[6];
+          3'h7: sd_raw_o <= hold_reg_d[7];
+       endcase
+
+always @(posedge clk)
+       sft_done <= !hold & (bit_cnt == 3'h7);
+
+always @(posedge clk)
+       sft_done_r <= sft_done;
+
+assign sft_done_e = sft_done & !sft_done_r;
+
+// Out Data Hold Register
+always @(posedge clk)
+       if(ld_sop_d)    hold_reg <= 8'h80;
+       else
+       if(ld_data)     hold_reg <= DataOut_i;
+
+always @(posedge clk) hold_reg_d <= hold_reg;
+
+///////////////////////////////////////////////////////////////////
+//
+// Bit Stuffer
+//
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        one_cnt <= 3'h0;
+       else
+       if(!tx_ip_sync) one_cnt <= 3'h0;
+       else
+       if(fs_ce)
+          begin
+               if(!sd_raw_o || stuff)  one_cnt <= 3'h0;
+               else                    one_cnt <= one_cnt + 3'h1;
+          end
+
+assign stuff = (one_cnt==3'h6);
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        sd_bs_o <= 1'h0;
+       else
+       if(fs_ce)       sd_bs_o <= !tx_ip_sync ? 1'b0 : (stuff ? 1'b0 : sd_raw_o);
+
+///////////////////////////////////////////////////////////////////
+//
+// NRZI Encoder
+//
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)                        sd_nrzi_o <= 1'b1;
+       else
+       if(!tx_ip_sync || !txoe_r1)     sd_nrzi_o <= 1'b1;
+       else
+       if(fs_ce)                       sd_nrzi_o <= sd_bs_o ? sd_nrzi_o : ~sd_nrzi_o;
+
+///////////////////////////////////////////////////////////////////
+//
+// EOP append logic
+//
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)                append_eop <= 1'b0;
+       else
+       if(ld_eop_d)            append_eop <= 1'b1;
+       else
+       if(append_eop_sync2)    append_eop <= 1'b0;
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        append_eop_sync1 <= 1'b0;
+       else
+       if(fs_ce)       append_eop_sync1 <= append_eop;
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        append_eop_sync2 <= 1'b0;
+       else
+       if(fs_ce)       append_eop_sync2 <= append_eop_sync1;
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        append_eop_sync3 <= 1'b0;
+       else
+       if(fs_ce)       append_eop_sync3 <= append_eop_sync2 |
+                       (append_eop_sync3 & !append_eop_sync4); // Make sure always 2 bit wide
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        append_eop_sync4 <= 1'b0;
+       else
+       if(fs_ce)       append_eop_sync4 <= append_eop_sync3;
+
+assign eop_done = append_eop_sync3;
+
+///////////////////////////////////////////////////////////////////
+//
+// Output Enable Logic
+//
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        txoe_r1 <= 1'b0;
+       else
+       if(fs_ce)       txoe_r1 <= tx_ip_sync;
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        txoe_r2 <= 1'b0;
+       else
+       if(fs_ce)       txoe_r2 <= txoe_r1;
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        txoe <= 1'b1;
+       else
+       if(fs_ce)       txoe <= !(txoe_r1 | txoe_r2);
+
+///////////////////////////////////////////////////////////////////
+//
+// Output Registers
+//
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        txdp <= 1'b1;
+       else
+       if(fs_ce)       txdp <= phy_mode ?
+                                       (!append_eop_sync3 &  sd_nrzi_o) :
+                                       sd_nrzi_o;
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        txdn <= 1'b0;
+       else
+       if(fs_ce)       txdn <= phy_mode ?
+                                       (!append_eop_sync3 & ~sd_nrzi_o) :
+                                       append_eop_sync3;
+
+///////////////////////////////////////////////////////////////////
+//
+// Tx Statemashine
+//
+
+`ifdef USB_ASYNC_REST
+always @(posedge clk or negedge rst)
+`else
+always @(posedge clk)
+`endif
+       if(!rst)        state <= IDLE;
+       else            state <= next_state;
+
+always @(state or TxValid_i or data_done or sft_done_e or eop_done or fs_ce)
+   begin
+       next_state = state;
+       tx_ready_d = 1'b0;
+
+       ld_sop_d = 1'b0;
+       ld_data_d = 1'b0;
+       ld_eop_d = 1'b0;
+
+       case(state)     // synopsys full_case parallel_case
+          IDLE:
+                       if(TxValid_i)
+                          begin
+                               ld_sop_d = 1'b1;
+                               next_state = SOP;
+                          end
+          SOP:
+                       if(sft_done_e)
+                          begin
+                               tx_ready_d = 1'b1;
+                               ld_data_d = 1'b1;
+                               next_state = DATA;
+                          end
+          DATA:
+                  begin
+                       if(!data_done && sft_done_e)
+                          begin
+                               ld_eop_d = 1'b1;
+                               next_state = EOP1;
+                          end
+                       
+                       if(data_done && sft_done_e)
+                          begin
+                               tx_ready_d = 1'b1;
+                               ld_data_d = 1'b1;
+                          end
+                  end
+          EOP1:
+                       if(eop_done)            next_state = EOP2;
+          EOP2:
+                       if(!eop_done && fs_ce)  next_state = WAIT;
+          WAIT:
+                       if(fs_ce)               next_state = IDLE;
+       endcase
+   end
+
+endmodule
+
diff --git a/tests/no-icarus/README b/tests/no-icarus/README
new file mode 100644 (file)
index 0000000..b43e7c0
--- /dev/null
@@ -0,0 +1,2 @@
+This directory contains test cases that can't be tested using Icarus Verilog
+because they exceed the Verilog subset that is supported by Icarus Verilog.
diff --git a/tests/no-icarus/autowire.v b/tests/no-icarus/autowire.v
new file mode 100644 (file)
index 0000000..3633d42
--- /dev/null
@@ -0,0 +1,25 @@
+
+module test01(a, b, y);
+
+input [3:0] a, b;
+output [3:0] y;
+
+assign temp1 = a + b;
+assign temp2 = ~temp1;
+assign y = temp2;
+
+endmodule
+
+// ------------------------------
+
+module test02(a, b, y);
+
+input [3:0] a, b;
+output [3:0] y;
+
+test01 test01_cell(A, B, Y);
+
+assign A = a, B = b, y = Y;
+
+endmodule
+
diff --git a/tests/no-icarus/var_range.v b/tests/no-icarus/var_range.v
new file mode 100644 (file)
index 0000000..431eacb
--- /dev/null
@@ -0,0 +1,45 @@
+
+module test01(a, b, x, y, z);
+
+input [7:0] a;
+input [2:0] b;
+output [7:0] x, y;
+output z;
+
+assign x = a >> b;
+assign y = a[b+7:b];
+assign z = a[b];
+
+endmodule
+
+module test02(clk, a, b, x, y, z);
+
+input clk;
+input [7:0] a;
+input [2:0] b;
+output reg [7:0] x, y;
+output reg z;
+
+always @(posedge clk) begin
+       x <= a >> b;
+       y <= a[b+7:b];
+       z <= a[b];
+end
+
+endmodule
+
+module test03(clk, a, b, x, y);
+
+input clk;
+input [2:0] a, b;
+output reg [7:0] x;
+output reg [9:0] y;
+
+always @(posedge clk)
+       y[b] <= a;
+
+always @(posedge clk)
+       y[b+2:b] <= a;
+
+endmodule
+
diff --git a/tests/openmsp430/rtl/omsp_alu.v b/tests/openmsp430/rtl/omsp_alu.v
new file mode 100644 (file)
index 0000000..d106997
--- /dev/null
@@ -0,0 +1,258 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_alu.v
+// 
+// *Module Description:
+//                       openMSP430 ALU
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 134 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2012-03-22 21:31:06 +0100 (Thu, 22 Mar 2012) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module  omsp_alu (
+
+// OUTPUTs
+    alu_out,                       // ALU output value
+    alu_out_add,                   // ALU adder output value
+    alu_stat,                      // ALU Status {V,N,Z,C}
+    alu_stat_wr,                   // ALU Status write {V,N,Z,C}
+
+// INPUTs
+    dbg_halt_st,                   // Halt/Run status from CPU
+    exec_cycle,                    // Instruction execution cycle
+    inst_alu,                      // ALU control signals
+    inst_bw,                       // Decoded Inst: byte width
+    inst_jmp,                      // Decoded Inst: Conditional jump
+    inst_so,                       // Single-operand arithmetic
+    op_dst,                        // Destination operand
+    op_src,                        // Source operand
+    status                         // R2 Status {V,N,Z,C}
+);
+
+// OUTPUTs
+//=========
+output       [15:0] alu_out;       // ALU output value
+output       [15:0] alu_out_add;   // ALU adder output value
+output        [3:0] alu_stat;      // ALU Status {V,N,Z,C}
+output        [3:0] alu_stat_wr;   // ALU Status write {V,N,Z,C}
+
+// INPUTs
+//=========
+input               dbg_halt_st;   // Halt/Run status from CPU
+input               exec_cycle;    // Instruction execution cycle
+input        [11:0] inst_alu;      // ALU control signals
+input               inst_bw;       // Decoded Inst: byte width
+input         [7:0] inst_jmp;      // Decoded Inst: Conditional jump
+input         [7:0] inst_so;       // Single-operand arithmetic
+input        [15:0] op_dst;        // Destination operand
+input        [15:0] op_src;        // Source operand
+input         [3:0] status;        // R2 Status {V,N,Z,C}
+
+
+//=============================================================================
+// 1)  FUNCTIONS
+//=============================================================================
+
+function [4:0] bcd_add;
+
+   input [3:0] X;
+   input [3:0] Y;
+   input       C_;
+
+   reg   [4:0] Z_;
+   begin
+      Z_ = {1'b0,X}+{1'b0,Y}+{4'b0,C_};
+      if (Z_<5'd10) bcd_add = Z_;
+      else          bcd_add = Z_+5'd6;
+   end
+
+endfunction
+
+
+//=============================================================================
+// 2)  INSTRUCTION FETCH/DECODE CONTROL STATE MACHINE
+//=============================================================================
+// SINGLE-OPERAND ARITHMETIC:
+//-----------------------------------------------------------------------------
+//   Mnemonic   S-Reg,   Operation                               Status bits
+//              D-Reg,                                            V  N  Z  C
+//
+//   RRC         dst     C->MSB->...LSB->C                        *  *  *  *
+//   RRA         dst     MSB->MSB->...LSB->C                      0  *  *  *
+//   SWPB        dst     Swap bytes                               -  -  -  -
+//   SXT         dst     Bit7->Bit8...Bit15                       0  *  *  *
+//   PUSH        src     SP-2->SP, src->@SP                       -  -  -  -
+//   CALL        dst     SP-2->SP, PC+2->@SP, dst->PC             -  -  -  -
+//   RETI                TOS->SR, SP+2->SP, TOS->PC, SP+2->SP     *  *  *  *
+//
+//-----------------------------------------------------------------------------
+// TWO-OPERAND ARITHMETIC:
+//-----------------------------------------------------------------------------
+//   Mnemonic   S-Reg,   Operation                               Status bits
+//              D-Reg,                                            V  N  Z  C
+//
+//   MOV       src,dst    src            -> dst                   -  -  -  -
+//   ADD       src,dst    src +  dst     -> dst                   *  *  *  *
+//   ADDC      src,dst    src +  dst + C -> dst                   *  *  *  *
+//   SUB       src,dst    dst + ~src + 1 -> dst                   *  *  *  *
+//   SUBC      src,dst    dst + ~src + C -> dst                   *  *  *  *
+//   CMP       src,dst    dst + ~src + 1                          *  *  *  *
+//   DADD      src,dst    src +  dst + C -> dst (decimaly)        *  *  *  *
+//   BIT       src,dst    src &  dst                              0  *  *  *
+//   BIC       src,dst   ~src &  dst     -> dst                   -  -  -  -
+//   BIS       src,dst    src |  dst     -> dst                   -  -  -  -
+//   XOR       src,dst    src ^  dst     -> dst                   *  *  *  *
+//   AND       src,dst    src &  dst     -> dst                   0  *  *  *
+//
+//-----------------------------------------------------------------------------
+// * the status bit is affected
+// - the status bit is not affected
+// 0 the status bit is cleared
+// 1 the status bit is set
+//-----------------------------------------------------------------------------
+
+// Invert source for substract and compare instructions.
+wire        op_src_inv_cmd = exec_cycle & (inst_alu[`ALU_SRC_INV]);
+wire [15:0] op_src_inv     = {16{op_src_inv_cmd}} ^ op_src;
+
+
+// Mask the bit 8 for the Byte instructions for correct flags generation
+wire        op_bit8_msk     = ~exec_cycle | ~inst_bw;
+wire [16:0] op_src_in       = {1'b0, {op_src_inv[15:8] & {8{op_bit8_msk}}}, op_src_inv[7:0]};
+wire [16:0] op_dst_in       = {1'b0, {op_dst[15:8]     & {8{op_bit8_msk}}}, op_dst[7:0]};
+
+// Clear the source operand (= jump offset) for conditional jumps
+wire        jmp_not_taken  = (inst_jmp[`JL]  & ~(status[3]^status[2])) |
+                             (inst_jmp[`JGE] &  (status[3]^status[2])) |
+                             (inst_jmp[`JN]  &  ~status[2])            |
+                             (inst_jmp[`JC]  &  ~status[0])            |
+                             (inst_jmp[`JNC] &   status[0])            |
+                             (inst_jmp[`JEQ] &  ~status[1])            |
+                             (inst_jmp[`JNE] &   status[1]);
+wire [16:0] op_src_in_jmp  = op_src_in & {17{~jmp_not_taken}};
+
+// Adder / AND / OR / XOR
+wire [16:0] alu_add        = op_src_in_jmp + op_dst_in;
+wire [16:0] alu_and        = op_src_in     & op_dst_in;
+wire [16:0] alu_or         = op_src_in     | op_dst_in;
+wire [16:0] alu_xor        = op_src_in     ^ op_dst_in;
+
+
+// Incrementer
+wire        alu_inc         = exec_cycle & ((inst_alu[`ALU_INC_C] & status[0]) |
+                                             inst_alu[`ALU_INC]);
+wire [16:0] alu_add_inc    = alu_add + {16'h0000, alu_inc};
+
+
+
+// Decimal adder (DADD)
+wire  [4:0] alu_dadd0      = bcd_add(op_src_in[3:0],   op_dst_in[3:0],  status[0]);
+wire  [4:0] alu_dadd1      = bcd_add(op_src_in[7:4],   op_dst_in[7:4],  alu_dadd0[4]);
+wire  [4:0] alu_dadd2      = bcd_add(op_src_in[11:8],  op_dst_in[11:8], alu_dadd1[4]);
+wire  [4:0] alu_dadd3      = bcd_add(op_src_in[15:12], op_dst_in[15:12],alu_dadd2[4]);
+wire [16:0] alu_dadd       = {alu_dadd3, alu_dadd2[3:0], alu_dadd1[3:0], alu_dadd0[3:0]};
+
+
+// Shifter for rotate instructions (RRC & RRA)
+wire        alu_shift_msb  = inst_so[`RRC] ? status[0]     :
+                            inst_bw       ? op_src[7]     : op_src[15];
+wire        alu_shift_7    = inst_bw       ? alu_shift_msb : op_src[8];
+wire [16:0] alu_shift      = {1'b0, alu_shift_msb, op_src[15:9], alu_shift_7, op_src[7:1]};
+
+
+// Swap bytes / Extend Sign
+wire [16:0] alu_swpb       = {1'b0, op_src[7:0],op_src[15:8]};
+wire [16:0] alu_sxt        = {1'b0, {8{op_src[7]}},op_src[7:0]};
+
+
+// Combine short paths toghether to simplify final ALU mux
+wire        alu_short_thro = ~(inst_alu[`ALU_AND]   |
+                               inst_alu[`ALU_OR]    |
+                               inst_alu[`ALU_XOR]   |
+                               inst_alu[`ALU_SHIFT] |
+                               inst_so[`SWPB]       |
+                               inst_so[`SXT]);
+
+wire [16:0] alu_short      = ({17{inst_alu[`ALU_AND]}}   & alu_and)   |
+                             ({17{inst_alu[`ALU_OR]}}    & alu_or)    |
+                             ({17{inst_alu[`ALU_XOR]}}   & alu_xor)   |
+                             ({17{inst_alu[`ALU_SHIFT]}} & alu_shift) |
+                             ({17{inst_so[`SWPB]}}       & alu_swpb)  |
+                             ({17{inst_so[`SXT]}}        & alu_sxt)   |
+                             ({17{alu_short_thro}}       & op_src_in);
+
+
+// ALU output mux
+wire [16:0] alu_out_nxt    = (inst_so[`IRQ] | dbg_halt_st |
+                              inst_alu[`ALU_ADD]) ? alu_add_inc :
+                              inst_alu[`ALU_DADD] ? alu_dadd    : alu_short;
+
+assign      alu_out        =  alu_out_nxt[15:0];
+assign      alu_out_add    =  alu_add[15:0];
+
+
+//-----------------------------------------------------------------------------
+// STATUS FLAG GENERATION
+//-----------------------------------------------------------------------------
+
+wire    V_xor       = inst_bw ? (op_src_in[7]  & op_dst_in[7])  :
+                                (op_src_in[15] & op_dst_in[15]);
+
+wire    V           = inst_bw ? ((~op_src_in[7]  & ~op_dst_in[7]  &  alu_out[7])  |
+                                 ( op_src_in[7]  &  op_dst_in[7]  & ~alu_out[7])) :
+                                ((~op_src_in[15] & ~op_dst_in[15] &  alu_out[15]) |
+                                 ( op_src_in[15] &  op_dst_in[15] & ~alu_out[15]));
+
+wire    N           = inst_bw ?  alu_out[7]       : alu_out[15];
+wire    Z           = inst_bw ? (alu_out[7:0]==0) : (alu_out==0);
+wire    C           = inst_bw ?  alu_out[8]       : alu_out_nxt[16];
+
+assign  alu_stat    = inst_alu[`ALU_SHIFT]  ? {1'b0, N,Z,op_src_in[0]} :
+                      inst_alu[`ALU_STAT_7] ? {1'b0, N,Z,~Z}           :
+                      inst_alu[`ALU_XOR]    ? {V_xor,N,Z,~Z}           : {V,N,Z,C};
+
+assign  alu_stat_wr = (inst_alu[`ALU_STAT_F] & exec_cycle) ? 4'b1111 : 4'b0000;
+
+
+endmodule // omsp_alu
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
diff --git a/tests/openmsp430/rtl/omsp_and_gate.v b/tests/openmsp430/rtl/omsp_and_gate.v
new file mode 100644 (file)
index 0000000..7ceeb8d
--- /dev/null
@@ -0,0 +1,89 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_and_gate.v
+// 
+// *Module Description:
+//                       Generic AND gate cell for the openMSP430
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 103 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $
+//----------------------------------------------------------------------------
+
+module  omsp_and_gate (
+
+// OUTPUTs
+    y,                         // AND gate output
+
+// INPUTs
+    a,                         // AND gate input A
+    b                          // AND gate input B
+);
+
+// OUTPUTs
+//=========
+output         y;              // AND gate output
+
+// INPUTs
+//=========
+input          a;              // AND gate input A
+input          b;              // AND gate input B
+
+
+//=============================================================================
+// 1)  SOME COMMENTS ON THIS MODULE
+//=============================================================================
+//
+//    In its ASIC version, some combinatorial pathes of the openMSP430 are
+// sensitive to glitches, in particular the ones generating the wakeup
+// signals.
+//    To prevent synthesis from optmizing combinatorial clouds into glitchy
+// logic, this AND gate module has been instanciated in the critical places.
+//
+//    Make sure that synthesis doesn't ungroup this module. As an alternative,
+// a standard cell from the library could also be directly instanciated here
+// (don't forget the "dont_touch" attribute)
+//
+//
+//=============================================================================
+// 2)  AND GATE
+//=============================================================================
+
+assign  y  =  a & b;
+
+
+endmodule // omsp_and_gate
+
+
+
diff --git a/tests/openmsp430/rtl/omsp_clock_gate.v b/tests/openmsp430/rtl/omsp_clock_gate.v
new file mode 100644 (file)
index 0000000..8ffe8e0
--- /dev/null
@@ -0,0 +1,86 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_clock_gate.v
+// 
+// *Module Description:
+//                       Generic clock gate cell for the openMSP430
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 103 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $
+//----------------------------------------------------------------------------
+
+module  omsp_clock_gate (
+
+// OUTPUTs
+    gclk,                      // Gated clock
+
+// INPUTs
+    clk,                       // Clock
+    enable,                    // Clock enable
+    scan_enable                // Scan enable (active during scan shifting)
+);
+
+// OUTPUTs
+//=========
+output         gclk;           // Gated clock
+
+// INPUTs
+//=========
+input          clk;            // Clock
+input          enable;         // Clock enable
+input          scan_enable;    // Scan enable (active during scan shifting)
+
+
+//=============================================================================
+// CLOCK GATE: LATCH + AND
+//=============================================================================
+   
+// Enable clock gate during scan shift
+// (the gate itself is checked with the scan capture cycle)
+wire    enable_in =   (enable | scan_enable);
+
+// LATCH the enable signal
+reg     enable_latch;
+always @(clk or enable_in)
+  if (~clk)
+    enable_latch <= enable_in;
+
+// AND gate
+assign  gclk      =  (clk & enable_latch);
+
+
+endmodule // omsp_clock_gate
+
+
diff --git a/tests/openmsp430/rtl/omsp_clock_module.v b/tests/openmsp430/rtl/omsp_clock_module.v
new file mode 100644 (file)
index 0000000..670c5e5
--- /dev/null
@@ -0,0 +1,1058 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_clock_module.v
+// 
+// *Module Description:
+//                       Basic clock module implementation.
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 134 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2012-03-22 21:31:06 +0100 (Thu, 22 Mar 2012) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module  omsp_clock_module (
+
+// OUTPUTs
+    aclk,                         // ACLK
+    aclk_en,                      // ACLK enable
+    cpu_en_s,                     // Enable CPU code execution (synchronous)
+    dbg_clk,                      // Debug unit clock
+    dbg_en_s,                     // Debug interface enable (synchronous)
+    dbg_rst,                      // Debug unit reset
+    dco_enable,                   // Fast oscillator enable
+    dco_wkup,                     // Fast oscillator wake-up (asynchronous)
+    lfxt_enable,                  // Low frequency oscillator enable
+    lfxt_wkup,                    // Low frequency oscillator wake-up (asynchronous)
+    mclk,                         // Main system clock
+    per_dout,                     // Peripheral data output
+    por,                          // Power-on reset
+    puc_pnd_set,                  // PUC pending set for the serial debug interface
+    puc_rst,                      // Main system reset
+    smclk,                        // SMCLK
+    smclk_en,                     // SMCLK enable
+            
+// INPUTs
+    cpu_en,                       // Enable CPU code execution (asynchronous)
+    cpuoff,                       // Turns off the CPU
+    dbg_cpu_reset,                // Reset CPU from debug interface
+    dbg_en,                       // Debug interface enable (asynchronous)
+    dco_clk,                      // Fast oscillator (fast clock)
+    lfxt_clk,                     // Low frequency oscillator (typ 32kHz)
+    mclk_enable,                  // Main System Clock enable
+    mclk_wkup,                    // Main System Clock wake-up (asynchronous)
+    oscoff,                       // Turns off LFXT1 clock input
+    per_addr,                     // Peripheral address
+    per_din,                      // Peripheral data input
+    per_en,                       // Peripheral enable (high active)
+    per_we,                       // Peripheral write enable (high active)
+    reset_n,                      // Reset Pin (low active, asynchronous)
+    scan_enable,                  // Scan enable (active during scan shifting)
+    scan_mode,                    // Scan mode
+    scg0,                         // System clock generator 1. Turns off the DCO
+    scg1,                         // System clock generator 1. Turns off the SMCLK
+    wdt_reset                     // Watchdog-timer reset
+);
+
+// OUTPUTs
+//=========
+output              aclk;         // ACLK
+output              aclk_en;      // ACLK enable
+output              cpu_en_s;     // Enable CPU code execution (synchronous)
+output              dbg_clk;      // Debug unit clock
+output              dbg_en_s;     // Debug unit enable (synchronous)
+output              dbg_rst;      // Debug unit reset
+output              dco_enable;   // Fast oscillator enable
+output              dco_wkup;     // Fast oscillator wake-up (asynchronous)
+output              lfxt_enable;  // Low frequency oscillator enable
+output              lfxt_wkup;    // Low frequency oscillator wake-up (asynchronous)
+output              mclk;         // Main system clock
+output       [15:0] per_dout;     // Peripheral data output
+output              por;          // Power-on reset
+output              puc_pnd_set;  // PUC pending set for the serial debug interface
+output              puc_rst;      // Main system reset
+output              smclk;        // SMCLK
+output              smclk_en;     // SMCLK enable
+
+// INPUTs
+//=========
+input               cpu_en;       // Enable CPU code execution (asynchronous)
+input               cpuoff;       // Turns off the CPU
+input               dbg_cpu_reset;// Reset CPU from debug interface
+input               dbg_en;       // Debug interface enable (asynchronous)
+input               dco_clk;      // Fast oscillator (fast clock)
+input               lfxt_clk;     // Low frequency oscillator (typ 32kHz)
+input               mclk_enable;  // Main System Clock enable
+input               mclk_wkup;    // Main System Clock wake-up (asynchronous)
+input               oscoff;       // Turns off LFXT1 clock input
+input        [13:0] per_addr;     // Peripheral address
+input        [15:0] per_din;      // Peripheral data input
+input               per_en;       // Peripheral enable (high active)
+input         [1:0] per_we;       // Peripheral write enable (high active)
+input               reset_n;      // Reset Pin (low active, asynchronous)
+input               scan_enable;  // Scan enable (active during scan shifting)
+input               scan_mode;    // Scan mode
+input               scg0;         // System clock generator 1. Turns off the DCO
+input               scg1;         // System clock generator 1. Turns off the SMCLK
+input               wdt_reset;    // Watchdog-timer reset
+
+
+//=============================================================================
+// 1)  WIRES & PARAMETER DECLARATION
+//=============================================================================
+
+// Register base address (must be aligned to decoder bit width)
+parameter       [14:0] BASE_ADDR   = 15'h0050;
+
+// Decoder bit width (defines how many bits are considered for address decoding)
+parameter              DEC_WD      =  4;
+
+// Register addresses offset
+parameter [DEC_WD-1:0] BCSCTL1     =  'h7,
+                       BCSCTL2     =  'h8;
+
+// Register one-hot decoder utilities
+parameter              DEC_SZ      =  (1 << DEC_WD);
+parameter [DEC_SZ-1:0] BASE_REG    =  {{DEC_SZ-1{1'b0}}, 1'b1};
+
+// Register one-hot decoder
+parameter [DEC_SZ-1:0] BCSCTL1_D   = (BASE_REG << BCSCTL1),
+                       BCSCTL2_D   = (BASE_REG << BCSCTL2);
+
+// Local wire declarations
+wire nodiv_mclk;
+wire nodiv_mclk_n;
+wire nodiv_smclk;
+
+
+//============================================================================
+// 2)  REGISTER DECODER
+//============================================================================
+
+// Local register selection
+wire              reg_sel      =  per_en & (per_addr[13:DEC_WD-1]==BASE_ADDR[14:DEC_WD]);
+
+// Register local address
+wire [DEC_WD-1:0] reg_addr     =  {1'b0, per_addr[DEC_WD-2:0]};
+
+// Register address decode
+wire [DEC_SZ-1:0] reg_dec      = (BCSCTL1_D  &  {DEC_SZ{(reg_addr==(BCSCTL1 >>1))}}) |
+                                 (BCSCTL2_D  &  {DEC_SZ{(reg_addr==(BCSCTL2 >>1))}});
+
+// Read/Write probes
+wire              reg_lo_write =  per_we[0] & reg_sel;
+wire              reg_hi_write =  per_we[1] & reg_sel;
+wire              reg_read     = ~|per_we   & reg_sel;
+
+// Read/Write vectors
+wire [DEC_SZ-1:0] reg_hi_wr    = reg_dec & {DEC_SZ{reg_hi_write}};
+wire [DEC_SZ-1:0] reg_lo_wr    = reg_dec & {DEC_SZ{reg_lo_write}};
+wire [DEC_SZ-1:0] reg_rd       = reg_dec & {DEC_SZ{reg_read}};
+
+
+//============================================================================
+// 3) REGISTERS
+//============================================================================
+
+// BCSCTL1 Register
+//--------------
+reg  [7:0] bcsctl1;
+wire       bcsctl1_wr  = BCSCTL1[0] ? reg_hi_wr[BCSCTL1] : reg_lo_wr[BCSCTL1];
+wire [7:0] bcsctl1_nxt = BCSCTL1[0] ? per_din[15:8]      : per_din[7:0];
+
+`ifdef ASIC
+  `ifdef ACLK_DIVIDER
+wire [7:0] divax_mask = 8'h30;
+  `else
+wire [7:0] divax_mask = 8'h00;
+  `endif
+`else
+wire [7:0] divax_mask = 8'h30;
+`endif
+
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst)          bcsctl1  <=  8'h00;
+  else if (bcsctl1_wr)  bcsctl1  <=  bcsctl1_nxt & divax_mask; // Mask unused bits
+
+
+// BCSCTL2 Register
+//--------------
+reg  [7:0] bcsctl2;
+wire       bcsctl2_wr    = BCSCTL2[0] ? reg_hi_wr[BCSCTL2] : reg_lo_wr[BCSCTL2];
+wire [7:0] bcsctl2_nxt   = BCSCTL2[0] ? per_din[15:8]      : per_din[7:0];
+
+`ifdef MCLK_MUX
+wire [7:0] selmx_mask = 8'h80;
+`else
+wire [7:0] selmx_mask = 8'h00;
+`endif
+`ifdef MCLK_DIVIDER
+wire [7:0] divmx_mask = 8'h30;
+`else
+wire [7:0] divmx_mask = 8'h00;
+`endif
+`ifdef ASIC
+  `ifdef SMCLK_MUX
+wire [7:0] sels_mask  = 8'h08;
+  `else
+wire [7:0] sels_mask  = 8'h00;
+  `endif
+  `ifdef SMCLK_DIVIDER
+wire [7:0] divsx_mask = 8'h06;
+  `else
+wire [7:0] divsx_mask = 8'h00;
+  `endif
+`else
+wire [7:0] sels_mask  = 8'h08;
+wire [7:0] divsx_mask = 8'h06;
+`endif
+
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst)          bcsctl2  <=  8'h00;
+  else if (bcsctl2_wr)  bcsctl2  <=  bcsctl2_nxt & ( sels_mask  | divsx_mask |
+                                                     selmx_mask | divmx_mask); // Mask unused bits
+
+
+//============================================================================
+// 4) DATA OUTPUT GENERATION
+//============================================================================
+
+// Data output mux
+wire [15:0] bcsctl1_rd   = {8'h00, (bcsctl1  & {8{reg_rd[BCSCTL1]}})}  << (8 & {4{BCSCTL1[0]}});
+wire [15:0] bcsctl2_rd   = {8'h00, (bcsctl2  & {8{reg_rd[BCSCTL2]}})}  << (8 & {4{BCSCTL2[0]}});
+
+wire [15:0] per_dout =  bcsctl1_rd   |
+                        bcsctl2_rd;
+
+
+//=============================================================================
+// 5)  DCO_CLK / LFXT_CLK INTERFACES (WAKEUP, ENABLE, ...)
+//=============================================================================
+
+`ifdef ASIC
+   wire cpuoff_and_mclk_enable;
+   omsp_and_gate and_cpuoff_mclk_en (.y(cpuoff_and_mclk_enable), .a(cpuoff), .b(mclk_enable));
+`endif
+
+//-----------------------------------------------------------
+// 5.1) HIGH SPEED SYSTEM CLOCK GENERATOR (DCO_CLK)
+//-----------------------------------------------------------
+// Note1: switching off the DCO osillator is only
+//        supported in ASIC mode with SCG0 low power mode
+//
+// Note2: unlike the original MSP430 specification,
+//        we allow to switch off the DCO even
+//        if it is selected by MCLK or SMCLK.
+
+wire por_a;
+wire dco_wkup;
+wire cpu_en_wkup;
+
+`ifdef SCG0_EN
+
+   // The DCO oscillator is synchronously disabled if:
+   //      - the cpu pin is disabled (in that case, wait for mclk_enable==0)
+   //      - the debug interface is disabled
+   //      - SCG0 is set (in that case, wait for the mclk_enable==0 if selected by SELMx)
+   //
+   // Note that we make extensive use of the AND gate module in order
+   // to prevent glitch propagation on the wakeup logic cone.
+   wire cpu_enabled_with_dco;
+   wire dco_not_enabled_by_dbg;
+   wire dco_disable_by_scg0;
+   wire dco_disable_by_cpu_en;
+   wire dco_enable_nxt;
+   omsp_and_gate and_dco_dis1 (.y(cpu_enabled_with_dco),   .a(~bcsctl2[`SELMx]),     .b(cpuoff_and_mclk_enable));
+   omsp_and_gate and_dco_dis2 (.y(dco_not_enabled_by_dbg), .a(~dbg_en_s),            .b(~cpu_enabled_with_dco));
+   omsp_and_gate and_dco_dis3 (.y(dco_disable_by_scg0),    .a(scg0),                 .b(dco_not_enabled_by_dbg));
+   omsp_and_gate and_dco_dis4 (.y(dco_disable_by_cpu_en),  .a(~cpu_en_s),            .b(~mclk_enable));
+   omsp_and_gate and_dco_dis5 (.y(dco_enable_nxt),         .a(~dco_disable_by_scg0), .b(~dco_disable_by_cpu_en));
+
+   // Register to prevent glitch propagation
+   reg  dco_disable;
+   always @(posedge nodiv_mclk_n or posedge por)
+   if (por) dco_disable <= 1'b1;
+   else     dco_disable <= ~dco_enable_nxt;
+
+   // Note that a synchronizer is required if the MCLK mux is included
+   wire dco_clk_n  = ~dco_clk;
+   `ifdef MCLK_MUX
+      omsp_sync_cell sync_cell_dco_disable (
+         .data_out  (dco_enable),
+         .data_in   (~dco_disable),
+         .clk       (dco_clk_n),
+         .rst       (por)
+      );
+   `else
+
+      assign dco_enable     = ~dco_disable;
+   `endif
+
+   // The DCO oscillator will get an asynchronous wakeup if:
+   //      - the MCLK  generates a wakeup (only if the MCLK mux selects dco_clk)
+   //      - if the DCO wants to be synchronously enabled (i.e dco_enable_nxt=1)
+   wire dco_mclk_wkup;
+   wire dco_en_wkup;
+   omsp_and_gate and_dco_mclk_wkup (.y(dco_mclk_wkup), .a(mclk_wkup),   .b(~bcsctl2[`SELMx]));
+   omsp_and_gate and_dco_en_wkup   (.y(dco_en_wkup),   .a(~dco_enable), .b(dco_enable_nxt));
+
+   wire dco_wkup_set = dco_mclk_wkup | dco_en_wkup | cpu_en_wkup;
+
+   // Scan MUX for the asynchronous SET
+   wire dco_wkup_set_scan;
+   omsp_scan_mux scan_mux_dco_wkup (
+                                   .scan_mode    (scan_mode),
+                                   .data_in_scan (por_a),
+                                   .data_in_func (dco_wkup_set | por),
+                                   .data_out     (dco_wkup_set_scan)
+                                  );
+
+   // Scan MUX to increase coverage 
+   wire dco_wkup_clear;
+   omsp_scan_mux scan_mux_dco_wkup_clear (
+                                         .scan_mode    (scan_mode),
+                                         .data_in_scan (dco_wkup_set),
+                                         .data_in_func (1'b1),
+                                         .data_out     (dco_wkup_clear)
+                                        );
+
+   // The wakeup is asynchronously set, synchronously released
+   wire dco_wkup_n;
+   omsp_sync_cell sync_cell_dco_wkup (
+       .data_out  (dco_wkup_n),
+       .data_in   (dco_wkup_clear),
+       .clk       (dco_clk_n),
+       .rst       (dco_wkup_set_scan)
+   );
+
+   omsp_and_gate and_dco_wkup (.y(dco_wkup), .a(~dco_wkup_n), .b(cpu_en));
+
+`else
+   assign dco_enable    = 1'b1;
+   assign dco_wkup      = 1'b1;
+`endif
+
+
+//-----------------------------------------------------------
+// 5.2) LOW FREQUENCY CRYSTAL CLOCK GENERATOR (LFXT_CLK)
+//-----------------------------------------------------------
+
+// ASIC MODE
+//------------------------------------------------
+// Note: unlike the original MSP430 specification,
+//       we allow to switch off the LFXT even
+//       if it is selected by MCLK or SMCLK.
+`ifdef ASIC
+
+`ifdef OSCOFF_EN
+
+   // The LFXT is synchronously disabled if:
+   //      - the cpu pin is disabled (in that case, wait for mclk_enable==0)
+   //      - the debug interface is disabled
+   //      - OSCOFF is set (in that case, wait for the mclk_enable==0 if selected by SELMx)
+   wire cpu_enabled_with_lfxt;
+   wire lfxt_not_enabled_by_dbg;
+   wire lfxt_disable_by_oscoff;
+   wire lfxt_disable_by_cpu_en;
+   wire lfxt_enable_nxt;
+   omsp_and_gate and_lfxt_dis1 (.y(cpu_enabled_with_lfxt),   .a(bcsctl2[`SELMx]),         .b(cpuoff_and_mclk_enable));
+   omsp_and_gate and_lfxt_dis2 (.y(lfxt_not_enabled_by_dbg), .a(~dbg_en_s),               .b(~cpu_enabled_with_lfxt));
+   omsp_and_gate and_lfxt_dis3 (.y(lfxt_disable_by_oscoff),  .a(oscoff),                  .b(lfxt_not_enabled_by_dbg));
+   omsp_and_gate and_lfxt_dis4 (.y(lfxt_disable_by_cpu_en),  .a(~cpu_en_s),               .b(~mclk_enable));
+   omsp_and_gate and_lfxt_dis5 (.y(lfxt_enable_nxt),         .a(~lfxt_disable_by_oscoff), .b(~lfxt_disable_by_cpu_en));
+
+   // Register to prevent glitch propagation
+   reg  lfxt_disable;
+   always @(posedge nodiv_mclk_n or posedge por)
+   if (por) lfxt_disable <= 1'b1;
+   else     lfxt_disable <= ~lfxt_enable_nxt;
+
+   // Synchronize the OSCOFF control signal to the LFXT clock domain
+   wire lfxt_clk_n  = ~lfxt_clk;
+   omsp_sync_cell sync_cell_lfxt_disable (
+      .data_out  (lfxt_enable),
+      .data_in   (~lfxt_disable),
+      .clk       (lfxt_clk_n),
+      .rst       (por)
+   );
+
+   // The LFXT will get an asynchronous wakeup if:
+   //      - the MCLK  generates a wakeup (only if the MCLK  mux selects lfxt_clk)
+   //      - if the LFXT wants to be synchronously enabled (i.e lfxt_enable_nxt=1)
+   wire lfxt_mclk_wkup;
+   wire lfxt_en_wkup;
+   omsp_and_gate and_lfxt_mclk_wkup (.y(lfxt_mclk_wkup), .a(mclk_wkup),    .b(bcsctl2[`SELMx]));
+   omsp_and_gate and_lfxt_en_wkup   (.y(lfxt_en_wkup),   .a(~lfxt_enable), .b(lfxt_enable_nxt));
+
+   wire   lfxt_wkup_set  = lfxt_mclk_wkup | lfxt_en_wkup | cpu_en_wkup;
+
+   // Scan MUX for the asynchronous SET
+   wire lfxt_wkup_set_scan;
+   omsp_scan_mux scan_mux_lfxt_wkup (
+                                    .scan_mode    (scan_mode),
+                                    .data_in_scan (por_a),
+                                    .data_in_func (lfxt_wkup_set | por),
+                                    .data_out     (lfxt_wkup_set_scan)
+                                   );
+
+   // Scan MUX to increase coverage 
+   wire lfxt_wkup_clear;
+   omsp_scan_mux scan_mux_lfxt_wkup_clear (
+                                          .scan_mode    (scan_mode),
+                                          .data_in_scan (lfxt_wkup_set),
+                                          .data_in_func (1'b1),
+                                          .data_out     (lfxt_wkup_clear)
+                                         );
+
+   // The wakeup is asynchronously set, synchronously released
+   wire lfxt_wkup_n;
+   omsp_sync_cell sync_cell_lfxt_wkup (
+       .data_out  (lfxt_wkup_n),
+       .data_in   (lfxt_wkup_clear),
+       .clk       (lfxt_clk_n),
+       .rst       (lfxt_wkup_set_scan)
+   );
+
+   omsp_and_gate and_lfxt_wkup (.y(lfxt_wkup), .a(~lfxt_wkup_n), .b(cpu_en));
+
+`else
+   assign lfxt_enable    = 1'b1;
+   assign lfxt_wkup      = 1'b0;
+`endif
+
+
+// FPGA MODE
+//---------------------------------------
+// Synchronize LFXT_CLK & edge detection
+`else
+
+wire lfxt_clk_s;
+
+omsp_sync_cell sync_cell_lfxt_clk (
+    .data_out  (lfxt_clk_s),
+    .data_in   (lfxt_clk),
+    .clk       (mclk),
+    .rst       (por)
+);
+
+reg  lfxt_clk_dly;
+   
+always @ (posedge mclk or posedge por)
+  if (por) lfxt_clk_dly <=  1'b0;
+  else     lfxt_clk_dly <=  lfxt_clk_s;    
+
+wire   lfxt_clk_en = (lfxt_clk_s & ~lfxt_clk_dly) & ~(oscoff & ~bcsctl2[`SELS]);
+assign lfxt_enable = 1'b1;
+assign lfxt_wkup   = 1'b0;
+`endif     
+
+   
+//=============================================================================
+// 6)  CLOCK GENERATION
+//=============================================================================
+
+//-----------------------------------------------------------
+// 6.1) GLOBAL CPU ENABLE
+//-----------------------------------------------------------
+// ACLK and SMCLK are directly switched-off
+// with the cpu_en pin (after synchronization).
+// MCLK will be switched off once the CPU reaches
+// its IDLE state (through the mclk_enable signal)
+
+
+// Synchronize CPU_EN signal to the MCLK domain
+//----------------------------------------------
+`ifdef SYNC_CPU_EN
+   omsp_sync_cell sync_cell_cpu_en (
+      .data_out  (cpu_en_s),
+      .data_in   (cpu_en),
+      .clk       (nodiv_mclk),
+      .rst       (por)
+   );
+   omsp_and_gate and_cpu_en_wkup (.y(cpu_en_wkup), .a(cpu_en), .b(~cpu_en_s));
+`else
+   assign cpu_en_s    = cpu_en;
+   assign cpu_en_wkup = 1'b0;
+`endif
+
+// Synchronize CPU_EN signal to the ACLK domain
+//----------------------------------------------
+`ifdef LFXT_DOMAIN
+   wire cpu_en_aux_s;
+   omsp_sync_cell sync_cell_cpu_aux_en (
+      .data_out  (cpu_en_aux_s),
+      .data_in   (cpu_en),
+      .clk       (lfxt_clk),
+      .rst       (por)
+   );
+`else
+   wire   cpu_en_aux_s    = cpu_en_s;
+`endif
+
+// Synchronize CPU_EN signal to the SMCLK domain
+//----------------------------------------------
+// Note: the synchronizer is only required if there is a SMCLK_MUX
+`ifdef ASIC
+  `ifdef SMCLK_MUX
+     wire cpu_en_sm_s;
+     omsp_sync_cell sync_cell_cpu_sm_en (
+        .data_out  (cpu_en_sm_s),
+        .data_in   (cpu_en),
+        .clk       (nodiv_smclk),
+        .rst       (por)
+     );
+  `else
+   wire   cpu_en_sm_s    = cpu_en_s;
+  `endif
+`endif
+
+
+//-----------------------------------------------------------
+// 6.2) MCLK GENERATION
+//-----------------------------------------------------------
+
+// Clock MUX
+//----------------------------
+`ifdef MCLK_MUX
+omsp_clock_mux clock_mux_mclk (
+   .clk_out   (nodiv_mclk),
+   .clk_in0   (dco_clk),
+   .clk_in1   (lfxt_clk),
+   .reset     (por),
+   .scan_mode (scan_mode),
+   .select    (bcsctl2[`SELMx])
+);
+`else
+assign nodiv_mclk   =  dco_clk;
+`endif
+assign nodiv_mclk_n = ~nodiv_mclk;
+   
+
+// Wakeup synchronizer
+//----------------------------
+wire mclk_wkup_s;
+
+`ifdef CPUOFF_EN
+omsp_sync_cell sync_cell_mclk_wkup (
+   .data_out  (mclk_wkup_s),
+   .data_in   (mclk_wkup),
+   .clk       (nodiv_mclk),
+   .rst       (puc_rst)
+);
+`else
+   assign mclk_wkup_s = 1'b0;
+`endif
+
+
+// Clock Divider
+//----------------------------
+// No need for extra synchronizer as bcsctl2
+// comes from the same clock domain.
+
+`ifdef CPUOFF_EN
+wire mclk_active = mclk_enable | mclk_wkup_s | (dbg_en_s & cpu_en_s);
+`else
+wire mclk_active = 1'b1;
+`endif
+   
+`ifdef MCLK_DIVIDER
+reg [2:0] mclk_div;
+always @ (posedge nodiv_mclk or posedge puc_rst)
+  if (puc_rst)                       mclk_div <=  3'h0;
+  else if ((bcsctl2[`DIVMx]!=2'b00)) mclk_div <=  mclk_div+3'h1;
+
+  wire  mclk_div_en = mclk_active & ((bcsctl2[`DIVMx]==2'b00) ?  1'b1          :
+                                     (bcsctl2[`DIVMx]==2'b01) ?  mclk_div[0]   :
+                                     (bcsctl2[`DIVMx]==2'b10) ? &mclk_div[1:0] :
+                                                                &mclk_div[2:0]);
+`else
+  wire  mclk_div_en = mclk_active;
+`endif
+
+
+// Generate main system clock
+//----------------------------
+`ifdef MCLK_CGATE
+
+omsp_clock_gate clock_gate_mclk (
+    .gclk        (mclk),
+    .clk         (nodiv_mclk),
+    .enable      (mclk_div_en),
+    .scan_enable (scan_enable)
+);
+`else
+   assign mclk   = nodiv_mclk;
+`endif
+
+
+//-----------------------------------------------------------
+// 6.3) ACLK GENERATION
+//-----------------------------------------------------------
+
+// ASIC MODE
+//----------------------------
+`ifdef ASIC
+
+  `ifdef ACLK_DIVIDER
+    `ifdef LFXT_DOMAIN
+
+   wire nodiv_aclk = lfxt_clk;
+
+   // Local Reset synchronizer
+   wire puc_lfxt_rst;
+   wire puc_lfxt_noscan_n;
+   omsp_sync_cell sync_cell_puc_lfxt (
+       .data_out     (puc_lfxt_noscan_n),
+       .data_in      (1'b1),
+       .clk          (nodiv_aclk),
+       .rst          (puc_rst)
+   );
+   omsp_scan_mux scan_mux_puc_lfxt (
+       .scan_mode    (scan_mode),
+       .data_in_scan (por_a),
+       .data_in_func (~puc_lfxt_noscan_n),
+       .data_out     (puc_lfxt_rst)
+   );
+
+   // Local synchronizer for the bcsctl1.DIVAx configuration
+   // (note that we can live with a full bus synchronizer as
+   //  it won't hurt if we get a wrong DIVAx value for a single clock cycle)
+   reg [1:0] divax_s;
+   reg [1:0] divax_ss;
+   always @ (posedge nodiv_aclk or posedge puc_lfxt_rst)
+     if (puc_lfxt_rst)
+       begin
+         divax_s  <=  2'h0;
+         divax_ss <=  2'h0;
+       end
+     else
+       begin
+         divax_s  <=  bcsctl1[`DIVAx];
+         divax_ss <=  divax_s;
+       end
+
+     // If the OSCOFF mode is enabled synchronize OSCOFF signal
+     wire oscoff_s;
+     `ifdef OSCOFF_EN
+         omsp_sync_cell sync_cell_oscoff (
+           .data_out     (oscoff_s),
+           .data_in      (oscoff),
+           .clk          (nodiv_aclk),
+           .rst          (puc_lfxt_rst)
+         );
+     `else
+     assign oscoff_s = 1'b0;
+     `endif
+  `else
+   wire       puc_lfxt_rst = puc_rst;
+   wire       nodiv_aclk   = dco_clk;
+   wire [1:0] divax_ss     = bcsctl1[`DIVAx];
+   wire       oscoff_s     = oscoff;
+  `endif   
+
+   // Divider
+   reg [2:0] aclk_div;
+   always @ (posedge nodiv_aclk or posedge puc_lfxt_rst)
+     if (puc_lfxt_rst)           aclk_div <=  3'h0;
+     else if ((divax_ss!=2'b00)) aclk_div <=  aclk_div+3'h1;
+
+   wire      aclk_div_en =  cpu_en_aux_s & ~oscoff_s & ((divax_ss==2'b00) ?  1'b1          :
+                                                        (divax_ss==2'b01) ?  aclk_div[0]   :
+                                                        (divax_ss==2'b10) ? &aclk_div[1:0] :
+                                                                            &aclk_div[2:0]);
+
+   // Clock gate
+   omsp_clock_gate clock_gate_aclk (
+      .gclk        (aclk),
+      .clk         (nodiv_aclk),
+      .enable      (aclk_div_en),
+      .scan_enable (scan_enable)
+   );
+
+ `else
+    `ifdef LFXT_DOMAIN
+    assign  aclk    = lfxt_clk;
+    `else
+    assign  aclk    = dco_clk;
+    `endif
+  `endif
+   
+
+    assign  aclk_en = 1'b1;
+
+
+// FPGA MODE
+//----------------------------
+`else
+  reg       aclk_en;
+  reg [2:0] aclk_div;
+  wire      aclk_en_nxt =  lfxt_clk_en & ((bcsctl1[`DIVAx]==2'b00) ?  1'b1          :
+                                          (bcsctl1[`DIVAx]==2'b01) ?  aclk_div[0]   :
+                                          (bcsctl1[`DIVAx]==2'b10) ? &aclk_div[1:0] :
+                                                                     &aclk_div[2:0]);
+
+  always @ (posedge mclk or posedge puc_rst)
+    if (puc_rst)                                     aclk_div <=  3'h0;
+    else if ((bcsctl1[`DIVAx]!=2'b00) & lfxt_clk_en) aclk_div <=  aclk_div+3'h1;
+
+  always @ (posedge mclk or posedge puc_rst)
+    if (puc_rst)  aclk_en <=  1'b0;
+    else          aclk_en <=  aclk_en_nxt & cpu_en_s;
+
+  assign  aclk   = mclk;
+`endif
+   
+//-----------------------------------------------------------
+// 6.4) SMCLK GENERATION
+//-----------------------------------------------------------
+
+// Clock MUX
+//----------------------------
+`ifdef SMCLK_MUX
+omsp_clock_mux clock_mux_smclk (
+   .clk_out   (nodiv_smclk),
+   .clk_in0   (dco_clk),
+   .clk_in1   (lfxt_clk),
+   .reset     (por),
+   .scan_mode (scan_mode),
+   .select    (bcsctl2[`SELS])
+);
+`else
+assign nodiv_smclk = dco_clk;
+`endif
+
+
+// ASIC MODE
+//----------------------------
+`ifdef ASIC
+  `ifdef SMCLK_MUX
+
+    // Synchronizers
+    //------------------------------------------------------
+    // When the SMCLK MUX is enabled, the reset and DIVSx
+    // and SCG1 signals must be synchronized, otherwise not.
+   
+     // Local Reset synchronizer
+     wire puc_sm_noscan_n;
+     wire puc_sm_rst;
+     omsp_sync_cell sync_cell_puc_sm (
+         .data_out     (puc_sm_noscan_n),
+         .data_in      (1'b1),
+         .clk          (nodiv_smclk),
+         .rst          (puc_rst)
+     );
+     omsp_scan_mux scan_mux_puc_sm (
+         .scan_mode    (scan_mode),
+         .data_in_scan (por_a),
+         .data_in_func (~puc_sm_noscan_n),
+         .data_out     (puc_sm_rst)
+     );
+
+     // SCG1 synchronizer
+     `ifdef SCG1_EN
+     wire scg1_s;
+     omsp_sync_cell sync_cell_scg1 (
+         .data_out     (scg1_s),
+         .data_in      (scg1),
+         .clk          (nodiv_smclk),
+         .rst          (puc_sm_rst)
+     );
+     `else
+     wire scg1_s = 1'b0;
+     `endif
+
+    `ifdef SMCLK_DIVIDER
+     // Local synchronizer for the bcsctl2.DIVSx configuration
+     // (note that we can live with a full bus synchronizer as
+     //  it won't hurt if we get a wrong DIVSx value for a single clock cycle)
+     reg [1:0] divsx_s;
+     reg [1:0] divsx_ss;
+     always @ (posedge nodiv_smclk or posedge puc_sm_rst)
+       if (puc_sm_rst)
+         begin
+           divsx_s  <=  2'h0;
+           divsx_ss <=  2'h0;
+        end
+       else
+        begin
+           divsx_s  <=  bcsctl2[`DIVSx];
+           divsx_ss <=  divsx_s;
+        end
+    `endif
+   
+   `else
+   
+      wire       puc_sm_rst   = puc_rst;
+      wire [1:0] divsx_ss     = bcsctl2[`DIVSx];
+      wire       scg1_s       = scg1;
+  `endif
+   
+   
+
+   // Clock Divider
+   //----------------------------
+ `ifdef SMCLK_DIVIDER
+
+   reg [2:0] smclk_div;
+   always @ (posedge nodiv_smclk or posedge puc_sm_rst)
+     if (puc_sm_rst)             smclk_div <=  3'h0;
+     else if ((divsx_ss!=2'b00)) smclk_div <=  smclk_div+3'h1;
+
+   wire  smclk_div_en = cpu_en_sm_s & ~scg1_s & ((divsx_ss==2'b00) ?  1'b1           :
+                                                 (divsx_ss==2'b01) ?  smclk_div[0]   :
+                                                 (divsx_ss==2'b10) ? &smclk_div[1:0] :
+                                                                     &smclk_div[2:0]);
+ `else
+   `ifdef SCG1_EN
+    wire smclk_div_en = cpu_en_sm_s & ~scg1_s;
+   `else
+    wire smclk_div_en = cpu_en_sm_s;
+   `endif
+ `endif
+   
+
+   // Generate sub-system clock
+   //----------------------------
+ `ifdef SMCLK_CGATE
+   omsp_clock_gate clock_gate_smclk (
+      .gclk        (smclk),
+      .clk         (nodiv_smclk),
+      .enable      (smclk_div_en),
+      .scan_enable (scan_enable)
+   );
+ `else
+   assign  smclk    = nodiv_smclk;
+ `endif
+   
+   assign  smclk_en = 1'b1;
+
+
+// FPGA MODE
+//----------------------------
+`else
+reg       smclk_en;
+reg [2:0] smclk_div;
+
+wire      smclk_in     = ~scg1 & (bcsctl2[`SELS] ? lfxt_clk_en : 1'b1);
+
+wire      smclk_en_nxt = smclk_in & ((bcsctl2[`DIVSx]==2'b00) ?  1'b1           :
+                                     (bcsctl2[`DIVSx]==2'b01) ?  smclk_div[0]   :
+                                     (bcsctl2[`DIVSx]==2'b10) ? &smclk_div[1:0] :
+                                                                &smclk_div[2:0]);
+   
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst)  smclk_en <=  1'b0;
+  else          smclk_en <=  smclk_en_nxt & cpu_en_s;
+
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst)                                  smclk_div <=  3'h0;
+  else if ((bcsctl2[`DIVSx]!=2'b00) & smclk_in) smclk_div <=  smclk_div+3'h1;
+
+wire  smclk  = mclk;
+
+`endif
+
+//-----------------------------------------------------------
+// 6.5) DEBUG INTERFACE CLOCK GENERATION (DBG_CLK)
+//-----------------------------------------------------------
+
+// Synchronize DBG_EN signal to MCLK domain
+//------------------------------------------
+`ifdef DBG_EN
+`ifdef SYNC_DBG_EN
+    wire dbg_en_n_s;
+    omsp_sync_cell sync_cell_dbg_en (
+       .data_out  (dbg_en_n_s),
+       .data_in   (~dbg_en),
+       .clk       (mclk),
+       .rst       (por)
+    );
+    assign dbg_en_s    = ~dbg_en_n_s;
+    wire   dbg_rst_nxt =  dbg_en_n_s;
+`else
+    assign dbg_en_s    =  dbg_en;
+    wire   dbg_rst_nxt = ~dbg_en;
+`endif
+`else
+    assign dbg_en_s    =  1'b0;
+    wire   dbg_rst_nxt =  1'b0;
+`endif
+
+
+// Serial Debug Interface Clock gate
+//------------------------------------------------
+`ifdef DBG_EN
+  `ifdef ASIC
+  omsp_clock_gate clock_gate_dbg_clk (
+      .gclk        (dbg_clk),
+      .clk         (mclk),
+      .enable      (dbg_en_s),
+      .scan_enable (scan_enable)
+  );
+  `else
+     assign dbg_clk = dco_clk;
+  `endif
+`else
+     assign dbg_clk = 1'b0;
+`endif
+
+
+//=============================================================================
+// 7)  RESET GENERATION
+//=============================================================================
+//
+// Whenever the reset pin (reset_n) is deasserted, the internal resets of the
+// openMSP430 will be released in the following order:
+//                1- POR
+//                2- DBG_RST (if the sdi interface is enabled, i.e. dbg_en=1)
+//                3- PUC
+//
+// Note: releasing the DBG_RST before PUC is particularly important in order
+//       to allow the sdi interface to halt the cpu immediately after a PUC.
+//
+   
+// Generate synchronized POR to MCLK domain
+//------------------------------------------
+
+// Asynchronous reset source
+assign    por_a         =  !reset_n;
+wire      por_noscan;
+
+// Reset Synchronizer
+omsp_sync_reset sync_reset_por (
+    .rst_s        (por_noscan),
+    .clk          (nodiv_mclk),
+    .rst_a        (por_a)
+);
+
+// Scan Reset Mux
+`ifdef ASIC
+omsp_scan_mux scan_mux_por (
+    .scan_mode    (scan_mode),
+    .data_in_scan (por_a),
+    .data_in_func (por_noscan),
+    .data_out     (por)
+);
+`else
+ assign por = por_noscan;
+`endif
+
+// Generate synchronized reset for the SDI
+//------------------------------------------
+`ifdef DBG_EN
+
+// Reset Generation
+reg  dbg_rst_noscan;
+always @ (posedge mclk or posedge por)
+  if (por)  dbg_rst_noscan <=  1'b1;
+  else      dbg_rst_noscan <=  dbg_rst_nxt;
+
+  // Scan Reset Mux
+  `ifdef ASIC
+  omsp_scan_mux scan_mux_dbg_rst (
+      .scan_mode    (scan_mode),
+      .data_in_scan (por_a),
+      .data_in_func (dbg_rst_noscan),
+      .data_out     (dbg_rst)
+  );
+  `else
+   assign dbg_rst = dbg_rst_noscan;
+  `endif
+
+`else
+   wire   dbg_rst_noscan = 1'b1;
+   assign dbg_rst        = 1'b1;
+`endif
+
+
+// Generate main system reset (PUC_RST)
+//--------------------------------------
+wire puc_noscan_n;
+wire puc_a_scan;
+
+// Asynchronous PUC reset
+wire puc_a = por | wdt_reset;
+
+// Synchronous PUC reset
+wire puc_s = dbg_cpu_reset |                              // With the debug interface command
+
+            (dbg_en_s & dbg_rst_noscan & ~puc_noscan_n);  // Sequencing making sure PUC is released
+                                                          // after DBG_RST if the debug interface is
+                                                          // enabled at power-on-reset time
+// Scan Reset Mux
+`ifdef ASIC
+omsp_scan_mux scan_mux_puc_rst_a (
+    .scan_mode    (scan_mode),
+    .data_in_scan (por_a),
+    .data_in_func (puc_a),
+    .data_out     (puc_a_scan)
+);
+`else
+  assign puc_a_scan = puc_a;
+`endif
+
+// Reset Synchronizer
+// (required because of the asynchronous watchdog reset)
+omsp_sync_cell sync_cell_puc (
+    .data_out  (puc_noscan_n),
+    .data_in   (~puc_s),
+    .clk       (mclk),
+    .rst       (puc_a_scan)
+);
+
+// Scan Reset Mux
+`ifdef ASIC
+omsp_scan_mux scan_mux_puc_rst (
+    .scan_mode    (scan_mode),
+    .data_in_scan (por_a),
+    .data_in_func (~puc_noscan_n),
+    .data_out     (puc_rst)
+);
+`else
+  assign puc_rst = ~puc_noscan_n;
+`endif
+
+// PUC pending set the serial debug interface
+assign puc_pnd_set = ~puc_noscan_n;
+
+
+endmodule // omsp_clock_module
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
diff --git a/tests/openmsp430/rtl/omsp_clock_mux.v b/tests/openmsp430/rtl/omsp_clock_mux.v
new file mode 100644 (file)
index 0000000..5f8406a
--- /dev/null
@@ -0,0 +1,192 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_clock_mux.v
+// 
+// *Module Description:
+//                       Standard clock mux for the openMSP430
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 103 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $
+//----------------------------------------------------------------------------
+
+module  omsp_clock_mux (
+
+// OUTPUTs
+    clk_out,                   // Clock output
+
+// INPUTs
+    clk_in0,                   // Clock input 0
+    clk_in1,                   // Clock input 1
+    reset,                     // Reset
+    scan_mode,                 // Scan mode (clk_in0 is selected in scan mode)
+    select                     // Clock selection
+);
+
+// OUTPUTs
+//=========
+output         clk_out;        // Clock output
+
+// INPUTs
+//=========
+input          clk_in0;        // Clock input 0
+input          clk_in1;        // Clock input 1
+input          reset;          // Reset
+input          scan_mode;      // Scan mode (clk_in0 is selected in scan mode)
+input          select;         // Clock selection
+
+
+//===========================================================================================================================//
+// 1)  CLOCK MUX                                                                                                             //
+//===========================================================================================================================//
+//                                                                                                                           //
+//    The following (glitch free) clock mux is implemented as following:                                                     //
+//                                                                                                                           //
+//                                                                                                                           //
+//                                                                                                                           //
+//                                                                                                                           //
+//                                   +-----.     +--------+   +--------+                                                     //
+//       select >>----+-------------O|      \    |        |   |        |          +-----.                                    //
+//                    |              |       |---| D    Q |---| D    Q |--+-------|      \                                   //
+//                    |     +-------O|      /    |        |   |        |  |       |       |O-+                               //
+//                    |     |        +-----'     |        |   |        |  |   +--O|      /   |                               //
+//                    |     |                    |   /\   |   |   /\   |  |   |   +-----'    |                               //
+//                    |     |                    +--+--+--+   +--+--+--+  |   |              |                               //
+//                    |     |                        O            |       |   |              |                               //
+//                    |     |                        |            |       |   |              |  +-----.                      //
+//       clk_in0 >>----------------------------------+------------+-----------+              +--|      \                     //
+//                    |     |                                             |                     |       |----<< clk_out      //
+//                    |     |     +---------------------------------------+                  +--|      /                     //
+//                    |     |     |                                                          |  +-----'                      //
+//                    |     +---------------------------------------------+                  |                               //
+//                    |           |                                       |                  |                               //
+//                    |           |  +-----.     +--------+   +--------+  |                  |                               //
+//                    |           +-O|      \    |        |   |        |  |       +-----.    |                               //
+//                    |              |       |---| D    Q |---| D    Q |--+-------|      \   |                               //
+//                    +--------------|      /    |        |   |        |          |       |O-+                               //
+//                                   +-----'     |        |   |        |      +--O|      /                                   //
+//                                               |   /\   |   |   /\   |      |   +-----'                                    //
+//                                               +--+--+--+   +--+--+--+      |                                              //
+//                                                   O            |           |                                              //
+//                                                   |            |           |                                              //
+//       clk_in1 >>----------------------------------+------------+-----------+                                              //
+//                                                                                                                           //
+//                                                                                                                           //
+//===========================================================================================================================//
+
+//-----------------------------------------------------------------------------
+// Wire declarations
+//-----------------------------------------------------------------------------
+   
+wire in0_select;
+reg  in0_select_s;
+reg  in0_select_ss;
+wire in0_enable;
+
+wire in1_select;
+reg  in1_select_s;
+reg  in1_select_ss;
+wire in1_enable;
+
+wire clk_in0_inv;
+wire clk_in1_inv;
+wire gated_clk_in0;
+wire gated_clk_in1;
+
+
+//-----------------------------------------------------------------------------
+// CLK_IN0 Selection
+//-----------------------------------------------------------------------------
+   
+assign in0_select = ~select & ~in1_select_ss;
+   
+always @ (posedge clk_in0_inv or posedge reset)
+  if (reset) in0_select_s  <=  1'b1;
+  else       in0_select_s  <=  in0_select;
+
+always @ (posedge clk_in0     or posedge reset)
+  if (reset) in0_select_ss <=  1'b1;
+  else       in0_select_ss <=  in0_select_s;
+
+assign in0_enable = in0_select_ss | scan_mode;
+
+
+//-----------------------------------------------------------------------------
+// CLK_IN1 Selection
+//-----------------------------------------------------------------------------
+   
+assign in1_select =  select & ~in0_select_ss;
+   
+always @ (posedge clk_in1_inv or posedge reset)
+  if (reset) in1_select_s  <=  1'b0;
+  else       in1_select_s  <=  in1_select;
+
+always @ (posedge clk_in1     or posedge reset)
+  if (reset) in1_select_ss <=  1'b0;
+  else       in1_select_ss <=  in1_select_s;
+
+assign in1_enable = in1_select_ss & ~scan_mode;
+
+   
+//-----------------------------------------------------------------------------
+// Clock MUX
+//-----------------------------------------------------------------------------
+//
+// IMPORTANT NOTE:
+//                  Because the clock network is a critical part of the design,
+//                 the following combinatorial logic should be replaced with
+//                 direct instanciation of standard cells from target library.
+//                  Don't forget the "dont_touch" attribute to make sure
+//                 synthesis won't mess it up.
+//
+
+// Replace with standard cell INVERTER
+assign clk_in0_inv   = ~clk_in0;
+assign clk_in1_inv   = ~clk_in1;
+
+
+// Replace with standard cell NAND2
+assign gated_clk_in0 = ~(clk_in0_inv & in0_enable);
+assign gated_clk_in1 = ~(clk_in1_inv & in1_enable);
+   
+
+// Replace with standard cell AND2
+assign clk_out       =  (gated_clk_in0 & gated_clk_in1);
+
+
+
+endmodule // omsp_clock_gate
+
+
+
diff --git a/tests/openmsp430/rtl/omsp_dbg.v b/tests/openmsp430/rtl/omsp_dbg.v
new file mode 100644 (file)
index 0000000..97e9ede
--- /dev/null
@@ -0,0 +1,827 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_dbg.v
+// 
+// *Module Description:
+//                       Debug interface
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 149 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2012-07-19 22:21:12 +0200 (Thu, 19 Jul 2012) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module  omsp_dbg (
+
+// OUTPUTs
+    dbg_freeze,                     // Freeze peripherals
+    dbg_halt_cmd,                   // Halt CPU command
+    dbg_mem_addr,                   // Debug address for rd/wr access
+    dbg_mem_dout,                   // Debug unit data output
+    dbg_mem_en,                     // Debug unit memory enable
+    dbg_mem_wr,                     // Debug unit memory write
+    dbg_reg_wr,                     // Debug unit CPU register write
+    dbg_cpu_reset,                  // Reset CPU from debug interface
+    dbg_uart_txd,                   // Debug interface: UART TXD
+                            
+// INPUTs
+    cpu_en_s,                       // Enable CPU code execution (synchronous)
+    cpu_id,                         // CPU ID
+    dbg_clk,                        // Debug unit clock
+    dbg_en_s,                       // Debug interface enable (synchronous)
+    dbg_halt_st,                    // Halt/Run status from CPU
+    dbg_mem_din,                    // Debug unit Memory data input
+    dbg_reg_din,                    // Debug unit CPU register data input
+    dbg_rst,                        // Debug unit reset
+    dbg_uart_rxd,                   // Debug interface: UART RXD (asynchronous)
+    decode_noirq,                   // Frontend decode instruction
+    eu_mab,                         // Execution-Unit Memory address bus
+    eu_mb_en,                       // Execution-Unit Memory bus enable
+    eu_mb_wr,                       // Execution-Unit Memory bus write transfer
+    eu_mdb_in,                      // Memory data bus input
+    eu_mdb_out,                     // Memory data bus output
+    exec_done,                      // Execution completed
+    fe_mb_en,                       // Frontend Memory bus enable
+    fe_mdb_in,                      // Frontend Memory data bus input
+    pc,                             // Program counter
+    puc_pnd_set                     // PUC pending set for the serial debug interface
+);
+
+// OUTPUTs
+//=========
+output              dbg_freeze;     // Freeze peripherals
+output              dbg_halt_cmd;   // Halt CPU command
+output       [15:0] dbg_mem_addr;   // Debug address for rd/wr access
+output       [15:0] dbg_mem_dout;   // Debug unit data output
+output              dbg_mem_en;     // Debug unit memory enable
+output        [1:0] dbg_mem_wr;     // Debug unit memory write
+output              dbg_reg_wr;     // Debug unit CPU register write
+output              dbg_cpu_reset;  // Reset CPU from debug interface
+output              dbg_uart_txd;   // Debug interface: UART TXD
+
+// INPUTs
+//=========
+input               cpu_en_s;       // Enable CPU code execution (synchronous)
+input        [31:0] cpu_id;         // CPU ID
+input               dbg_clk;        // Debug unit clock
+input               dbg_en_s;       // Debug interface enable (synchronous)
+input               dbg_halt_st;    // Halt/Run status from CPU
+input        [15:0] dbg_mem_din;    // Debug unit Memory data input
+input        [15:0] dbg_reg_din;    // Debug unit CPU register data input
+input               dbg_rst;        // Debug unit reset
+input               dbg_uart_rxd;   // Debug interface: UART RXD (asynchronous)
+input               decode_noirq;   // Frontend decode instruction
+input        [15:0] eu_mab;         // Execution-Unit Memory address bus
+input               eu_mb_en;       // Execution-Unit Memory bus enable
+input         [1:0] eu_mb_wr;       // Execution-Unit Memory bus write transfer
+input        [15:0] eu_mdb_in;      // Memory data bus input
+input        [15:0] eu_mdb_out;     // Memory data bus output
+input               exec_done;      // Execution completed
+input               fe_mb_en;       // Frontend Memory bus enable
+input        [15:0] fe_mdb_in;      // Frontend Memory data bus input
+input        [15:0] pc;             // Program counter
+input               puc_pnd_set;    // PUC pending set for the serial debug interface
+
+
+//=============================================================================
+// 1)  WIRE & PARAMETER DECLARATION
+//=============================================================================
+
+// Diverse wires and registers
+wire  [5:0] dbg_addr;
+wire [15:0] dbg_din;
+wire        dbg_wr;
+reg        mem_burst;
+wire        dbg_reg_rd;
+wire        dbg_mem_rd;
+reg         dbg_mem_rd_dly;
+wire        dbg_swbrk;
+wire        dbg_rd;
+reg         dbg_rd_rdy;
+wire        mem_burst_rd;
+wire        mem_burst_wr;
+wire        brk0_halt;
+wire        brk0_pnd;
+wire [15:0] brk0_dout;
+wire        brk1_halt;
+wire        brk1_pnd;
+wire [15:0] brk1_dout;
+wire        brk2_halt;
+wire        brk2_pnd;
+wire [15:0] brk2_dout;
+wire        brk3_halt;
+wire        brk3_pnd;
+wire [15:0] brk3_dout;
+    
+// Number of registers
+parameter           NR_REG       = 24;
+
+// Register addresses
+parameter           CPU_ID_LO    = 6'h00;
+parameter           CPU_ID_HI    = 6'h01;
+parameter           CPU_CTL      = 6'h02;
+parameter           CPU_STAT     = 6'h03;
+parameter           MEM_CTL      = 6'h04;
+parameter           MEM_ADDR     = 6'h05;
+parameter           MEM_DATA     = 6'h06;
+parameter           MEM_CNT      = 6'h07;
+`ifdef DBG_HWBRK_0
+parameter           BRK0_CTL     = 6'h08;
+parameter           BRK0_STAT    = 6'h09;
+parameter           BRK0_ADDR0   = 6'h0A;
+parameter           BRK0_ADDR1   = 6'h0B;
+`endif
+`ifdef DBG_HWBRK_1
+parameter           BRK1_CTL     = 6'h0C;
+parameter           BRK1_STAT    = 6'h0D;
+parameter           BRK1_ADDR0   = 6'h0E;
+parameter           BRK1_ADDR1   = 6'h0F;
+`endif
+`ifdef DBG_HWBRK_2
+parameter           BRK2_CTL     = 6'h10;
+parameter           BRK2_STAT    = 6'h11;
+parameter           BRK2_ADDR0   = 6'h12;
+parameter           BRK2_ADDR1   = 6'h13;
+`endif
+`ifdef DBG_HWBRK_3
+parameter           BRK3_CTL     = 6'h14;
+parameter           BRK3_STAT    = 6'h15;
+parameter           BRK3_ADDR0   = 6'h16;
+parameter           BRK3_ADDR1   = 6'h17;
+`endif
+
+// Register one-hot decoder
+parameter           BASE_D       = {{NR_REG-1{1'b0}}, 1'b1};
+parameter           CPU_ID_LO_D  = (BASE_D << CPU_ID_LO);
+parameter           CPU_ID_HI_D  = (BASE_D << CPU_ID_HI);
+parameter           CPU_CTL_D    = (BASE_D << CPU_CTL);
+parameter           CPU_STAT_D   = (BASE_D << CPU_STAT);
+parameter           MEM_CTL_D    = (BASE_D << MEM_CTL);
+parameter           MEM_ADDR_D   = (BASE_D << MEM_ADDR);
+parameter           MEM_DATA_D   = (BASE_D << MEM_DATA);
+parameter           MEM_CNT_D    = (BASE_D << MEM_CNT);
+`ifdef DBG_HWBRK_0
+parameter           BRK0_CTL_D   = (BASE_D << BRK0_CTL);
+parameter           BRK0_STAT_D  = (BASE_D << BRK0_STAT);
+parameter           BRK0_ADDR0_D = (BASE_D << BRK0_ADDR0);
+parameter           BRK0_ADDR1_D = (BASE_D << BRK0_ADDR1);
+`endif
+`ifdef DBG_HWBRK_1
+parameter           BRK1_CTL_D   = (BASE_D << BRK1_CTL);
+parameter           BRK1_STAT_D  = (BASE_D << BRK1_STAT);
+parameter           BRK1_ADDR0_D = (BASE_D << BRK1_ADDR0);
+parameter           BRK1_ADDR1_D = (BASE_D << BRK1_ADDR1);
+`endif
+`ifdef DBG_HWBRK_2
+parameter           BRK2_CTL_D   = (BASE_D << BRK2_CTL);
+parameter           BRK2_STAT_D  = (BASE_D << BRK2_STAT);
+parameter           BRK2_ADDR0_D = (BASE_D << BRK2_ADDR0);
+parameter           BRK2_ADDR1_D = (BASE_D << BRK2_ADDR1);
+`endif
+`ifdef DBG_HWBRK_3
+parameter           BRK3_CTL_D   = (BASE_D << BRK3_CTL);
+parameter           BRK3_STAT_D  = (BASE_D << BRK3_STAT);
+parameter           BRK3_ADDR0_D = (BASE_D << BRK3_ADDR0);
+parameter           BRK3_ADDR1_D = (BASE_D << BRK3_ADDR1);
+`endif
+
+
+//============================================================================
+// 2)  REGISTER DECODER
+//============================================================================
+
+// Select Data register during a burst
+wire  [5:0] dbg_addr_in = mem_burst ? MEM_DATA : dbg_addr;
+
+// Register address decode
+reg  [NR_REG-1:0]  reg_dec; 
+always @(dbg_addr_in)
+  case (dbg_addr_in)
+    CPU_ID_LO :  reg_dec  =  CPU_ID_LO_D;
+    CPU_ID_HI :  reg_dec  =  CPU_ID_HI_D;
+    CPU_CTL   :  reg_dec  =  CPU_CTL_D;
+    CPU_STAT  :  reg_dec  =  CPU_STAT_D;
+    MEM_CTL   :  reg_dec  =  MEM_CTL_D;
+    MEM_ADDR  :  reg_dec  =  MEM_ADDR_D;
+    MEM_DATA  :  reg_dec  =  MEM_DATA_D;
+    MEM_CNT   :  reg_dec  =  MEM_CNT_D;
+`ifdef DBG_HWBRK_0
+    BRK0_CTL  :  reg_dec  =  BRK0_CTL_D;
+    BRK0_STAT :  reg_dec  =  BRK0_STAT_D;
+    BRK0_ADDR0:  reg_dec  =  BRK0_ADDR0_D;
+    BRK0_ADDR1:  reg_dec  =  BRK0_ADDR1_D;
+`endif
+`ifdef DBG_HWBRK_1
+    BRK1_CTL  :  reg_dec  =  BRK1_CTL_D;
+    BRK1_STAT :  reg_dec  =  BRK1_STAT_D;
+    BRK1_ADDR0:  reg_dec  =  BRK1_ADDR0_D;
+    BRK1_ADDR1:  reg_dec  =  BRK1_ADDR1_D;
+`endif
+`ifdef DBG_HWBRK_2
+    BRK2_CTL  :  reg_dec  =  BRK2_CTL_D;
+    BRK2_STAT :  reg_dec  =  BRK2_STAT_D;
+    BRK2_ADDR0:  reg_dec  =  BRK2_ADDR0_D;
+    BRK2_ADDR1:  reg_dec  =  BRK2_ADDR1_D;
+`endif
+`ifdef DBG_HWBRK_3
+    BRK3_CTL  :  reg_dec  =  BRK3_CTL_D;
+    BRK3_STAT :  reg_dec  =  BRK3_STAT_D;
+    BRK3_ADDR0:  reg_dec  =  BRK3_ADDR0_D;
+    BRK3_ADDR1:  reg_dec  =  BRK3_ADDR1_D;
+`endif
+  // pragma coverage off
+    default:     reg_dec  =  {NR_REG{1'b0}};
+  // pragma coverage on
+  endcase
+
+// Read/Write probes
+wire               reg_write =  dbg_wr;
+wire               reg_read  =  1'b1;
+
+// Read/Write vectors
+wire  [NR_REG-1:0] reg_wr    = reg_dec & {NR_REG{reg_write}};
+wire  [NR_REG-1:0] reg_rd    = reg_dec & {NR_REG{reg_read}};
+
+
+//=============================================================================
+// 3)  REGISTER: CORE INTERFACE
+//=============================================================================
+
+// CPU_ID Register
+//-----------------   
+//              -------------------------------------------------------------------
+// CPU_ID_LO:  | 15  14  13  12  11  10  9  |  8  7  6  5  4  |  3   |   2  1  0   |
+//             |----------------------------+-----------------+------+-------------|
+//             |        PER_SPACE           |   USER_VERSION  | ASIC | CPU_VERSION |
+//              --------------------------------------------------------------------
+// CPU_ID_HI:  |   15  14  13  12  11  10   |   9  8  7  6  5  4  3  2  1   |   0  |
+//             |----------------------------+-------------------------------+------|
+//             |         PMEM_SIZE          |            DMEM_SIZE          |  MPY |
+//              -------------------------------------------------------------------
+
+// This register is assigned in the SFR module
+
+
+// CPU_CTL Register
+//-----------------------------------------------------------------------------
+//       7         6          5          4           3        2     1    0
+//   Reserved   CPU_RST  RST_BRK_EN  FRZ_BRK_EN  SW_BRK_EN  ISTEP  RUN  HALT
+//-----------------------------------------------------------------------------
+reg   [6:3] cpu_ctl;
+
+wire        cpu_ctl_wr = reg_wr[CPU_CTL];
+   
+always @ (posedge dbg_clk or posedge dbg_rst)
+`ifdef DBG_RST_BRK_EN
+  if (dbg_rst)         cpu_ctl <=  4'h6;
+`else
+  if (dbg_rst)         cpu_ctl <=  4'h2;
+`endif
+  else if (cpu_ctl_wr) cpu_ctl <=  dbg_din[6:3];
+
+wire  [7:0] cpu_ctl_full = {1'b0, cpu_ctl, 3'b000};
+
+wire        halt_cpu = cpu_ctl_wr & dbg_din[`HALT]  & ~dbg_halt_st;
+wire        run_cpu  = cpu_ctl_wr & dbg_din[`RUN]   &  dbg_halt_st;
+wire        istep    = cpu_ctl_wr & dbg_din[`ISTEP] &  dbg_halt_st;
+
+   
+// CPU_STAT Register
+//------------------------------------------------------------------------------------
+//      7           6          5           4           3         2      1       0
+// HWBRK3_PND  HWBRK2_PND  HWBRK1_PND  HWBRK0_PND  SWBRK_PND  PUC_PND  Res.  HALT_RUN
+//------------------------------------------------------------------------------------
+reg   [3:2] cpu_stat;
+
+wire        cpu_stat_wr  = reg_wr[CPU_STAT];
+wire  [3:2] cpu_stat_set = {dbg_swbrk, puc_pnd_set};
+wire  [3:2] cpu_stat_clr = ~dbg_din[3:2];
+
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)          cpu_stat <=  2'b00;
+  else if (cpu_stat_wr) cpu_stat <= ((cpu_stat & cpu_stat_clr) | cpu_stat_set);
+  else                  cpu_stat <=  (cpu_stat                 | cpu_stat_set);
+
+wire  [7:0] cpu_stat_full = {brk3_pnd, brk2_pnd, brk1_pnd, brk0_pnd,
+                             cpu_stat, 1'b0, dbg_halt_st};
+
+   
+//=============================================================================
+// 4)  REGISTER: MEMORY INTERFACE
+//=============================================================================
+
+// MEM_CTL Register
+//-----------------------------------------------------------------------------
+//       7     6     5     4          3        2         1       0
+//            Reserved               B/W    MEM/REG    RD/WR   START
+//
+// START  :  -  0 : Do nothing.
+//           -  1 : Initiate memory transfer.
+//
+// RD/WR  :  -  0 : Read access.
+//           -  1 : Write access.
+//
+// MEM/REG:  -  0 : Memory access.
+//           -  1 : CPU Register access.
+//
+// B/W    :  -  0 : 16 bit access.
+//           -  1 :  8 bit access (not valid for CPU Registers).
+//
+//-----------------------------------------------------------------------------
+reg   [3:1] mem_ctl;
+
+wire        mem_ctl_wr = reg_wr[MEM_CTL];
+   
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)         mem_ctl <=  3'h0;
+  else if (mem_ctl_wr) mem_ctl <=  dbg_din[3:1];
+
+wire  [7:0] mem_ctl_full  = {4'b0000, mem_ctl, 1'b0};
+
+reg         mem_start;
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)  mem_start <=  1'b0;
+  else          mem_start <=  mem_ctl_wr & dbg_din[0];
+
+wire        mem_bw    = mem_ctl[3];
+   
+// MEM_DATA Register
+//------------------   
+reg  [15:0] mem_data;
+reg  [15:0] mem_addr;
+wire        mem_access;
+   
+wire        mem_data_wr = reg_wr[MEM_DATA];
+
+wire [15:0] dbg_mem_din_bw = ~mem_bw      ? dbg_mem_din                :
+                             mem_addr[0] ? {8'h00, dbg_mem_din[15:8]} :
+                                           {8'h00, dbg_mem_din[7:0]};
+   
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)             mem_data <=  16'h0000;
+  else if (mem_data_wr)    mem_data <=  dbg_din;
+  else if (dbg_reg_rd)     mem_data <=  dbg_reg_din;
+  else if (dbg_mem_rd_dly) mem_data <=  dbg_mem_din_bw;
+
+   
+// MEM_ADDR Register
+//------------------   
+reg  [15:0] mem_cnt;
+
+wire        mem_addr_wr  = reg_wr[MEM_ADDR];
+wire        dbg_mem_acc  = (|dbg_mem_wr | (dbg_rd_rdy & ~mem_ctl[2]));
+wire        dbg_reg_acc  = ( dbg_reg_wr | (dbg_rd_rdy &  mem_ctl[2]));
+   
+wire [15:0] mem_addr_inc = (mem_cnt==16'h0000)         ? 16'h0000 :
+                           (dbg_mem_acc & ~mem_bw)     ? 16'h0002 :
+                           (dbg_mem_acc | dbg_reg_acc) ? 16'h0001 : 16'h0000;
+   
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)          mem_addr <=  16'h0000;
+  else if (mem_addr_wr) mem_addr <=  dbg_din;
+  else                  mem_addr <=  mem_addr + mem_addr_inc;
+   
+// MEM_CNT Register
+//------------------   
+
+wire        mem_cnt_wr  = reg_wr[MEM_CNT];
+
+wire [15:0] mem_cnt_dec = (mem_cnt==16'h0000)                       ? 16'h0000 :
+                          (mem_burst & (dbg_mem_acc | dbg_reg_acc)) ? 16'hffff : 16'h0000;
+   
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)         mem_cnt <=  16'h0000;
+  else if (mem_cnt_wr) mem_cnt <=  dbg_din;
+  else                 mem_cnt <=  mem_cnt + mem_cnt_dec;
+
+
+//=============================================================================
+// 5)  BREAKPOINTS / WATCHPOINTS
+//=============================================================================
+
+`ifdef DBG_HWBRK_0
+// Hardware Breakpoint/Watchpoint Register read select
+wire [3:0] brk0_reg_rd = {reg_rd[BRK0_ADDR1],
+                          reg_rd[BRK0_ADDR0],
+                          reg_rd[BRK0_STAT],
+                          reg_rd[BRK0_CTL]};
+
+// Hardware Breakpoint/Watchpoint Register write select
+wire [3:0] brk0_reg_wr = {reg_wr[BRK0_ADDR1],
+                          reg_wr[BRK0_ADDR0],
+                          reg_wr[BRK0_STAT],
+                          reg_wr[BRK0_CTL]};
+
+omsp_dbg_hwbrk dbg_hwbr_0 (
+
+// OUTPUTs
+    .brk_halt   (brk0_halt),   // Hardware breakpoint command
+    .brk_pnd    (brk0_pnd),    // Hardware break/watch-point pending
+    .brk_dout   (brk0_dout),   // Hardware break/watch-point register data input
+                            
+// INPUTs
+    .brk_reg_rd (brk0_reg_rd), // Hardware break/watch-point register read select
+    .brk_reg_wr (brk0_reg_wr), // Hardware break/watch-point register write select
+    .dbg_clk    (dbg_clk),     // Debug unit clock
+    .dbg_din    (dbg_din),     // Debug register data input
+    .dbg_rst    (dbg_rst),     // Debug unit reset
+    .eu_mab     (eu_mab),      // Execution-Unit Memory address bus
+    .eu_mb_en   (eu_mb_en),    // Execution-Unit Memory bus enable
+    .eu_mb_wr   (eu_mb_wr),    // Execution-Unit Memory bus write transfer
+    .eu_mdb_in  (eu_mdb_in),   // Memory data bus input
+    .eu_mdb_out (eu_mdb_out),  // Memory data bus output
+    .exec_done  (exec_done),   // Execution completed
+    .fe_mb_en   (fe_mb_en),    // Frontend Memory bus enable
+    .pc         (pc)           // Program counter
+);
+
+`else
+assign brk0_halt =  1'b0;
+assign brk0_pnd  =  1'b0;
+assign brk0_dout = 16'h0000;
+`endif
+
+`ifdef DBG_HWBRK_1
+// Hardware Breakpoint/Watchpoint Register read select
+wire [3:0] brk1_reg_rd = {reg_rd[BRK1_ADDR1],
+                          reg_rd[BRK1_ADDR0],
+                          reg_rd[BRK1_STAT],
+                          reg_rd[BRK1_CTL]};
+
+// Hardware Breakpoint/Watchpoint Register write select
+wire [3:0] brk1_reg_wr = {reg_wr[BRK1_ADDR1],
+                          reg_wr[BRK1_ADDR0],
+                          reg_wr[BRK1_STAT],
+                          reg_wr[BRK1_CTL]};
+
+omsp_dbg_hwbrk dbg_hwbr_1 (
+
+// OUTPUTs
+    .brk_halt   (brk1_halt),   // Hardware breakpoint command
+    .brk_pnd    (brk1_pnd),    // Hardware break/watch-point pending
+    .brk_dout   (brk1_dout),   // Hardware break/watch-point register data input
+                            
+// INPUTs
+    .brk_reg_rd (brk1_reg_rd), // Hardware break/watch-point register read select
+    .brk_reg_wr (brk1_reg_wr), // Hardware break/watch-point register write select
+    .dbg_clk    (dbg_clk),     // Debug unit clock
+    .dbg_din    (dbg_din),     // Debug register data input
+    .dbg_rst    (dbg_rst),     // Debug unit reset
+    .eu_mab     (eu_mab),      // Execution-Unit Memory address bus
+    .eu_mb_en   (eu_mb_en),    // Execution-Unit Memory bus enable
+    .eu_mb_wr   (eu_mb_wr),    // Execution-Unit Memory bus write transfer
+    .eu_mdb_in  (eu_mdb_in),   // Memory data bus input
+    .eu_mdb_out (eu_mdb_out),  // Memory data bus output
+    .exec_done  (exec_done),   // Execution completed
+    .fe_mb_en   (fe_mb_en),    // Frontend Memory bus enable
+    .pc         (pc)           // Program counter
+);
+
+`else
+assign brk1_halt =  1'b0;
+assign brk1_pnd  =  1'b0;
+assign brk1_dout = 16'h0000;
+`endif
+
+ `ifdef DBG_HWBRK_2
+// Hardware Breakpoint/Watchpoint Register read select
+wire [3:0] brk2_reg_rd = {reg_rd[BRK2_ADDR1],
+                          reg_rd[BRK2_ADDR0],
+                          reg_rd[BRK2_STAT],
+                          reg_rd[BRK2_CTL]};
+
+// Hardware Breakpoint/Watchpoint Register write select
+wire [3:0] brk2_reg_wr = {reg_wr[BRK2_ADDR1],
+                          reg_wr[BRK2_ADDR0],
+                          reg_wr[BRK2_STAT],
+                          reg_wr[BRK2_CTL]};
+
+omsp_dbg_hwbrk dbg_hwbr_2 (
+
+// OUTPUTs
+    .brk_halt   (brk2_halt),   // Hardware breakpoint command
+    .brk_pnd    (brk2_pnd),    // Hardware break/watch-point pending
+    .brk_dout   (brk2_dout),   // Hardware break/watch-point register data input
+                            
+// INPUTs
+    .brk_reg_rd (brk2_reg_rd), // Hardware break/watch-point register read select
+    .brk_reg_wr (brk2_reg_wr), // Hardware break/watch-point register write select
+    .dbg_clk    (dbg_clk),     // Debug unit clock
+    .dbg_din    (dbg_din),     // Debug register data input
+    .dbg_rst    (dbg_rst),     // Debug unit reset
+    .eu_mab     (eu_mab),      // Execution-Unit Memory address bus
+    .eu_mb_en   (eu_mb_en),    // Execution-Unit Memory bus enable
+    .eu_mb_wr   (eu_mb_wr),    // Execution-Unit Memory bus write transfer
+    .eu_mdb_in  (eu_mdb_in),   // Memory data bus input
+    .eu_mdb_out (eu_mdb_out),  // Memory data bus output
+    .exec_done  (exec_done),   // Execution completed
+    .fe_mb_en   (fe_mb_en),    // Frontend Memory bus enable
+    .pc         (pc)           // Program counter
+);
+
+`else
+assign brk2_halt =  1'b0;
+assign brk2_pnd  =  1'b0;
+assign brk2_dout = 16'h0000;
+`endif
+
+`ifdef DBG_HWBRK_3
+// Hardware Breakpoint/Watchpoint Register read select
+wire [3:0] brk3_reg_rd = {reg_rd[BRK3_ADDR1],
+                          reg_rd[BRK3_ADDR0],
+                          reg_rd[BRK3_STAT],
+                          reg_rd[BRK3_CTL]};
+
+// Hardware Breakpoint/Watchpoint Register write select
+wire [3:0] brk3_reg_wr = {reg_wr[BRK3_ADDR1],
+                          reg_wr[BRK3_ADDR0],
+                          reg_wr[BRK3_STAT],
+                          reg_wr[BRK3_CTL]};
+
+omsp_dbg_hwbrk dbg_hwbr_3 (
+
+// OUTPUTs
+    .brk_halt   (brk3_halt),   // Hardware breakpoint command
+    .brk_pnd    (brk3_pnd),    // Hardware break/watch-point pending
+    .brk_dout   (brk3_dout),   // Hardware break/watch-point register data input
+                            
+// INPUTs
+    .brk_reg_rd (brk3_reg_rd), // Hardware break/watch-point register read select
+    .brk_reg_wr (brk3_reg_wr), // Hardware break/watch-point register write select
+    .dbg_clk    (dbg_clk),     // Debug unit clock
+    .dbg_din    (dbg_din),     // Debug register data input
+    .dbg_rst    (dbg_rst),     // Debug unit reset
+    .eu_mab     (eu_mab),      // Execution-Unit Memory address bus
+    .eu_mb_en   (eu_mb_en),    // Execution-Unit Memory bus enable
+    .eu_mb_wr   (eu_mb_wr),    // Execution-Unit Memory bus write transfer
+    .eu_mdb_in  (eu_mdb_in),   // Memory data bus input
+    .eu_mdb_out (eu_mdb_out),  // Memory data bus output
+    .exec_done  (exec_done),   // Execution completed
+    .fe_mb_en   (fe_mb_en),    // Frontend Memory bus enable
+    .pc         (pc)           // Program counter
+);
+
+`else
+assign brk3_halt =  1'b0;
+assign brk3_pnd  =  1'b0;
+assign brk3_dout = 16'h0000;
+`endif
+
+
+//============================================================================
+// 6) DATA OUTPUT GENERATION
+//============================================================================
+
+wire [15:0] cpu_id_lo_rd = cpu_id[15:0]           & {16{reg_rd[CPU_ID_LO]}};
+wire [15:0] cpu_id_hi_rd = cpu_id[31:16]          & {16{reg_rd[CPU_ID_HI]}};
+wire [15:0] cpu_ctl_rd   = {8'h00, cpu_ctl_full}  & {16{reg_rd[CPU_CTL]}};
+wire [15:0] cpu_stat_rd  = {8'h00, cpu_stat_full} & {16{reg_rd[CPU_STAT]}};
+wire [15:0] mem_ctl_rd   = {8'h00, mem_ctl_full}  & {16{reg_rd[MEM_CTL]}};
+wire [15:0] mem_data_rd  = mem_data               & {16{reg_rd[MEM_DATA]}};
+wire [15:0] mem_addr_rd  = mem_addr               & {16{reg_rd[MEM_ADDR]}};
+wire [15:0] mem_cnt_rd   = mem_cnt                & {16{reg_rd[MEM_CNT]}};
+
+wire [15:0] dbg_dout = cpu_id_lo_rd |
+                       cpu_id_hi_rd |
+                       cpu_ctl_rd   |
+                       cpu_stat_rd  |
+                       mem_ctl_rd   |
+                       mem_data_rd  |
+                       mem_addr_rd  |
+                       mem_cnt_rd   |
+                       brk0_dout    |
+                       brk1_dout    |
+                       brk2_dout    |
+                       brk3_dout;
+
+// Tell UART/JTAG interface that the data is ready to be read
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)                       dbg_rd_rdy  <=  1'b0;
+  else if (mem_burst | mem_burst_rd) dbg_rd_rdy  <= (dbg_reg_rd | dbg_mem_rd_dly);
+  else                               dbg_rd_rdy  <=  dbg_rd;
+
+
+//============================================================================
+// 7) CPU CONTROL
+//============================================================================
+
+// Reset CPU
+//--------------------------
+wire dbg_cpu_reset  = cpu_ctl[`CPU_RST];
+
+   
+// Break after reset
+//--------------------------
+wire halt_rst = cpu_ctl[`RST_BRK_EN] & dbg_en_s & puc_pnd_set;
+
+   
+// Freeze peripherals
+//--------------------------
+wire dbg_freeze = dbg_halt_st & (cpu_ctl[`FRZ_BRK_EN] | ~cpu_en_s);
+
+
+// Software break
+//--------------------------
+assign dbg_swbrk = (fe_mdb_in==`DBG_SWBRK_OP) & decode_noirq & cpu_ctl[`SW_BRK_EN];
+
+
+// Single step
+//--------------------------
+reg [1:0] inc_step;
+always @(posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)    inc_step <= 2'b00;
+  else if (istep) inc_step <= 2'b11;
+  else            inc_step <= {inc_step[0], 1'b0};
+
+   
+// Run / Halt
+//--------------------------
+reg   halt_flag;
+
+wire  mem_halt_cpu;
+wire  mem_run_cpu;
+
+wire  halt_flag_clr = run_cpu   | mem_run_cpu;
+wire  halt_flag_set = halt_cpu  | halt_rst  | dbg_swbrk | mem_halt_cpu |
+                      brk0_halt | brk1_halt | brk2_halt | brk3_halt;
+
+always @(posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)            halt_flag <= 1'b0;
+  else if (halt_flag_clr) halt_flag <= 1'b0;
+  else if (halt_flag_set) halt_flag <= 1'b1;
+
+wire dbg_halt_cmd = (halt_flag | halt_flag_set) & ~inc_step[1];
+
+     
+//============================================================================
+// 8) MEMORY CONTROL
+//============================================================================
+
+// Control Memory bursts
+//------------------------------
+
+wire mem_burst_start = (mem_start             &  |mem_cnt);
+wire mem_burst_end   = ((dbg_wr | dbg_rd_rdy) & ~|mem_cnt);
+
+// Detect when burst is on going
+always @(posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)              mem_burst <= 1'b0;
+  else if (mem_burst_start) mem_burst <= 1'b1;
+  else if (mem_burst_end)   mem_burst <= 1'b0;
+
+// Control signals for UART/JTAG interface
+assign mem_burst_rd = (mem_burst_start & ~mem_ctl[1]);
+assign mem_burst_wr = (mem_burst_start &  mem_ctl[1]);
+
+// Trigger CPU Register or memory access during a burst
+reg        mem_startb;   
+always @(posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst) mem_startb <= 1'b0;
+  else         mem_startb <= (mem_burst & (dbg_wr | dbg_rd)) | mem_burst_rd;
+
+// Combine single and burst memory start of sequence
+wire       mem_seq_start = ((mem_start & ~|mem_cnt) | mem_startb);
+
+   
+// Memory access state machine
+//------------------------------
+reg  [1:0] mem_state;
+reg  [1:0] mem_state_nxt;
+
+// State machine definition
+parameter  M_IDLE       = 2'h0;
+parameter  M_SET_BRK    = 2'h1;
+parameter  M_ACCESS_BRK = 2'h2;
+parameter  M_ACCESS     = 2'h3;
+
+// State transition
+always @(mem_state or mem_seq_start or dbg_halt_st)
+  case (mem_state)
+    M_IDLE       : mem_state_nxt = ~mem_seq_start ? M_IDLE       : 
+                                    dbg_halt_st   ? M_ACCESS     : M_SET_BRK;
+    M_SET_BRK    : mem_state_nxt =  dbg_halt_st   ? M_ACCESS_BRK : M_SET_BRK;
+    M_ACCESS_BRK : mem_state_nxt =  M_IDLE;
+    M_ACCESS     : mem_state_nxt =  M_IDLE;
+  // pragma coverage off
+    default      : mem_state_nxt =  M_IDLE;
+  // pragma coverage on
+  endcase
+
+// State machine
+always @(posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst) mem_state <= M_IDLE;
+  else         mem_state <= mem_state_nxt;
+
+// Utility signals
+assign mem_halt_cpu = (mem_state==M_IDLE)       & (mem_state_nxt==M_SET_BRK);
+assign mem_run_cpu  = (mem_state==M_ACCESS_BRK) & (mem_state_nxt==M_IDLE);
+assign mem_access   = (mem_state==M_ACCESS)     | (mem_state==M_ACCESS_BRK);
+
+
+// Interface to CPU Registers and Memory bacbkone
+//------------------------------------------------
+assign      dbg_mem_addr   =  mem_addr;
+assign      dbg_mem_dout   = ~mem_bw      ? mem_data               :
+                              mem_addr[0] ? {mem_data[7:0], 8'h00} :
+                                            {8'h00, mem_data[7:0]};
+
+assign      dbg_reg_wr     = mem_access &  mem_ctl[1] &  mem_ctl[2];
+assign      dbg_reg_rd     = mem_access & ~mem_ctl[1] &  mem_ctl[2];
+
+assign      dbg_mem_en     = mem_access & ~mem_ctl[2];
+assign      dbg_mem_rd     = dbg_mem_en & ~mem_ctl[1];
+
+wire  [1:0] dbg_mem_wr_msk = ~mem_bw      ? 2'b11 :
+                              mem_addr[0] ? 2'b10 : 2'b01;
+assign      dbg_mem_wr     = {2{dbg_mem_en & mem_ctl[1]}} & dbg_mem_wr_msk;
+
+
+// It takes one additional cycle to read from Memory as from registers
+always @(posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst) dbg_mem_rd_dly <= 1'b0;
+  else         dbg_mem_rd_dly <= dbg_mem_rd;
+
+      
+//=============================================================================
+// 9)  UART COMMUNICATION
+//=============================================================================
+`ifdef DBG_UART
+omsp_dbg_uart dbg_uart_0 (
+
+// OUTPUTs
+    .dbg_addr     (dbg_addr),      // Debug register address
+    .dbg_din      (dbg_din),       // Debug register data input
+    .dbg_rd       (dbg_rd),        // Debug register data read
+    .dbg_uart_txd (dbg_uart_txd),  // Debug interface: UART TXD
+    .dbg_wr       (dbg_wr),        // Debug register data write
+                            
+// INPUTs
+    .dbg_clk      (dbg_clk),       // Debug unit clock
+    .dbg_dout     (dbg_dout),      // Debug register data output
+    .dbg_rd_rdy   (dbg_rd_rdy),    // Debug register data is ready for read
+    .dbg_rst      (dbg_rst),       // Debug unit reset
+    .dbg_uart_rxd (dbg_uart_rxd),  // Debug interface: UART RXD
+    .mem_burst    (mem_burst),     // Burst on going
+    .mem_burst_end(mem_burst_end), // End TX/RX burst
+    .mem_burst_rd (mem_burst_rd),  // Start TX burst
+    .mem_burst_wr (mem_burst_wr),  // Start RX burst
+    .mem_bw       (mem_bw)         // Burst byte width
+);
+
+`else
+assign dbg_addr     =  6'h00;
+assign dbg_din      = 16'h0000;
+assign dbg_rd       =  1'b0;
+assign dbg_uart_txd =  1'b0;
+assign dbg_wr       =  1'b0;
+`endif
+
+   
+//=============================================================================
+// 10)  JTAG COMMUNICATION
+//=============================================================================
+`ifdef DBG_JTAG
+JTAG INTERFACE IS NOT SUPPORTED YET
+`else
+`endif
+
+endmodule // dbg
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
diff --git a/tests/openmsp430/rtl/omsp_dbg_hwbrk.v b/tests/openmsp430/rtl/omsp_dbg_hwbrk.v
new file mode 100644 (file)
index 0000000..6f639ae
--- /dev/null
@@ -0,0 +1,282 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_dbg_hwbrk.v
+// 
+// *Module Description:
+//                       Hardware Breakpoint / Watchpoint module
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 117 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2011-06-23 21:30:51 +0200 (Thu, 23 Jun 2011) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module  omsp_dbg_hwbrk (
+
+// OUTPUTs
+    brk_halt,                // Hardware breakpoint command
+    brk_pnd,                 // Hardware break/watch-point pending
+    brk_dout,                // Hardware break/watch-point register data input
+                            
+// INPUTs
+    brk_reg_rd,              // Hardware break/watch-point register read select
+    brk_reg_wr,              // Hardware break/watch-point register write select
+    dbg_clk,                 // Debug unit clock
+    dbg_din,                 // Debug register data input
+    dbg_rst,                 // Debug unit reset
+    eu_mab,                  // Execution-Unit Memory address bus
+    eu_mb_en,                // Execution-Unit Memory bus enable
+    eu_mb_wr,                // Execution-Unit Memory bus write transfer
+    eu_mdb_in,               // Memory data bus input
+    eu_mdb_out,              // Memory data bus output
+    exec_done,               // Execution completed
+    fe_mb_en,                // Frontend Memory bus enable
+    pc                       // Program counter
+);
+
+// OUTPUTs
+//=========
+output         brk_halt;     // Hardware breakpoint command
+output         brk_pnd;      // Hardware break/watch-point pending
+output  [15:0] brk_dout;     // Hardware break/watch-point register data input
+
+// INPUTs
+//=========
+input    [3:0] brk_reg_rd;   // Hardware break/watch-point register read select
+input    [3:0] brk_reg_wr;   // Hardware break/watch-point register write select
+input          dbg_clk;      // Debug unit clock
+input   [15:0] dbg_din;      // Debug register data input
+input          dbg_rst;      // Debug unit reset
+input   [15:0] eu_mab;       // Execution-Unit Memory address bus
+input          eu_mb_en;     // Execution-Unit Memory bus enable
+input    [1:0] eu_mb_wr;     // Execution-Unit Memory bus write transfer
+input   [15:0] eu_mdb_in;    // Memory data bus input
+input   [15:0] eu_mdb_out;   // Memory data bus output
+input          exec_done;    // Execution completed
+input          fe_mb_en;     // Frontend Memory bus enable
+input   [15:0] pc;           // Program counter
+
+
+//=============================================================================
+// 1)  WIRE & PARAMETER DECLARATION
+//=============================================================================
+
+wire      range_wr_set;
+wire      range_rd_set;
+wire      addr1_wr_set;
+wire      addr1_rd_set;
+wire      addr0_wr_set;
+wire      addr0_rd_set;
+
+   
+parameter BRK_CTL   = 0,
+          BRK_STAT  = 1,
+          BRK_ADDR0 = 2,
+          BRK_ADDR1 = 3;
+
+   
+//=============================================================================
+// 2)  CONFIGURATION REGISTERS
+//=============================================================================
+
+// BRK_CTL Register
+//-----------------------------------------------------------------------------
+//       7   6   5        4            3          2            1  0
+//        Reserved    RANGE_MODE    INST_EN    BREAK_EN    ACCESS_MODE
+//
+// ACCESS_MODE: - 00 : Disabled
+//              - 01 : Detect read access
+//              - 10 : Detect write access
+//              - 11 : Detect read/write access
+//              NOTE: '10' & '11' modes are not supported on the instruction flow
+//
+// BREAK_EN:    -  0 : Watchmode enable
+//              -  1 : Break enable
+//
+// INST_EN:     -  0 : Checks are done on the execution unit (data flow)
+//              -  1 : Checks are done on the frontend (instruction flow)
+//
+// RANGE_MODE:  -  0 : Address match on BRK_ADDR0 or BRK_ADDR1
+//              -  1 : Address match on BRK_ADDR0->BRK_ADDR1 range
+//
+//-----------------------------------------------------------------------------
+reg   [4:0] brk_ctl;
+
+wire        brk_ctl_wr = brk_reg_wr[BRK_CTL];
+   
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)         brk_ctl <=  5'h00;
+  else if (brk_ctl_wr) brk_ctl <=  {`HWBRK_RANGE & dbg_din[4], dbg_din[3:0]};
+
+wire  [7:0] brk_ctl_full = {3'b000, brk_ctl};
+
+   
+// BRK_STAT Register
+//-----------------------------------------------------------------------------
+//     7    6       5         4         3         2         1         0
+//    Reserved  RANGE_WR  RANGE_RD  ADDR1_WR  ADDR1_RD  ADDR0_WR  ADDR0_RD
+//-----------------------------------------------------------------------------
+reg   [5:0] brk_stat;
+
+wire        brk_stat_wr  = brk_reg_wr[BRK_STAT];
+wire  [5:0] brk_stat_set = {range_wr_set & `HWBRK_RANGE,
+                            range_rd_set & `HWBRK_RANGE,
+                           addr1_wr_set, addr1_rd_set,
+                           addr0_wr_set, addr0_rd_set};
+wire  [5:0] brk_stat_clr = ~dbg_din[5:0];
+
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)          brk_stat <=  6'h00;
+  else if (brk_stat_wr) brk_stat <= ((brk_stat & brk_stat_clr) | brk_stat_set);
+  else                  brk_stat <=  (brk_stat                 | brk_stat_set);
+
+wire  [7:0] brk_stat_full = {2'b00, brk_stat};
+wire        brk_pnd       = |brk_stat;
+
+
+// BRK_ADDR0 Register
+//-----------------------------------------------------------------------------
+reg  [15:0] brk_addr0;
+
+wire        brk_addr0_wr = brk_reg_wr[BRK_ADDR0];
+   
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)           brk_addr0 <=  16'h0000;
+  else if (brk_addr0_wr) brk_addr0 <=  dbg_din;
+
+   
+// BRK_ADDR1/DATA0 Register
+//-----------------------------------------------------------------------------
+reg  [15:0] brk_addr1;
+
+wire        brk_addr1_wr = brk_reg_wr[BRK_ADDR1];
+   
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)           brk_addr1 <=  16'h0000;
+  else if (brk_addr1_wr) brk_addr1 <=  dbg_din;
+
+   
+//============================================================================
+// 3) DATA OUTPUT GENERATION
+//============================================================================
+
+wire [15:0] brk_ctl_rd   = {8'h00, brk_ctl_full}  & {16{brk_reg_rd[BRK_CTL]}};
+wire [15:0] brk_stat_rd  = {8'h00, brk_stat_full} & {16{brk_reg_rd[BRK_STAT]}};
+wire [15:0] brk_addr0_rd = brk_addr0              & {16{brk_reg_rd[BRK_ADDR0]}};
+wire [15:0] brk_addr1_rd = brk_addr1              & {16{brk_reg_rd[BRK_ADDR1]}};
+
+wire [15:0] brk_dout = brk_ctl_rd   |
+                       brk_stat_rd  |
+                       brk_addr0_rd |
+                       brk_addr1_rd;
+
+   
+//============================================================================
+// 4) BREAKPOINT / WATCHPOINT GENERATION
+//============================================================================
+
+// Comparators
+//---------------------------
+// Note: here the comparison logic is instanciated several times in order
+//       to improve the timings, at the cost of a bit more area.
+   
+wire        equ_d_addr0 = eu_mb_en & (eu_mab==brk_addr0) & ~brk_ctl[`BRK_RANGE];
+wire        equ_d_addr1 = eu_mb_en & (eu_mab==brk_addr1) & ~brk_ctl[`BRK_RANGE];
+wire        equ_d_range = eu_mb_en & ((eu_mab>=brk_addr0) & (eu_mab<=brk_addr1)) & 
+                          brk_ctl[`BRK_RANGE] & `HWBRK_RANGE;
+
+reg         fe_mb_en_buf;
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)  fe_mb_en_buf <=  1'b0;
+  else          fe_mb_en_buf <=  fe_mb_en;
+
+wire        equ_i_addr0 = fe_mb_en_buf & (pc==brk_addr0) & ~brk_ctl[`BRK_RANGE];
+wire        equ_i_addr1 = fe_mb_en_buf & (pc==brk_addr1) & ~brk_ctl[`BRK_RANGE];
+wire        equ_i_range = fe_mb_en_buf & ((pc>=brk_addr0) & (pc<=brk_addr1)) &
+                          brk_ctl[`BRK_RANGE] & `HWBRK_RANGE;
+
+
+// Detect accesses
+//---------------------------
+
+// Detect Instruction read access
+wire i_addr0_rd =  equ_i_addr0 &  brk_ctl[`BRK_I_EN];
+wire i_addr1_rd =  equ_i_addr1 &  brk_ctl[`BRK_I_EN];
+wire i_range_rd =  equ_i_range &  brk_ctl[`BRK_I_EN];
+
+// Detect Execution-Unit write access
+wire d_addr0_wr =  equ_d_addr0 & ~brk_ctl[`BRK_I_EN] &  |eu_mb_wr;
+wire d_addr1_wr =  equ_d_addr1 & ~brk_ctl[`BRK_I_EN] &  |eu_mb_wr;
+wire d_range_wr =  equ_d_range & ~brk_ctl[`BRK_I_EN] &  |eu_mb_wr;
+
+// Detect DATA read access
+// Whenever an "ADD r9. &0x200" instruction is executed, &0x200 will be read
+// before being written back. In that case, the read flag should not be set.
+// In general, We should here make sure no write access occures during the
+// same instruction cycle before setting the read flag.
+reg [2:0] d_rd_trig;
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)        d_rd_trig <=  3'h0;
+  else if (exec_done) d_rd_trig <=  3'h0;
+  else                d_rd_trig <=  {equ_d_range & ~brk_ctl[`BRK_I_EN] & ~|eu_mb_wr,
+                                     equ_d_addr1 & ~brk_ctl[`BRK_I_EN] & ~|eu_mb_wr,
+                                     equ_d_addr0 & ~brk_ctl[`BRK_I_EN] & ~|eu_mb_wr};
+   
+wire d_addr0_rd =  d_rd_trig[0] & exec_done & ~d_addr0_wr;
+wire d_addr1_rd =  d_rd_trig[1] & exec_done & ~d_addr1_wr;
+wire d_range_rd =  d_rd_trig[2] & exec_done & ~d_range_wr;
+
+
+// Set flags
+assign addr0_rd_set = brk_ctl[`BRK_MODE_RD] & (d_addr0_rd  | i_addr0_rd);
+assign addr0_wr_set = brk_ctl[`BRK_MODE_WR] &  d_addr0_wr;
+assign addr1_rd_set = brk_ctl[`BRK_MODE_RD] & (d_addr1_rd  | i_addr1_rd);
+assign addr1_wr_set = brk_ctl[`BRK_MODE_WR] &  d_addr1_wr;
+assign range_rd_set = brk_ctl[`BRK_MODE_RD] & (d_range_rd  | i_range_rd);
+assign range_wr_set = brk_ctl[`BRK_MODE_WR] &  d_range_wr;
+
+   
+// Break CPU
+assign brk_halt     = brk_ctl[`BRK_EN] & |brk_stat_set;
+   
+     
+endmodule // omsp_dbg_hwbrk
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
diff --git a/tests/openmsp430/rtl/omsp_dbg_uart.v b/tests/openmsp430/rtl/omsp_dbg_uart.v
new file mode 100644 (file)
index 0000000..319099a
--- /dev/null
@@ -0,0 +1,298 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_dbg_uart.v
+// 
+// *Module Description:
+//                       Debug UART communication interface (8N1, Half-duplex)
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 134 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2012-03-22 21:31:06 +0100 (Thu, 22 Mar 2012) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module  omsp_dbg_uart (
+
+// OUTPUTs
+    dbg_addr,                       // Debug register address
+    dbg_din,                        // Debug register data input
+    dbg_rd,                         // Debug register data read
+    dbg_uart_txd,                   // Debug interface: UART TXD
+    dbg_wr,                         // Debug register data write
+                            
+// INPUTs
+    dbg_clk,                        // Debug unit clock
+    dbg_dout,                       // Debug register data output
+    dbg_rd_rdy,                     // Debug register data is ready for read
+    dbg_rst,                        // Debug unit reset
+    dbg_uart_rxd,                   // Debug interface: UART RXD
+    mem_burst,                      // Burst on going
+    mem_burst_end,                  // End TX/RX burst
+    mem_burst_rd,                   // Start TX burst
+    mem_burst_wr,                   // Start RX burst
+    mem_bw                          // Burst byte width
+);
+
+// OUTPUTs
+//=========
+output        [5:0] dbg_addr;       // Debug register address
+output       [15:0] dbg_din;        // Debug register data input
+output              dbg_rd;         // Debug register data read
+output              dbg_uart_txd;   // Debug interface: UART TXD
+output              dbg_wr;         // Debug register data write
+
+// INPUTs
+//=========
+input               dbg_clk;        // Debug unit clock
+input        [15:0] dbg_dout;       // Debug register data output
+input               dbg_rd_rdy;     // Debug register data is ready for read
+input               dbg_rst;        // Debug unit reset
+input               dbg_uart_rxd;   // Debug interface: UART RXD
+input               mem_burst;      // Burst on going
+input               mem_burst_end;  // End TX/RX burst
+input               mem_burst_rd;   // Start TX burst
+input               mem_burst_wr;   // Start RX burst
+input               mem_bw;         // Burst byte width
+
+
+//=============================================================================
+// 1)  UART RECEIVE LINE SYNCHRONIZTION & FILTERING
+//=============================================================================
+
+// Synchronize RXD input
+//--------------------------------
+`ifdef SYNC_DBG_UART_RXD
+
+    wire uart_rxd_n;
+
+    omsp_sync_cell sync_cell_uart_rxd (
+        .data_out  (uart_rxd_n),
+        .data_in   (~dbg_uart_rxd),
+        .clk       (dbg_clk),
+        .rst       (dbg_rst)
+    );
+    wire uart_rxd = ~uart_rxd_n;
+`else
+    wire uart_rxd = dbg_uart_rxd;
+`endif
+   
+// RXD input buffer
+//--------------------------------
+reg  [1:0] rxd_buf;
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst) rxd_buf <=  2'h3;
+  else         rxd_buf <=  {rxd_buf[0], uart_rxd};
+
+// Majority decision
+//------------------------
+reg        rxd_maj;
+
+wire       rxd_maj_nxt = (uart_rxd   & rxd_buf[0]) |
+                        (uart_rxd   & rxd_buf[1]) |
+                        (rxd_buf[0] & rxd_buf[1]);
+   
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst) rxd_maj <=  1'b1;
+  else         rxd_maj <=  rxd_maj_nxt;
+
+wire rxd_s    =  rxd_maj;
+wire rxd_fe   =  rxd_maj & ~rxd_maj_nxt;
+wire rxd_re   = ~rxd_maj &  rxd_maj_nxt;
+wire rxd_edge =  rxd_maj ^  rxd_maj_nxt;
+   
+//=============================================================================
+// 2)  UART STATE MACHINE
+//=============================================================================
+
+// Receive state
+//------------------------
+reg   [2:0] uart_state;
+reg   [2:0] uart_state_nxt;
+
+wire        sync_done;
+wire        xfer_done;
+reg  [19:0] xfer_buf;
+wire [19:0] xfer_buf_nxt;
+
+// State machine definition
+parameter  RX_SYNC  = 3'h0;
+parameter  RX_CMD   = 3'h1;
+parameter  RX_DATA1 = 3'h2;
+parameter  RX_DATA2 = 3'h3;
+parameter  TX_DATA1 = 3'h4;
+parameter  TX_DATA2 = 3'h5;
+
+// State transition
+always @(uart_state or xfer_buf_nxt or mem_burst or mem_burst_wr or mem_burst_rd or mem_burst_end or mem_bw)
+  case (uart_state)
+    RX_SYNC  : uart_state_nxt =  RX_CMD;
+    RX_CMD   : uart_state_nxt =  mem_burst_wr                ?
+                                (mem_bw                      ? RX_DATA2 : RX_DATA1) :
+                                 mem_burst_rd                ?
+                                (mem_bw                      ? TX_DATA2 : TX_DATA1) :
+                                (xfer_buf_nxt[`DBG_UART_WR]  ?
+                                (xfer_buf_nxt[`DBG_UART_BW]  ? RX_DATA2 : RX_DATA1) :
+                                (xfer_buf_nxt[`DBG_UART_BW]  ? TX_DATA2 : TX_DATA1));
+    RX_DATA1 : uart_state_nxt =  RX_DATA2;
+    RX_DATA2 : uart_state_nxt = (mem_burst & ~mem_burst_end) ?
+                                (mem_bw                      ? RX_DATA2 : RX_DATA1) :
+                                 RX_CMD;
+    TX_DATA1 : uart_state_nxt =  TX_DATA2;
+    TX_DATA2 : uart_state_nxt = (mem_burst & ~mem_burst_end) ?
+                                (mem_bw                      ? TX_DATA2 : TX_DATA1) :
+                                 RX_CMD;
+  // pragma coverage off
+    default  : uart_state_nxt =  RX_CMD;
+  // pragma coverage on
+  endcase
+   
+// State machine
+always @(posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)                          uart_state <= RX_SYNC;
+  else if (xfer_done    | sync_done |
+           mem_burst_wr | mem_burst_rd) uart_state <= uart_state_nxt;
+
+// Utility signals
+wire cmd_valid = (uart_state==RX_CMD) & xfer_done;
+wire rx_active = (uart_state==RX_DATA1) | (uart_state==RX_DATA2) | (uart_state==RX_CMD);
+wire tx_active = (uart_state==TX_DATA1) | (uart_state==TX_DATA2);
+
+   
+//=============================================================================
+// 3)  UART SYNCHRONIZATION
+//=============================================================================
+// After DBG_RST, the host needs to fist send a synchronization character (0x80)
+// If this feature doesn't work properly, it is possible to disable it by
+// commenting the DBG_UART_AUTO_SYNC define in the openMSP430.inc file.
+
+reg        sync_busy;
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)                             sync_busy <=  1'b0;
+  else if ((uart_state==RX_SYNC) & rxd_fe) sync_busy <=  1'b1;
+  else if ((uart_state==RX_SYNC) & rxd_re) sync_busy <=  1'b0;
+
+assign sync_done =  (uart_state==RX_SYNC) & rxd_re & sync_busy;
+
+`ifdef DBG_UART_AUTO_SYNC
+
+reg [`DBG_UART_XFER_CNT_W+2:0] sync_cnt;
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)                                     sync_cnt <=  {{`DBG_UART_XFER_CNT_W{1'b1}}, 3'b000};
+  else if (sync_busy | (~sync_busy & sync_cnt[2])) sync_cnt <=  sync_cnt+{{`DBG_UART_XFER_CNT_W+2{1'b0}}, 1'b1};
+
+wire [`DBG_UART_XFER_CNT_W-1:0] bit_cnt_max = sync_cnt[`DBG_UART_XFER_CNT_W+2:3];
+`else
+wire [`DBG_UART_XFER_CNT_W-1:0] bit_cnt_max = `DBG_UART_CNT;
+`endif
+   
+   
+//=============================================================================
+// 4)  UART RECEIVE / TRANSMIT
+//=============================================================================
+   
+// Transfer counter
+//------------------------
+reg                      [3:0] xfer_bit;
+reg [`DBG_UART_XFER_CNT_W-1:0] xfer_cnt;
+
+wire       txd_start    = dbg_rd_rdy | (xfer_done & (uart_state==TX_DATA1));
+wire       rxd_start    = (xfer_bit==4'h0) & rxd_fe & ((uart_state!=RX_SYNC));
+wire       xfer_bit_inc = (xfer_bit!=4'h0) & (xfer_cnt=={`DBG_UART_XFER_CNT_W{1'b0}});
+assign     xfer_done    = rx_active ? (xfer_bit==4'ha) : (xfer_bit==4'hb);
+   
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)                       xfer_bit <=  4'h0;
+  else if (txd_start | rxd_start)    xfer_bit <=  4'h1;
+  else if (xfer_done)                xfer_bit <=  4'h0;
+  else if (xfer_bit_inc)             xfer_bit <=  xfer_bit+4'h1;
+
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)                       xfer_cnt <=  {`DBG_UART_XFER_CNT_W{1'b0}};
+  else if (rx_active & rxd_edge)     xfer_cnt <=  {1'b0, bit_cnt_max[`DBG_UART_XFER_CNT_W-1:1]};
+  else if (txd_start | xfer_bit_inc) xfer_cnt <=  bit_cnt_max;
+  else if (|xfer_cnt)                xfer_cnt <=  xfer_cnt+{`DBG_UART_XFER_CNT_W{1'b1}};
+
+
+// Receive/Transmit buffer
+//-------------------------
+assign xfer_buf_nxt =  {rxd_s, xfer_buf[19:1]};
+
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)           xfer_buf <=  20'h00000;
+  else if (dbg_rd_rdy)   xfer_buf <=  {1'b1, dbg_dout[15:8], 2'b01, dbg_dout[7:0], 1'b0};
+  else if (xfer_bit_inc) xfer_buf <=  xfer_buf_nxt;
+
+
+// Generate TXD output
+//------------------------
+reg dbg_uart_txd;
+   
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)                       dbg_uart_txd <=  1'b1;
+  else if (xfer_bit_inc & tx_active) dbg_uart_txd <=  xfer_buf[0];
+
+//=============================================================================
+// 5) INTERFACE TO DEBUG REGISTERS
+//=============================================================================
+
+reg [5:0] dbg_addr;
+ always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)        dbg_addr <=  6'h00;
+  else if (cmd_valid) dbg_addr <=  xfer_buf_nxt[`DBG_UART_ADDR];
+
+reg       dbg_bw;
+always @ (posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst)        dbg_bw   <=  1'b0;
+  else if (cmd_valid) dbg_bw   <=  xfer_buf_nxt[`DBG_UART_BW];
+
+wire        dbg_din_bw =  mem_burst  ? mem_bw : dbg_bw;
+
+wire [15:0] dbg_din    =  dbg_din_bw ? {8'h00,           xfer_buf_nxt[18:11]} :
+                                       {xfer_buf_nxt[18:11], xfer_buf_nxt[9:2]};
+wire        dbg_wr     = (xfer_done & (uart_state==RX_DATA2));
+wire        dbg_rd     = mem_burst ? (xfer_done & (uart_state==TX_DATA2)) :
+                                     (cmd_valid & ~xfer_buf_nxt[`DBG_UART_WR]) | mem_burst_rd;
+
+           
+   
+endmodule // omsp_dbg_uart
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
diff --git a/tests/openmsp430/rtl/omsp_execution_unit.v b/tests/openmsp430/rtl/omsp_execution_unit.v
new file mode 100644 (file)
index 0000000..8a2965e
--- /dev/null
@@ -0,0 +1,420 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_execution_unit.v
+// 
+// *Module Description:
+//                       openMSP430 Execution unit
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 134 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2012-03-22 21:31:06 +0100 (Thu, 22 Mar 2012) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module  omsp_execution_unit (
+
+// OUTPUTs
+    cpuoff,                        // Turns off the CPU
+    dbg_reg_din,                   // Debug unit CPU register data input
+    gie,                           // General interrupt enable
+    mab,                           // Memory address bus
+    mb_en,                         // Memory bus enable
+    mb_wr,                         // Memory bus write transfer
+    mdb_out,                       // Memory data bus output
+    oscoff,                        // Turns off LFXT1 clock input
+    pc_sw,                         // Program counter software value
+    pc_sw_wr,                      // Program counter software write
+    scg0,                          // System clock generator 1. Turns off the DCO
+    scg1,                          // System clock generator 1. Turns off the SMCLK
+
+// INPUTs
+    dbg_halt_st,                   // Halt/Run status from CPU
+    dbg_mem_dout,                  // Debug unit data output
+    dbg_reg_wr,                    // Debug unit CPU register write
+    e_state,                       // Execution state
+    exec_done,                     // Execution completed
+    inst_ad,                       // Decoded Inst: destination addressing mode
+    inst_as,                       // Decoded Inst: source addressing mode
+    inst_alu,                      // ALU control signals
+    inst_bw,                       // Decoded Inst: byte width
+    inst_dest,                     // Decoded Inst: destination (one hot)
+    inst_dext,                     // Decoded Inst: destination extended instruction word
+    inst_irq_rst,                  // Decoded Inst: reset interrupt
+    inst_jmp,                      // Decoded Inst: Conditional jump
+    inst_mov,                      // Decoded Inst: mov instruction
+    inst_sext,                     // Decoded Inst: source extended instruction word
+    inst_so,                       // Decoded Inst: Single-operand arithmetic
+    inst_src,                      // Decoded Inst: source (one hot)
+    inst_type,                     // Decoded Instruction type
+    mclk,                          // Main system clock
+    mdb_in,                        // Memory data bus input
+    pc,                            // Program counter
+    pc_nxt,                        // Next PC value (for CALL & IRQ)
+    puc_rst,                       // Main system reset
+    scan_enable                    // Scan enable (active during scan shifting)
+);
+
+// OUTPUTs
+//=========
+output                     cpuoff;        // Turns off the CPU
+output       [15:0] dbg_reg_din;   // Debug unit CPU register data input
+output                     gie;           // General interrupt enable
+output       [15:0] mab;           // Memory address bus
+output              mb_en;         // Memory bus enable
+output        [1:0] mb_wr;         // Memory bus write transfer
+output       [15:0] mdb_out;       // Memory data bus output
+output                     oscoff;        // Turns off LFXT1 clock input
+output       [15:0] pc_sw;         // Program counter software value
+output              pc_sw_wr;      // Program counter software write
+output              scg0;          // System clock generator 1. Turns off the DCO
+output              scg1;          // System clock generator 1. Turns off the SMCLK
+
+// INPUTs
+//=========
+input               dbg_halt_st;   // Halt/Run status from CPU
+input        [15:0] dbg_mem_dout;  // Debug unit data output
+input               dbg_reg_wr;    // Debug unit CPU register write
+input         [3:0] e_state;       // Execution state
+input               exec_done;     // Execution completed
+input         [7:0] inst_ad;       // Decoded Inst: destination addressing mode
+input         [7:0] inst_as;       // Decoded Inst: source addressing mode
+input        [11:0] inst_alu;      // ALU control signals
+input               inst_bw;       // Decoded Inst: byte width
+input        [15:0] inst_dest;     // Decoded Inst: destination (one hot)
+input        [15:0] inst_dext;     // Decoded Inst: destination extended instruction word
+input               inst_irq_rst;  // Decoded Inst: reset interrupt
+input         [7:0] inst_jmp;      // Decoded Inst: Conditional jump
+input               inst_mov;      // Decoded Inst: mov instruction
+input        [15:0] inst_sext;     // Decoded Inst: source extended instruction word
+input         [7:0] inst_so;       // Decoded Inst: Single-operand arithmetic
+input        [15:0] inst_src;      // Decoded Inst: source (one hot)
+input         [2:0] inst_type;     // Decoded Instruction type
+input               mclk;          // Main system clock
+input        [15:0] mdb_in;        // Memory data bus input
+input        [15:0] pc;            // Program counter
+input        [15:0] pc_nxt;        // Next PC value (for CALL & IRQ)
+input               puc_rst;       // Main system reset
+input               scan_enable;   // Scan enable (active during scan shifting)
+
+
+//=============================================================================
+// 1)  INTERNAL WIRES/REGISTERS/PARAMETERS DECLARATION
+//=============================================================================
+
+wire         [15:0] alu_out;
+wire         [15:0] alu_out_add;
+wire          [3:0] alu_stat;
+wire          [3:0] alu_stat_wr;
+wire         [15:0] op_dst;
+wire         [15:0] op_src;
+wire         [15:0] reg_dest;
+wire         [15:0] reg_src;
+wire         [15:0] mdb_in_bw;
+wire         [15:0] mdb_in_val;
+wire          [3:0] status;
+
+
+//=============================================================================
+// 2)  REGISTER FILE
+//=============================================================================
+
+wire reg_dest_wr  = ((e_state==`E_EXEC) & (
+                     (inst_type[`INST_TO] & inst_ad[`DIR] & ~inst_alu[`EXEC_NO_WR])  |
+                     (inst_type[`INST_SO] & inst_as[`DIR] & ~(inst_so[`PUSH] | inst_so[`CALL] | inst_so[`RETI])) |
+                      inst_type[`INST_JMP])) | dbg_reg_wr;
+
+wire reg_sp_wr    = (((e_state==`E_IRQ_1) | (e_state==`E_IRQ_3)) & ~inst_irq_rst) |
+                     ((e_state==`E_DST_RD) & ((inst_so[`PUSH] | inst_so[`CALL]) &  ~inst_as[`IDX] & ~((inst_as[`INDIR] | inst_as[`INDIR_I]) & inst_src[1]))) |
+                     ((e_state==`E_SRC_AD) & ((inst_so[`PUSH] | inst_so[`CALL]) &  inst_as[`IDX])) |
+                     ((e_state==`E_SRC_RD) & ((inst_so[`PUSH] | inst_so[`CALL]) &  ((inst_as[`INDIR] | inst_as[`INDIR_I]) & inst_src[1])));
+
+wire reg_sr_wr    =  (e_state==`E_DST_RD) & inst_so[`RETI];
+
+wire reg_sr_clr   =  (e_state==`E_IRQ_2);
+
+wire reg_pc_call  = ((e_state==`E_EXEC)   & inst_so[`CALL]) | 
+                    ((e_state==`E_DST_WR) & inst_so[`RETI]);
+
+wire reg_incr     =  (exec_done          & inst_as[`INDIR_I]) |
+                    ((e_state==`E_SRC_RD) & inst_so[`RETI])    |
+                    ((e_state==`E_EXEC)   & inst_so[`RETI]);
+
+assign dbg_reg_din = reg_dest;
+
+
+omsp_register_file register_file_0 (
+
+// OUTPUTs
+    .cpuoff       (cpuoff),       // Turns off the CPU
+    .gie          (gie),          // General interrupt enable
+    .oscoff       (oscoff),       // Turns off LFXT1 clock input
+    .pc_sw        (pc_sw),        // Program counter software value
+    .pc_sw_wr     (pc_sw_wr),     // Program counter software write
+    .reg_dest     (reg_dest),     // Selected register destination content
+    .reg_src      (reg_src),      // Selected register source content
+    .scg0         (scg0),         // System clock generator 1. Turns off the DCO
+    .scg1         (scg1),         // System clock generator 1. Turns off the SMCLK
+    .status       (status),       // R2 Status {V,N,Z,C}
+
+// INPUTs
+    .alu_stat     (alu_stat),     // ALU Status {V,N,Z,C}
+    .alu_stat_wr  (alu_stat_wr),  // ALU Status write {V,N,Z,C}
+    .inst_bw      (inst_bw),      // Decoded Inst: byte width
+    .inst_dest    (inst_dest),    // Register destination selection
+    .inst_src     (inst_src),     // Register source selection
+    .mclk         (mclk),         // Main system clock
+    .pc           (pc),           // Program counter
+    .puc_rst      (puc_rst),      // Main system reset
+    .reg_dest_val (alu_out),      // Selected register destination value
+    .reg_dest_wr  (reg_dest_wr),  // Write selected register destination
+    .reg_pc_call  (reg_pc_call),  // Trigger PC update for a CALL instruction
+    .reg_sp_val   (alu_out_add),  // Stack Pointer next value
+    .reg_sp_wr    (reg_sp_wr),    // Stack Pointer write
+    .reg_sr_clr   (reg_sr_clr),   // Status register clear for interrupts
+    .reg_sr_wr    (reg_sr_wr),    // Status Register update for RETI instruction
+    .reg_incr     (reg_incr),     // Increment source register
+    .scan_enable  (scan_enable)   // Scan enable (active during scan shifting)
+);
+
+
+//=============================================================================
+// 3)  SOURCE OPERAND MUXING
+//=============================================================================
+// inst_as[`DIR]    : Register direct.   -> Source is in register
+// inst_as[`IDX]    : Register indexed.  -> Source is in memory, address is register+offset
+// inst_as[`INDIR]  : Register indirect.
+// inst_as[`INDIR_I]: Register indirect autoincrement.
+// inst_as[`SYMB]   : Symbolic (operand is in memory at address PC+x).
+// inst_as[`IMM]    : Immediate (operand is next word in the instruction stream).
+// inst_as[`ABS]    : Absolute (operand is in memory at address x).
+// inst_as[`CONST]  : Constant.
+
+wire src_reg_src_sel    =  (e_state==`E_IRQ_0)                    |
+                           (e_state==`E_IRQ_2)                    |
+                          ((e_state==`E_SRC_RD) & ~inst_as[`ABS]) |
+                          ((e_state==`E_SRC_WR) & ~inst_as[`ABS]) |
+                          ((e_state==`E_EXEC)   &  inst_as[`DIR] & ~inst_type[`INST_JMP]);
+
+wire src_reg_dest_sel   =  (e_state==`E_IRQ_1)                    |
+                           (e_state==`E_IRQ_3)                    |
+                          ((e_state==`E_DST_RD) & (inst_so[`PUSH] | inst_so[`CALL])) |
+                          ((e_state==`E_SRC_AD) & (inst_so[`PUSH] | inst_so[`CALL]) & inst_as[`IDX]);
+
+wire src_mdb_in_val_sel = ((e_state==`E_DST_RD) &  inst_so[`RETI])                     |
+                          ((e_state==`E_EXEC)   & (inst_as[`INDIR] | inst_as[`INDIR_I] |
+                                                   inst_as[`IDX]   | inst_as[`SYMB]    |
+                                                   inst_as[`ABS]));
+
+wire src_inst_dext_sel =  ((e_state==`E_DST_RD) & ~(inst_so[`PUSH] | inst_so[`CALL])) |
+                          ((e_state==`E_DST_WR) & ~(inst_so[`PUSH] | inst_so[`CALL]   |
+                                                    inst_so[`RETI]));
+
+wire src_inst_sext_sel =  ((e_state==`E_EXEC)   &  (inst_type[`INST_JMP] | inst_as[`IMM] |
+                                                    inst_as[`CONST]      | inst_so[`RETI]));
+
+
+assign op_src = src_reg_src_sel     ?  reg_src    :
+                src_reg_dest_sel    ?  reg_dest   :
+                src_mdb_in_val_sel  ?  mdb_in_val :
+                src_inst_dext_sel   ?  inst_dext  :
+                src_inst_sext_sel   ?  inst_sext  : 16'h0000;
+
+
+//=============================================================================
+// 4)  DESTINATION OPERAND MUXING
+//=============================================================================
+// inst_ad[`DIR]    : Register direct.
+// inst_ad[`IDX]    : Register indexed.
+// inst_ad[`SYMB]   : Symbolic (operand is in memory at address PC+x).
+// inst_ad[`ABS]    : Absolute (operand is in memory at address x).
+
+
+wire dst_inst_sext_sel  = ((e_state==`E_SRC_RD) & (inst_as[`IDX] | inst_as[`SYMB] |
+                                                   inst_as[`ABS]))                |
+                          ((e_state==`E_SRC_WR) & (inst_as[`IDX] | inst_as[`SYMB] |
+                                                   inst_as[`ABS]));
+
+wire dst_mdb_in_bw_sel  = ((e_state==`E_DST_WR) &   inst_so[`RETI]) |
+                          ((e_state==`E_EXEC)   & ~(inst_ad[`DIR] | inst_type[`INST_JMP] |
+                                                    inst_type[`INST_SO]) & ~inst_so[`RETI]);
+
+wire dst_fffe_sel       =  (e_state==`E_IRQ_0)  |
+                           (e_state==`E_IRQ_1)  |
+                           (e_state==`E_IRQ_3)  |
+                          ((e_state==`E_DST_RD) & (inst_so[`PUSH] | inst_so[`CALL]) & ~inst_so[`RETI]) |
+                          ((e_state==`E_SRC_AD) & (inst_so[`PUSH] | inst_so[`CALL]) & inst_as[`IDX]) |
+                          ((e_state==`E_SRC_RD) & (inst_so[`PUSH] | inst_so[`CALL]) & (inst_as[`INDIR] | inst_as[`INDIR_I]) & inst_src[1]);
+
+wire dst_reg_dest_sel   = ((e_state==`E_DST_RD) & ~(inst_so[`PUSH] | inst_so[`CALL] | inst_ad[`ABS] | inst_so[`RETI])) |
+                          ((e_state==`E_DST_WR) &  ~inst_ad[`ABS]) |
+                          ((e_state==`E_EXEC)   &  (inst_ad[`DIR] | inst_type[`INST_JMP] |
+                                                    inst_type[`INST_SO]) & ~inst_so[`RETI]);
+
+
+assign op_dst = dbg_halt_st        ? dbg_mem_dout  :
+                dst_inst_sext_sel  ? inst_sext     :
+                dst_mdb_in_bw_sel  ? mdb_in_bw     :
+                dst_reg_dest_sel   ? reg_dest      :
+                dst_fffe_sel       ? 16'hfffe      : 16'h0000;
+
+
+//=============================================================================
+// 5)  ALU
+//=============================================================================
+
+wire exec_cycle = (e_state==`E_EXEC);
+
+omsp_alu alu_0 (
+
+// OUTPUTs
+    .alu_out      (alu_out),      // ALU output value
+    .alu_out_add  (alu_out_add),  // ALU adder output value
+    .alu_stat     (alu_stat),     // ALU Status {V,N,Z,C}
+    .alu_stat_wr  (alu_stat_wr),  // ALU Status write {V,N,Z,C}
+
+// INPUTs
+    .dbg_halt_st  (dbg_halt_st),  // Halt/Run status from CPU
+    .exec_cycle   (exec_cycle),   // Instruction execution cycle
+    .inst_alu     (inst_alu),     // ALU control signals
+    .inst_bw      (inst_bw),      // Decoded Inst: byte width
+    .inst_jmp     (inst_jmp),     // Decoded Inst: Conditional jump
+    .inst_so      (inst_so),      // Single-operand arithmetic
+    .op_dst       (op_dst),       // Destination operand
+    .op_src       (op_src),       // Source operand
+    .status       (status)        // R2 Status {V,N,Z,C}
+);
+
+
+//=============================================================================
+// 6)  MEMORY INTERFACE
+//=============================================================================
+
+// Detect memory read/write access
+assign      mb_en     = ((e_state==`E_IRQ_1)  & ~inst_irq_rst)        |
+                        ((e_state==`E_IRQ_3)  & ~inst_irq_rst)        |
+                        ((e_state==`E_SRC_RD) & ~inst_as[`IMM])       |
+                         (e_state==`E_SRC_WR)                         |
+                        ((e_state==`E_EXEC)   &  inst_so[`RETI])      |
+                        ((e_state==`E_DST_RD) & ~inst_type[`INST_SO]
+                                              & ~inst_mov)            |
+                         (e_state==`E_DST_WR);
+
+wire  [1:0] mb_wr_msk =  inst_alu[`EXEC_NO_WR]  ? 2'b00 :
+                        ~inst_bw                ? 2'b11 :
+                         alu_out_add[0]         ? 2'b10 : 2'b01;
+assign      mb_wr     = ({2{(e_state==`E_IRQ_1)}}  |
+                         {2{(e_state==`E_IRQ_3)}}  |
+                         {2{(e_state==`E_DST_WR)}} |
+                         {2{(e_state==`E_SRC_WR)}}) & mb_wr_msk;
+
+// Memory address bus
+assign      mab       = alu_out_add[15:0];
+
+// Memory data bus output
+reg  [15:0] mdb_out_nxt;
+
+`ifdef CLOCK_GATING
+wire        mdb_out_nxt_en  = (e_state==`E_DST_RD) |
+                              (((e_state==`E_EXEC) & ~inst_so[`CALL]) |
+                                (e_state==`E_IRQ_0) | (e_state==`E_IRQ_2));
+wire        mclk_mdb_out_nxt;
+omsp_clock_gate clock_gate_mdb_out_nxt (.gclk(mclk_mdb_out_nxt),
+                                        .clk (mclk), .enable(mdb_out_nxt_en), .scan_enable(scan_enable));
+`else
+wire        mclk_mdb_out_nxt = mclk;
+`endif
+
+always @(posedge mclk_mdb_out_nxt or posedge puc_rst)
+  if (puc_rst)                                        mdb_out_nxt <= 16'h0000;
+  else if (e_state==`E_DST_RD)                        mdb_out_nxt <= pc_nxt;
+`ifdef CLOCK_GATING
+  else                                                mdb_out_nxt <= alu_out;
+`else
+  else if ((e_state==`E_EXEC & ~inst_so[`CALL]) |
+           (e_state==`E_IRQ_0) | (e_state==`E_IRQ_2)) mdb_out_nxt <= alu_out;
+`endif
+
+assign      mdb_out = inst_bw ? {2{mdb_out_nxt[7:0]}} : mdb_out_nxt;
+
+// Format memory data bus input depending on BW
+reg        mab_lsb;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)    mab_lsb <= 1'b0;
+  else if (mb_en) mab_lsb <= alu_out_add[0];
+
+assign mdb_in_bw  = ~inst_bw ? mdb_in :
+                     mab_lsb ? {2{mdb_in[15:8]}} : mdb_in;
+
+// Memory data bus input buffer (buffer after a source read)
+reg         mdb_in_buf_en;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)  mdb_in_buf_en <= 1'b0;
+  else          mdb_in_buf_en <= (e_state==`E_SRC_RD);
+
+reg         mdb_in_buf_valid;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)               mdb_in_buf_valid <= 1'b0;
+  else if (e_state==`E_EXEC) mdb_in_buf_valid <= 1'b0;
+  else if (mdb_in_buf_en)    mdb_in_buf_valid <= 1'b1;
+
+reg  [15:0] mdb_in_buf;
+
+`ifdef CLOCK_GATING
+wire        mclk_mdb_in_buf;
+omsp_clock_gate clock_gate_mdb_in_buf (.gclk(mclk_mdb_in_buf),
+                                       .clk (mclk), .enable(mdb_in_buf_en), .scan_enable(scan_enable));
+`else
+wire        mclk_mdb_in_buf = mclk;
+`endif
+
+always @(posedge mclk_mdb_in_buf or posedge puc_rst)
+  if (puc_rst)            mdb_in_buf <= 16'h0000;
+`ifdef CLOCK_GATING
+  else                    mdb_in_buf <= mdb_in_bw;
+`else
+  else if (mdb_in_buf_en) mdb_in_buf <= mdb_in_bw;
+`endif
+
+assign mdb_in_val = mdb_in_buf_valid ? mdb_in_buf : mdb_in_bw;
+
+
+endmodule // omsp_execution_unit
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
diff --git a/tests/openmsp430/rtl/omsp_frontend.v b/tests/openmsp430/rtl/omsp_frontend.v
new file mode 100644 (file)
index 0000000..343944b
--- /dev/null
@@ -0,0 +1,966 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_frontend.v
+// 
+// *Module Description:
+//                       openMSP430 Instruction fetch and decode unit
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 134 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2012-03-22 21:31:06 +0100 (Thu, 22 Mar 2012) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module  omsp_frontend (
+
+// OUTPUTs
+    dbg_halt_st,                   // Halt/Run status from CPU
+    decode_noirq,                  // Frontend decode instruction
+    e_state,                       // Execution state
+    exec_done,                     // Execution completed
+    inst_ad,                       // Decoded Inst: destination addressing mode
+    inst_as,                       // Decoded Inst: source addressing mode
+    inst_alu,                      // ALU control signals
+    inst_bw,                       // Decoded Inst: byte width
+    inst_dest,                     // Decoded Inst: destination (one hot)
+    inst_dext,                     // Decoded Inst: destination extended instruction word
+    inst_irq_rst,                  // Decoded Inst: Reset interrupt
+    inst_jmp,                      // Decoded Inst: Conditional jump
+    inst_mov,                      // Decoded Inst: mov instruction
+    inst_sext,                     // Decoded Inst: source extended instruction word
+    inst_so,                       // Decoded Inst: Single-operand arithmetic
+    inst_src,                      // Decoded Inst: source (one hot)
+    inst_type,                     // Decoded Instruction type
+    irq_acc,                       // Interrupt request accepted (one-hot signal)
+    mab,                           // Frontend Memory address bus
+    mb_en,                         // Frontend Memory bus enable
+    mclk_enable,                   // Main System Clock enable
+    mclk_wkup,                     // Main System Clock wake-up (asynchronous)
+    nmi_acc,                       // Non-Maskable interrupt request accepted
+    pc,                            // Program counter
+    pc_nxt,                        // Next PC value (for CALL & IRQ)
+
+// INPUTs
+    cpu_en_s,                      // Enable CPU code execution (synchronous)
+    cpuoff,                        // Turns off the CPU
+    dbg_halt_cmd,                  // Halt CPU command
+    dbg_reg_sel,                   // Debug selected register for rd/wr access
+    fe_pmem_wait,                  // Frontend wait for Instruction fetch
+    gie,                           // General interrupt enable
+    irq,                           // Maskable interrupts
+    mclk,                          // Main system clock
+    mdb_in,                        // Frontend Memory data bus input
+    nmi_pnd,                       // Non-maskable interrupt pending
+    nmi_wkup,                      // NMI Wakeup
+    pc_sw,                         // Program counter software value
+    pc_sw_wr,                      // Program counter software write
+    puc_rst,                       // Main system reset
+    scan_enable,                   // Scan enable (active during scan shifting)
+    wdt_irq,                       // Watchdog-timer interrupt
+    wdt_wkup,                      // Watchdog Wakeup
+    wkup                           // System Wake-up (asynchronous)
+);
+
+// OUTPUTs
+//=========
+output              dbg_halt_st;   // Halt/Run status from CPU
+output              decode_noirq;  // Frontend decode instruction
+output        [3:0] e_state;       // Execution state
+output              exec_done;     // Execution completed
+output        [7:0] inst_ad;       // Decoded Inst: destination addressing mode
+output        [7:0] inst_as;       // Decoded Inst: source addressing mode
+output       [11:0] inst_alu;      // ALU control signals
+output              inst_bw;       // Decoded Inst: byte width
+output       [15:0] inst_dest;     // Decoded Inst: destination (one hot)
+output       [15:0] inst_dext;     // Decoded Inst: destination extended instruction word
+output              inst_irq_rst;  // Decoded Inst: Reset interrupt
+output        [7:0] inst_jmp;      // Decoded Inst: Conditional jump
+output              inst_mov;      // Decoded Inst: mov instruction
+output       [15:0] inst_sext;     // Decoded Inst: source extended instruction word
+output        [7:0] inst_so;       // Decoded Inst: Single-operand arithmetic
+output       [15:0] inst_src;      // Decoded Inst: source (one hot)
+output        [2:0] inst_type;     // Decoded Instruction type
+output       [13:0] irq_acc;       // Interrupt request accepted (one-hot signal)
+output       [15:0] mab;           // Frontend Memory address bus
+output              mb_en;         // Frontend Memory bus enable
+output              mclk_enable;   // Main System Clock enable
+output              mclk_wkup;     // Main System Clock wake-up (asynchronous)
+output              nmi_acc;       // Non-Maskable interrupt request accepted
+output       [15:0] pc;            // Program counter
+output       [15:0] pc_nxt;        // Next PC value (for CALL & IRQ)
+
+// INPUTs
+//=========
+input               cpu_en_s;      // Enable CPU code execution (synchronous)
+input               cpuoff;        // Turns off the CPU
+input               dbg_halt_cmd;  // Halt CPU command
+input         [3:0] dbg_reg_sel;   // Debug selected register for rd/wr access
+input               fe_pmem_wait;  // Frontend wait for Instruction fetch
+input               gie;           // General interrupt enable
+input        [13:0] irq;           // Maskable interrupts
+input               mclk;          // Main system clock
+input        [15:0] mdb_in;        // Frontend Memory data bus input
+input               nmi_pnd;       // Non-maskable interrupt pending
+input               nmi_wkup;      // NMI Wakeup
+input        [15:0] pc_sw;         // Program counter software value
+input               pc_sw_wr;      // Program counter software write
+input               puc_rst;       // Main system reset
+input               scan_enable;   // Scan enable (active during scan shifting)
+input               wdt_irq;       // Watchdog-timer interrupt
+input               wdt_wkup;      // Watchdog Wakeup
+input               wkup;          // System Wake-up (asynchronous)
+
+
+//=============================================================================
+// 1)  UTILITY FUNCTIONS
+//=============================================================================
+
+// 16 bits one-hot decoder
+function [15:0] one_hot16;
+   input  [3:0] binary;
+   begin
+      one_hot16         = 16'h0000;
+      one_hot16[binary] =  1'b1;
+   end
+endfunction
+   
+// 8 bits one-hot decoder
+function [7:0] one_hot8;
+   input  [2:0] binary;
+   begin
+      one_hot8         = 8'h00;
+      one_hot8[binary] = 1'b1;
+   end
+endfunction
+   
+
+//=============================================================================
+// 2)  PARAMETER DEFINITIONS
+//=============================================================================
+
+//
+// 2.1) Instruction State machine definitons
+//-------------------------------------------
+
+parameter I_IRQ_FETCH = `I_IRQ_FETCH;
+parameter I_IRQ_DONE  = `I_IRQ_DONE;
+parameter I_DEC       = `I_DEC;        // New instruction ready for decode
+parameter I_EXT1      = `I_EXT1;       // 1st Extension word
+parameter I_EXT2      = `I_EXT2;       // 2nd Extension word
+parameter I_IDLE      = `I_IDLE;       // CPU is in IDLE mode
+
+//
+// 2.2) Execution State machine definitons
+//-------------------------------------------
+
+parameter E_IRQ_0     = `E_IRQ_0;
+parameter E_IRQ_1     = `E_IRQ_1;
+parameter E_IRQ_2     = `E_IRQ_2;
+parameter E_IRQ_3     = `E_IRQ_3;
+parameter E_IRQ_4     = `E_IRQ_4;
+parameter E_SRC_AD    = `E_SRC_AD;
+parameter E_SRC_RD    = `E_SRC_RD;
+parameter E_SRC_WR    = `E_SRC_WR;
+parameter E_DST_AD    = `E_DST_AD;
+parameter E_DST_RD    = `E_DST_RD;
+parameter E_DST_WR    = `E_DST_WR;
+parameter E_EXEC      = `E_EXEC;
+parameter E_JUMP      = `E_JUMP;
+parameter E_IDLE      = `E_IDLE;
+
+
+//=============================================================================
+// 3)  FRONTEND STATE MACHINE
+//=============================================================================
+
+// The wire "conv" is used as state bits to calculate the next response
+reg  [2:0] i_state;
+reg  [2:0] i_state_nxt;
+
+reg  [1:0] inst_sz;
+wire [1:0] inst_sz_nxt;
+wire       irq_detect;
+wire [2:0] inst_type_nxt;
+wire       is_const;
+reg [15:0] sconst_nxt;
+reg  [3:0] e_state_nxt;
+           
+// CPU on/off through the debug interface or cpu_en port
+wire   cpu_halt_cmd = dbg_halt_cmd | ~cpu_en_s;
+   
+// States Transitions
+always @(i_state    or inst_sz  or inst_sz_nxt  or pc_sw_wr or exec_done or
+         irq_detect or cpuoff   or cpu_halt_cmd or e_state)
+    case(i_state)
+      I_IDLE     : i_state_nxt = (irq_detect & ~cpu_halt_cmd) ? I_IRQ_FETCH :
+                                 (~cpuoff    & ~cpu_halt_cmd) ? I_DEC       : I_IDLE;
+      I_IRQ_FETCH: i_state_nxt =  I_IRQ_DONE;
+      I_IRQ_DONE : i_state_nxt =  I_DEC;
+      I_DEC      : i_state_nxt =  irq_detect                  ? I_IRQ_FETCH :
+                          (cpuoff | cpu_halt_cmd) & exec_done ? I_IDLE      :
+                            cpu_halt_cmd & (e_state==E_IDLE)  ? I_IDLE      :
+                                  pc_sw_wr                    ? I_DEC       :
+                             ~exec_done & ~(e_state==E_IDLE)  ? I_DEC       :        // Wait in decode state
+                                  (inst_sz_nxt!=2'b00)        ? I_EXT1      : I_DEC; // until execution is completed
+      I_EXT1     : i_state_nxt =  pc_sw_wr                    ? I_DEC       : 
+                                  (inst_sz!=2'b01)            ? I_EXT2      : I_DEC;
+      I_EXT2     : i_state_nxt =  I_DEC;
+    // pragma coverage off
+      default    : i_state_nxt =  I_IRQ_FETCH;
+    // pragma coverage on
+    endcase
+
+// State machine
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst) i_state  <= I_IRQ_FETCH;
+  else         i_state  <= i_state_nxt;
+
+// Utility signals
+wire   decode_noirq =  ((i_state==I_DEC) &  (exec_done | (e_state==E_IDLE)));
+wire   decode       =  decode_noirq | irq_detect;
+wire   fetch        = ~((i_state==I_DEC) & ~(exec_done | (e_state==E_IDLE))) & ~(e_state_nxt==E_IDLE);
+
+// Debug interface cpu status
+reg    dbg_halt_st;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)  dbg_halt_st <= 1'b0;
+  else          dbg_halt_st <= cpu_halt_cmd & (i_state_nxt==I_IDLE);
+
+
+//=============================================================================
+// 4)  INTERRUPT HANDLING & SYSTEM WAKEUP
+//=============================================================================
+
+//
+// 4.1) INTERRUPT HANDLING
+//-----------------------------------------
+
+// Detect reset interrupt
+reg         inst_irq_rst;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)                  inst_irq_rst <= 1'b1;
+  else if (exec_done)           inst_irq_rst <= 1'b0;
+
+//  Detect other interrupts
+assign  irq_detect = (nmi_pnd | ((|irq | wdt_irq) & gie)) & ~cpu_halt_cmd & ~dbg_halt_st & (exec_done | (i_state==I_IDLE));
+
+`ifdef CLOCK_GATING
+wire       mclk_irq_num;
+omsp_clock_gate clock_gate_irq_num (.gclk(mclk_irq_num),
+                                    .clk (mclk), .enable(irq_detect), .scan_enable(scan_enable));
+`else
+wire       mclk_irq_num = mclk;
+`endif
+
+// Select interrupt vector
+reg  [3:0] irq_num;
+always @(posedge mclk_irq_num or posedge puc_rst)
+  if (puc_rst)         irq_num <= 4'hf;
+`ifdef CLOCK_GATING
+  else                 irq_num <= nmi_pnd            ?  4'he :
+`else
+  else if (irq_detect) irq_num <= nmi_pnd            ?  4'he :
+`endif
+                                  irq[13]            ?  4'hd :
+                                  irq[12]            ?  4'hc :
+                                  irq[11]            ?  4'hb :
+                                 (irq[10] | wdt_irq) ?  4'ha :
+                                  irq[9]             ?  4'h9 :
+                                  irq[8]             ?  4'h8 :
+                                  irq[7]             ?  4'h7 :
+                                  irq[6]             ?  4'h6 :
+                                  irq[5]             ?  4'h5 :
+                                  irq[4]             ?  4'h4 :
+                                  irq[3]             ?  4'h3 :
+                                  irq[2]             ?  4'h2 :
+                                  irq[1]             ?  4'h1 :
+                                  irq[0]             ?  4'h0 : 4'hf;
+
+wire [15:0] irq_addr    = {11'h7ff, irq_num, 1'b0};
+
+// Interrupt request accepted
+wire [15:0] irq_acc_all = one_hot16(irq_num) & {16{(i_state==I_IRQ_FETCH)}};
+wire [13:0] irq_acc     = irq_acc_all[13:0];
+wire        nmi_acc     = irq_acc_all[14];
+
+//
+// 4.2) SYSTEM WAKEUP
+//-----------------------------------------
+`ifdef CPUOFF_EN
+
+// Generate the main system clock enable signal
+                                                    // Keep the clock running if:
+wire mclk_enable = inst_irq_rst ? cpu_en_s :        //      - the RESET interrupt is currently executing
+                                                    //        and if the CPU is enabled
+                                                    // otherwise if:
+                  ~((cpuoff | ~cpu_en_s) &          //      - the CPUOFF flag, cpu_en command, instruction
+                   (i_state==I_IDLE) &              //        and execution state machines are all two
+                   (e_state==E_IDLE));              //        not idle.
+
+   
+// Wakeup condition from maskable interrupts
+wire mirq_wkup;
+omsp_and_gate and_mirq_wkup (.y(mirq_wkup), .a(wkup | wdt_wkup), .b(gie));
+
+// Combined asynchronous wakeup detection from nmi & irq (masked if the cpu is disabled)
+omsp_and_gate and_mclk_wkup (.y(mclk_wkup), .a(nmi_wkup | mirq_wkup), .b(cpu_en_s));
+
+`else
+
+// In the CPUOFF feature is disabled, the wake-up and enable signals are always 1
+assign  mclk_wkup   = 1'b1;
+assign  mclk_enable = 1'b1;
+`endif
+
+//=============================================================================
+// 5)  FETCH INSTRUCTION
+//=============================================================================
+
+//
+// 5.1) PROGRAM COUNTER & MEMORY INTERFACE
+//-----------------------------------------
+
+// Program counter
+reg  [15:0] pc;
+
+// Compute next PC value
+wire [15:0] pc_incr = pc + {14'h0000, fetch, 1'b0};
+wire [15:0] pc_nxt  = pc_sw_wr               ? pc_sw    :
+                      (i_state==I_IRQ_FETCH) ? irq_addr :
+                      (i_state==I_IRQ_DONE)  ? mdb_in   :  pc_incr;
+
+`ifdef CLOCK_GATING
+wire       pc_en  = fetch                  |
+                    pc_sw_wr               |
+                    (i_state==I_IRQ_FETCH) |
+                    (i_state==I_IRQ_DONE);
+wire       mclk_pc;
+omsp_clock_gate clock_gate_pc (.gclk(mclk_pc),
+                               .clk (mclk), .enable(pc_en), .scan_enable(scan_enable));
+`else
+wire       mclk_pc = mclk;
+`endif
+
+always @(posedge mclk_pc or posedge puc_rst)
+  if (puc_rst)  pc <= 16'h0000;
+  else          pc <= pc_nxt;
+
+// Check if ROM has been busy in order to retry ROM access
+reg pmem_busy;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)  pmem_busy <= 1'b0;
+  else          pmem_busy <= fe_pmem_wait;
+   
+// Memory interface
+wire [15:0] mab      = pc_nxt;
+wire        mb_en    = fetch | pc_sw_wr | (i_state==I_IRQ_FETCH) | pmem_busy | (dbg_halt_st & ~cpu_halt_cmd);
+
+
+//
+// 5.2) INSTRUCTION REGISTER
+//--------------------------------
+
+// Instruction register
+wire [15:0] ir  = mdb_in;
+
+// Detect if source extension word is required
+wire is_sext = (inst_as[`IDX] | inst_as[`SYMB] | inst_as[`ABS] | inst_as[`IMM]);
+
+// For the Symbolic addressing mode, add -2 to the extension word in order
+// to make up for the PC address
+wire [15:0] ext_incr = ((i_state==I_EXT1)     &  inst_as[`SYMB]) |
+                       ((i_state==I_EXT2)     &  inst_ad[`SYMB]) |
+                       ((i_state==I_EXT1)     & ~inst_as[`SYMB] &
+                       ~(i_state_nxt==I_EXT2) &  inst_ad[`SYMB])   ? 16'hfffe : 16'h0000;
+
+wire [15:0] ext_nxt  = ir + ext_incr;
+
+// Store source extension word
+reg [15:0] inst_sext;
+
+`ifdef CLOCK_GATING
+wire       inst_sext_en  = (decode & is_const)                 |
+                           (decode & inst_type_nxt[`INST_JMP]) |
+                           ((i_state==I_EXT1) & is_sext);
+wire       mclk_inst_sext;
+omsp_clock_gate clock_gate_inst_sext (.gclk(mclk_inst_sext),
+                                      .clk (mclk), .enable(inst_sext_en), .scan_enable(scan_enable));
+`else
+wire       mclk_inst_sext = mclk;
+`endif
+
+always @(posedge mclk_inst_sext or posedge puc_rst)
+  if (puc_rst)                                 inst_sext <= 16'h0000;
+  else if (decode & is_const)                  inst_sext <= sconst_nxt;
+  else if (decode & inst_type_nxt[`INST_JMP])  inst_sext <= {{5{ir[9]}},ir[9:0],1'b0};
+`ifdef CLOCK_GATING
+  else                                         inst_sext <= ext_nxt;
+`else
+  else if ((i_state==I_EXT1) & is_sext)        inst_sext <= ext_nxt;
+`endif
+
+// Source extension word is ready
+wire inst_sext_rdy = (i_state==I_EXT1) & is_sext;
+
+
+// Store destination extension word
+reg [15:0] inst_dext;
+
+`ifdef CLOCK_GATING
+wire       inst_dext_en  = ((i_state==I_EXT1) & ~is_sext) |
+                            (i_state==I_EXT2);
+wire       mclk_inst_dext;
+omsp_clock_gate clock_gate_inst_dext (.gclk(mclk_inst_dext),
+                                      .clk (mclk), .enable(inst_dext_en), .scan_enable(scan_enable));
+`else
+wire       mclk_inst_dext = mclk;
+`endif
+
+always @(posedge mclk_inst_dext or posedge puc_rst)
+  if (puc_rst)                           inst_dext <= 16'h0000;
+  else if ((i_state==I_EXT1) & ~is_sext) inst_dext <= ext_nxt;
+`ifdef CLOCK_GATING
+  else                                   inst_dext <= ext_nxt;
+`else
+  else if  (i_state==I_EXT2)             inst_dext <= ext_nxt;
+`endif
+
+// Destination extension word is ready
+wire inst_dext_rdy = (((i_state==I_EXT1) & ~is_sext) | (i_state==I_EXT2));
+
+
+//=============================================================================
+// 6)  DECODE INSTRUCTION
+//=============================================================================
+
+`ifdef CLOCK_GATING
+wire       mclk_decode;
+omsp_clock_gate clock_gate_decode (.gclk(mclk_decode),
+                                   .clk (mclk), .enable(decode), .scan_enable(scan_enable));
+`else
+wire       mclk_decode = mclk;
+`endif
+
+//
+// 6.1) OPCODE: INSTRUCTION TYPE
+//----------------------------------------
+// Instructions type is encoded in a one hot fashion as following:
+//
+// 3'b001: Single-operand arithmetic
+// 3'b010: Conditional jump
+// 3'b100: Two-operand arithmetic
+
+reg  [2:0] inst_type;
+assign     inst_type_nxt = {(ir[15:14]!=2'b00),
+                            (ir[15:13]==3'b001),
+                            (ir[15:13]==3'b000)} & {3{~irq_detect}};
+   
+always @(posedge mclk_decode or posedge puc_rst)
+  if (puc_rst)      inst_type <= 3'b000;
+`ifdef CLOCK_GATING
+  else              inst_type <= inst_type_nxt;
+`else
+  else if (decode)  inst_type <= inst_type_nxt;
+`endif
+
+//
+// 6.2) OPCODE: SINGLE-OPERAND ARITHMETIC
+//----------------------------------------
+// Instructions are encoded in a one hot fashion as following:
+//
+// 8'b00000001: RRC
+// 8'b00000010: SWPB
+// 8'b00000100: RRA
+// 8'b00001000: SXT
+// 8'b00010000: PUSH
+// 8'b00100000: CALL
+// 8'b01000000: RETI
+// 8'b10000000: IRQ
+
+reg   [7:0] inst_so;
+wire  [7:0] inst_so_nxt = irq_detect ? 8'h80 : (one_hot8(ir[9:7]) & {8{inst_type_nxt[`INST_SO]}});
+
+always @(posedge mclk_decode or posedge puc_rst)
+  if (puc_rst)     inst_so <= 8'h00;
+`ifdef CLOCK_GATING
+  else             inst_so <= inst_so_nxt;
+`else
+  else if (decode) inst_so <= inst_so_nxt;
+`endif
+
+//
+// 6.3) OPCODE: CONDITIONAL JUMP
+//--------------------------------
+// Instructions are encoded in a one hot fashion as following:
+//
+// 8'b00000001: JNE/JNZ
+// 8'b00000010: JEQ/JZ
+// 8'b00000100: JNC/JLO
+// 8'b00001000: JC/JHS
+// 8'b00010000: JN
+// 8'b00100000: JGE
+// 8'b01000000: JL
+// 8'b10000000: JMP
+
+reg   [2:0] inst_jmp_bin;
+always @(posedge mclk_decode or posedge puc_rst)
+  if (puc_rst)     inst_jmp_bin <= 3'h0;
+`ifdef CLOCK_GATING
+  else             inst_jmp_bin <= ir[12:10];
+`else
+  else if (decode) inst_jmp_bin <= ir[12:10];
+`endif
+
+wire [7:0] inst_jmp = one_hot8(inst_jmp_bin) & {8{inst_type[`INST_JMP]}};
+
+
+//
+// 6.4) OPCODE: TWO-OPERAND ARITHMETIC
+//-------------------------------------
+// Instructions are encoded in a one hot fashion as following:
+//
+// 12'b000000000001: MOV
+// 12'b000000000010: ADD
+// 12'b000000000100: ADDC
+// 12'b000000001000: SUBC
+// 12'b000000010000: SUB
+// 12'b000000100000: CMP
+// 12'b000001000000: DADD
+// 12'b000010000000: BIT
+// 12'b000100000000: BIC
+// 12'b001000000000: BIS
+// 12'b010000000000: XOR
+// 12'b100000000000: AND
+
+wire [15:0] inst_to_1hot = one_hot16(ir[15:12]) & {16{inst_type_nxt[`INST_TO]}};
+wire [11:0] inst_to_nxt  = inst_to_1hot[15:4];
+
+reg         inst_mov;
+always @(posedge mclk_decode or posedge puc_rst)
+  if (puc_rst)     inst_mov <= 1'b0;
+`ifdef CLOCK_GATING
+  else             inst_mov <= inst_to_nxt[`MOV];
+`else
+  else if (decode) inst_mov <= inst_to_nxt[`MOV];
+`endif
+
+
+//
+// 6.5) SOURCE AND DESTINATION REGISTERS
+//---------------------------------------
+
+// Destination register
+reg [3:0] inst_dest_bin;
+always @(posedge mclk_decode or posedge puc_rst)
+  if (puc_rst)     inst_dest_bin <= 4'h0;
+`ifdef CLOCK_GATING
+  else             inst_dest_bin <= ir[3:0];
+`else
+  else if (decode) inst_dest_bin <= ir[3:0];
+`endif
+
+wire  [15:0] inst_dest = dbg_halt_st          ? one_hot16(dbg_reg_sel) :
+                         inst_type[`INST_JMP] ? 16'h0001               :
+                         inst_so[`IRQ]  |
+                         inst_so[`PUSH] |
+                         inst_so[`CALL]       ? 16'h0002               :
+                                                one_hot16(inst_dest_bin);
+
+
+// Source register
+reg [3:0] inst_src_bin;
+always @(posedge mclk_decode or posedge puc_rst)
+  if (puc_rst)     inst_src_bin <= 4'h0;
+`ifdef CLOCK_GATING
+  else             inst_src_bin <= ir[11:8];
+`else
+  else if (decode) inst_src_bin <= ir[11:8];
+`endif
+
+wire  [15:0] inst_src = inst_type[`INST_TO] ? one_hot16(inst_src_bin)  :
+                        inst_so[`RETI]      ? 16'h0002                 :
+                        inst_so[`IRQ]       ? 16'h0001                 :
+                        inst_type[`INST_SO] ? one_hot16(inst_dest_bin) : 16'h0000;
+
+
+//
+// 6.6) SOURCE ADDRESSING MODES
+//--------------------------------
+// Source addressing modes are encoded in a one hot fashion as following:
+//
+// 13'b0000000000001: Register direct.
+// 13'b0000000000010: Register indexed.
+// 13'b0000000000100: Register indirect.
+// 13'b0000000001000: Register indirect autoincrement.
+// 13'b0000000010000: Symbolic (operand is in memory at address PC+x).
+// 13'b0000000100000: Immediate (operand is next word in the instruction stream).
+// 13'b0000001000000: Absolute (operand is in memory at address x).
+// 13'b0000010000000: Constant 4.
+// 13'b0000100000000: Constant 8.
+// 13'b0001000000000: Constant 0.
+// 13'b0010000000000: Constant 1.
+// 13'b0100000000000: Constant 2.
+// 13'b1000000000000: Constant -1.
+
+reg [12:0] inst_as_nxt;
+
+wire [3:0] src_reg = inst_type_nxt[`INST_SO] ? ir[3:0] : ir[11:8];
+
+always @(src_reg or ir or inst_type_nxt)
+  begin
+     if (inst_type_nxt[`INST_JMP])
+       inst_as_nxt =  13'b0000000000001;
+     else if (src_reg==4'h3) // Addressing mode using R3
+       case (ir[5:4])
+         2'b11  : inst_as_nxt =  13'b1000000000000;
+         2'b10  : inst_as_nxt =  13'b0100000000000;
+         2'b01  : inst_as_nxt =  13'b0010000000000;
+         default: inst_as_nxt =  13'b0001000000000;
+       endcase
+     else if (src_reg==4'h2) // Addressing mode using R2
+       case (ir[5:4])
+         2'b11  : inst_as_nxt =  13'b0000100000000;
+         2'b10  : inst_as_nxt =  13'b0000010000000;
+         2'b01  : inst_as_nxt =  13'b0000001000000;
+         default: inst_as_nxt =  13'b0000000000001;
+       endcase
+     else if (src_reg==4'h0) // Addressing mode using R0
+       case (ir[5:4])
+         2'b11  : inst_as_nxt =  13'b0000000100000;
+         2'b10  : inst_as_nxt =  13'b0000000000100;
+         2'b01  : inst_as_nxt =  13'b0000000010000;
+         default: inst_as_nxt =  13'b0000000000001;
+       endcase
+     else                    // General Addressing mode
+       case (ir[5:4])
+         2'b11  : inst_as_nxt =  13'b0000000001000;
+         2'b10  : inst_as_nxt =  13'b0000000000100;
+         2'b01  : inst_as_nxt =  13'b0000000000010;
+         default: inst_as_nxt =  13'b0000000000001;
+       endcase
+  end
+assign    is_const = |inst_as_nxt[12:7];
+
+reg [7:0] inst_as;
+always @(posedge mclk_decode or posedge puc_rst)
+  if (puc_rst)     inst_as <= 8'h00;
+`ifdef CLOCK_GATING
+  else             inst_as <= {is_const, inst_as_nxt[6:0]};
+`else
+  else if (decode) inst_as <= {is_const, inst_as_nxt[6:0]};
+`endif
+
+
+// 13'b0000010000000: Constant 4.
+// 13'b0000100000000: Constant 8.
+// 13'b0001000000000: Constant 0.
+// 13'b0010000000000: Constant 1.
+// 13'b0100000000000: Constant 2.
+// 13'b1000000000000: Constant -1.
+always @(inst_as_nxt)
+  begin
+     if (inst_as_nxt[7])        sconst_nxt = 16'h0004;
+     else if (inst_as_nxt[8])   sconst_nxt = 16'h0008;
+     else if (inst_as_nxt[9])   sconst_nxt = 16'h0000;
+     else if (inst_as_nxt[10])  sconst_nxt = 16'h0001;
+     else if (inst_as_nxt[11])  sconst_nxt = 16'h0002;
+     else if (inst_as_nxt[12])  sconst_nxt = 16'hffff;
+     else                       sconst_nxt = 16'h0000;
+  end
+
+
+//
+// 6.7) DESTINATION ADDRESSING MODES
+//-----------------------------------
+// Destination addressing modes are encoded in a one hot fashion as following:
+//
+// 8'b00000001: Register direct.
+// 8'b00000010: Register indexed.
+// 8'b00010000: Symbolic (operand is in memory at address PC+x).
+// 8'b01000000: Absolute (operand is in memory at address x).
+
+reg  [7:0] inst_ad_nxt;
+
+wire [3:0] dest_reg = ir[3:0];
+
+always @(dest_reg or ir or inst_type_nxt)
+  begin
+     if (~inst_type_nxt[`INST_TO])
+       inst_ad_nxt =  8'b00000000;
+     else if (dest_reg==4'h2)   // Addressing mode using R2
+       case (ir[7])
+         1'b1   : inst_ad_nxt =  8'b01000000;
+         default: inst_ad_nxt =  8'b00000001;
+       endcase
+     else if (dest_reg==4'h0)   // Addressing mode using R0
+       case (ir[7])
+         1'b1   : inst_ad_nxt =  8'b00010000;
+         default: inst_ad_nxt =  8'b00000001;
+       endcase
+     else                       // General Addressing mode
+       case (ir[7])
+         1'b1   : inst_ad_nxt =  8'b00000010;
+         default: inst_ad_nxt =  8'b00000001;
+       endcase
+  end
+
+reg [7:0] inst_ad;
+always @(posedge mclk_decode or posedge puc_rst)
+  if (puc_rst)     inst_ad <= 8'h00;
+`ifdef CLOCK_GATING
+  else             inst_ad <= inst_ad_nxt;
+`else
+  else if (decode) inst_ad <= inst_ad_nxt;
+`endif
+
+
+//
+// 6.8) REMAINING INSTRUCTION DECODING
+//-------------------------------------
+
+// Operation size
+reg       inst_bw;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)     inst_bw     <= 1'b0;
+  else if (decode) inst_bw     <= ir[6] & ~inst_type_nxt[`INST_JMP] & ~irq_detect & ~cpu_halt_cmd;
+
+// Extended instruction size
+assign    inst_sz_nxt = {1'b0,  (inst_as_nxt[`IDX] | inst_as_nxt[`SYMB] | inst_as_nxt[`ABS] | inst_as_nxt[`IMM])} +
+                        {1'b0, ((inst_ad_nxt[`IDX] | inst_ad_nxt[`SYMB] | inst_ad_nxt[`ABS]) & ~inst_type_nxt[`INST_SO])};
+always @(posedge mclk_decode or posedge puc_rst)
+  if (puc_rst)     inst_sz     <= 2'b00;
+`ifdef CLOCK_GATING
+  else             inst_sz     <= inst_sz_nxt;
+`else
+  else if (decode) inst_sz     <= inst_sz_nxt;
+`endif
+
+
+//=============================================================================
+// 7)  EXECUTION-UNIT STATE MACHINE
+//=============================================================================
+
+// State machine registers
+reg  [3:0] e_state;
+
+
+// State machine control signals
+//--------------------------------
+
+wire src_acalc_pre =  inst_as_nxt[`IDX]   | inst_as_nxt[`SYMB]    | inst_as_nxt[`ABS];
+wire src_rd_pre    =  inst_as_nxt[`INDIR] | inst_as_nxt[`INDIR_I] | inst_as_nxt[`IMM]  | inst_so_nxt[`RETI];
+wire dst_acalc_pre =  inst_ad_nxt[`IDX]   | inst_ad_nxt[`SYMB]    | inst_ad_nxt[`ABS];
+wire dst_acalc     =  inst_ad[`IDX]       | inst_ad[`SYMB]        | inst_ad[`ABS];
+wire dst_rd_pre    =  inst_ad_nxt[`IDX]   | inst_so_nxt[`PUSH]    | inst_so_nxt[`CALL] | inst_so_nxt[`RETI];
+wire dst_rd        =  inst_ad[`IDX]       | inst_so[`PUSH]        | inst_so[`CALL]     | inst_so[`RETI];
+
+wire inst_branch   =  (inst_ad_nxt[`DIR] & (ir[3:0]==4'h0)) | inst_type_nxt[`INST_JMP] | inst_so_nxt[`RETI];
+
+reg exec_jmp;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)                   exec_jmp <= 1'b0;
+  else if (inst_branch & decode) exec_jmp <= 1'b1;
+  else if (e_state==E_JUMP)      exec_jmp <= 1'b0;
+
+reg exec_dst_wr;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)                exec_dst_wr <= 1'b0;
+  else if (e_state==E_DST_RD) exec_dst_wr <= 1'b1;
+  else if (e_state==E_DST_WR) exec_dst_wr <= 1'b0;
+
+reg exec_src_wr;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)                                         exec_src_wr <= 1'b0;
+  else if (inst_type[`INST_SO] & (e_state==E_SRC_RD))  exec_src_wr <= 1'b1;
+  else if ((e_state==E_SRC_WR) || (e_state==E_DST_WR)) exec_src_wr <= 1'b0;
+
+reg exec_dext_rdy;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)                exec_dext_rdy <= 1'b0;
+  else if (e_state==E_DST_RD) exec_dext_rdy <= 1'b0;
+  else if (inst_dext_rdy)     exec_dext_rdy <= 1'b1;
+
+// Execution first state
+wire [3:0] e_first_state = ~dbg_halt_st  & inst_so_nxt[`IRQ] ? E_IRQ_0  :
+                            cpu_halt_cmd | (i_state==I_IDLE) ? E_IDLE   :
+                            cpuoff                           ? E_IDLE   :
+                            src_acalc_pre                    ? E_SRC_AD :
+                            src_rd_pre                       ? E_SRC_RD :
+                            dst_acalc_pre                    ? E_DST_AD :
+                            dst_rd_pre                       ? E_DST_RD : E_EXEC;
+
+
+// State machine
+//--------------------------------
+
+// States Transitions
+always @(e_state       or dst_acalc     or dst_rd   or inst_sext_rdy or
+         inst_dext_rdy or exec_dext_rdy or exec_jmp or exec_dst_wr   or
+         e_first_state or exec_src_wr)
+    case(e_state)
+      E_IDLE   : e_state_nxt =  e_first_state;
+      E_IRQ_0  : e_state_nxt =  E_IRQ_1;
+      E_IRQ_1  : e_state_nxt =  E_IRQ_2;
+      E_IRQ_2  : e_state_nxt =  E_IRQ_3;
+      E_IRQ_3  : e_state_nxt =  E_IRQ_4;
+      E_IRQ_4  : e_state_nxt =  E_EXEC;
+
+      E_SRC_AD : e_state_nxt =  inst_sext_rdy     ? E_SRC_RD : E_SRC_AD;
+
+      E_SRC_RD : e_state_nxt =  dst_acalc         ? E_DST_AD : 
+                                 dst_rd           ? E_DST_RD : E_EXEC;
+
+      E_DST_AD : e_state_nxt =  (inst_dext_rdy |
+                                 exec_dext_rdy)   ? E_DST_RD : E_DST_AD;
+
+      E_DST_RD : e_state_nxt =  E_EXEC;
+
+      E_EXEC   : e_state_nxt =  exec_dst_wr       ? E_DST_WR :
+                                exec_jmp          ? E_JUMP   :
+                                exec_src_wr       ? E_SRC_WR : e_first_state;
+
+      E_JUMP   : e_state_nxt =  e_first_state;
+      E_DST_WR : e_state_nxt =  exec_jmp          ? E_JUMP   : e_first_state;
+      E_SRC_WR : e_state_nxt =  e_first_state;
+    // pragma coverage off
+      default  : e_state_nxt =  E_IRQ_0;
+    // pragma coverage on
+    endcase
+
+// State machine
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst) e_state  <= E_IRQ_1;
+  else         e_state  <= e_state_nxt;
+
+
+// Frontend State machine control signals
+//----------------------------------------
+
+wire exec_done = exec_jmp        ? (e_state==E_JUMP)   :
+                 exec_dst_wr     ? (e_state==E_DST_WR) :
+                 exec_src_wr     ? (e_state==E_SRC_WR) : (e_state==E_EXEC);
+
+
+//=============================================================================
+// 8)  EXECUTION-UNIT STATE CONTROL
+//=============================================================================
+
+//
+// 8.1) ALU CONTROL SIGNALS
+//-------------------------------------
+//
+// 12'b000000000001: Enable ALU source inverter
+// 12'b000000000010: Enable Incrementer
+// 12'b000000000100: Enable Incrementer on carry bit
+// 12'b000000001000: Select Adder
+// 12'b000000010000: Select AND
+// 12'b000000100000: Select OR
+// 12'b000001000000: Select XOR
+// 12'b000010000000: Select DADD
+// 12'b000100000000: Update N, Z & C (C=~Z)
+// 12'b001000000000: Update all status bits
+// 12'b010000000000: Update status bit for XOR instruction
+// 12'b100000000000: Don't write to destination
+
+reg  [11:0] inst_alu;
+
+wire        alu_src_inv   = inst_to_nxt[`SUB]  | inst_to_nxt[`SUBC] |
+                            inst_to_nxt[`CMP]  | inst_to_nxt[`BIC] ;
+
+wire        alu_inc       = inst_to_nxt[`SUB]  | inst_to_nxt[`CMP];
+
+wire        alu_inc_c     = inst_to_nxt[`ADDC] | inst_to_nxt[`DADD] |
+                            inst_to_nxt[`SUBC];
+
+wire        alu_add       = inst_to_nxt[`ADD]  | inst_to_nxt[`ADDC]       |
+                            inst_to_nxt[`SUB]  | inst_to_nxt[`SUBC]       |
+                            inst_to_nxt[`CMP]  | inst_type_nxt[`INST_JMP] |
+                            inst_so_nxt[`RETI];
+
+wire        alu_and       = inst_to_nxt[`AND]  | inst_to_nxt[`BIC]  |
+                            inst_to_nxt[`BIT];
+
+wire        alu_or        = inst_to_nxt[`BIS];
+
+wire        alu_xor       = inst_to_nxt[`XOR];
+
+wire        alu_dadd      = inst_to_nxt[`DADD];
+
+wire        alu_stat_7    = inst_to_nxt[`BIT]  | inst_to_nxt[`AND]  |
+                            inst_so_nxt[`SXT];
+
+wire        alu_stat_f    = inst_to_nxt[`ADD]  | inst_to_nxt[`ADDC] |
+                            inst_to_nxt[`SUB]  | inst_to_nxt[`SUBC] |
+                            inst_to_nxt[`CMP]  | inst_to_nxt[`DADD] |
+                            inst_to_nxt[`BIT]  | inst_to_nxt[`XOR]  |
+                            inst_to_nxt[`AND]  |
+                            inst_so_nxt[`RRC]  | inst_so_nxt[`RRA]  |
+                            inst_so_nxt[`SXT];
+
+wire        alu_shift     = inst_so_nxt[`RRC]  | inst_so_nxt[`RRA];
+
+wire        exec_no_wr    = inst_to_nxt[`CMP] | inst_to_nxt[`BIT];
+
+wire [11:0] inst_alu_nxt  = {exec_no_wr,
+                             alu_shift,
+                             alu_stat_f,
+                             alu_stat_7,
+                             alu_dadd,
+                             alu_xor,
+                             alu_or,
+                             alu_and,
+                             alu_add,
+                             alu_inc_c,
+                             alu_inc,
+                             alu_src_inv};
+
+always @(posedge mclk_decode or posedge puc_rst)
+  if (puc_rst)     inst_alu <= 12'h000;
+`ifdef CLOCK_GATING
+  else             inst_alu <= inst_alu_nxt;
+`else
+  else if (decode) inst_alu <= inst_alu_nxt;
+`endif
+
+
+endmodule // omsp_frontend
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
diff --git a/tests/openmsp430/rtl/omsp_mem_backbone.v b/tests/openmsp430/rtl/omsp_mem_backbone.v
new file mode 100644 (file)
index 0000000..299cbff
--- /dev/null
@@ -0,0 +1,275 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_mem_backbone.v
+// 
+// *Module Description:
+//                       Memory interface backbone (decoder + arbiter)
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 151 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2012-07-23 00:24:11 +0200 (Mon, 23 Jul 2012) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module  omsp_mem_backbone (
+
+// OUTPUTs
+    dbg_mem_din,                    // Debug unit Memory data input
+    dmem_addr,                      // Data Memory address
+    dmem_cen,                       // Data Memory chip enable (low active)
+    dmem_din,                       // Data Memory data input
+    dmem_wen,                       // Data Memory write enable (low active)
+    eu_mdb_in,                      // Execution Unit Memory data bus input
+    fe_mdb_in,                      // Frontend Memory data bus input
+    fe_pmem_wait,                   // Frontend wait for Instruction fetch
+    per_addr,                       // Peripheral address
+    per_din,                        // Peripheral data input
+    per_we,                         // Peripheral write enable (high active)
+    per_en,                         // Peripheral enable (high active)
+    pmem_addr,                      // Program Memory address
+    pmem_cen,                       // Program Memory chip enable (low active)
+    pmem_din,                       // Program Memory data input (optional)
+    pmem_wen,                       // Program Memory write enable (low active) (optional)
+
+// INPUTs
+    dbg_halt_st,                    // Halt/Run status from CPU
+    dbg_mem_addr,                   // Debug address for rd/wr access
+    dbg_mem_dout,                   // Debug unit data output
+    dbg_mem_en,                     // Debug unit memory enable
+    dbg_mem_wr,                     // Debug unit memory write
+    dmem_dout,                      // Data Memory data output
+    eu_mab,                         // Execution Unit Memory address bus
+    eu_mb_en,                       // Execution Unit Memory bus enable
+    eu_mb_wr,                       // Execution Unit Memory bus write transfer
+    eu_mdb_out,                     // Execution Unit Memory data bus output
+    fe_mab,                         // Frontend Memory address bus
+    fe_mb_en,                       // Frontend Memory bus enable
+    mclk,                           // Main system clock
+    per_dout,                       // Peripheral data output
+    pmem_dout,                      // Program Memory data output
+    puc_rst,                        // Main system reset
+    scan_enable                     // Scan enable (active during scan shifting)
+);
+
+// OUTPUTs
+//=========
+output        [15:0] dbg_mem_din;   // Debug unit Memory data input
+output [`DMEM_MSB:0] dmem_addr;     // Data Memory address
+output               dmem_cen;      // Data Memory chip enable (low active)
+output        [15:0] dmem_din;      // Data Memory data input
+output         [1:0] dmem_wen;      // Data Memory write enable (low active)
+output        [15:0] eu_mdb_in;     // Execution Unit Memory data bus input
+output        [15:0] fe_mdb_in;     // Frontend Memory data bus input
+output               fe_pmem_wait;  // Frontend wait for Instruction fetch
+output        [13:0] per_addr;      // Peripheral address
+output        [15:0] per_din;       // Peripheral data input
+output         [1:0] per_we;        // Peripheral write enable (high active)
+output               per_en;        // Peripheral enable (high active)
+output [`PMEM_MSB:0] pmem_addr;     // Program Memory address
+output               pmem_cen;      // Program Memory chip enable (low active)
+output        [15:0] pmem_din;      // Program Memory data input (optional)
+output         [1:0] pmem_wen;      // Program Memory write enable (low active) (optional)
+
+// INPUTs
+//=========
+input                dbg_halt_st;   // Halt/Run status from CPU
+input         [15:0] dbg_mem_addr;  // Debug address for rd/wr access
+input         [15:0] dbg_mem_dout;  // Debug unit data output
+input                dbg_mem_en;    // Debug unit memory enable
+input          [1:0] dbg_mem_wr;    // Debug unit memory write
+input         [15:0] dmem_dout;     // Data Memory data output
+input         [14:0] eu_mab;        // Execution Unit Memory address bus
+input                eu_mb_en;      // Execution Unit Memory bus enable
+input          [1:0] eu_mb_wr;      // Execution Unit Memory bus write transfer
+input         [15:0] eu_mdb_out;    // Execution Unit Memory data bus output
+input         [14:0] fe_mab;        // Frontend Memory address bus
+input                fe_mb_en;      // Frontend Memory bus enable
+input                mclk;          // Main system clock
+input         [15:0] per_dout;      // Peripheral data output
+input         [15:0] pmem_dout;     // Program Memory data output
+input                puc_rst;       // Main system reset
+input                scan_enable;   // Scan enable (active during scan shifting)
+
+
+//=============================================================================
+// 1)  DECODER
+//=============================================================================
+
+// RAM Interface
+//------------------
+
+// Execution unit access
+wire               eu_dmem_cen   = ~(eu_mb_en & (eu_mab>=(`DMEM_BASE>>1)) &
+                                                (eu_mab<((`DMEM_BASE+`DMEM_SIZE)>>1)));
+wire        [15:0] eu_dmem_addr  = {1'b0, eu_mab}-(`DMEM_BASE>>1);
+
+// Debug interface access
+wire               dbg_dmem_cen  = ~(dbg_mem_en & (dbg_mem_addr[15:1]>=(`DMEM_BASE>>1)) &
+                                                  (dbg_mem_addr[15:1]<((`DMEM_BASE+`DMEM_SIZE)>>1)));
+wire        [15:0] dbg_dmem_addr = {1'b0, dbg_mem_addr[15:1]}-(`DMEM_BASE>>1);
+
+   
+// RAM Interface
+wire [`DMEM_MSB:0] dmem_addr     = ~dbg_dmem_cen ? dbg_dmem_addr[`DMEM_MSB:0] : eu_dmem_addr[`DMEM_MSB:0];
+wire               dmem_cen      =  dbg_dmem_cen & eu_dmem_cen;
+wire         [1:0] dmem_wen      = ~(dbg_mem_wr | eu_mb_wr);
+wire        [15:0] dmem_din      = ~dbg_dmem_cen ? dbg_mem_dout : eu_mdb_out;
+
+
+// ROM Interface
+//------------------
+parameter          PMEM_OFFSET   = (16'hFFFF-`PMEM_SIZE+1);
+
+// Execution unit access (only read access are accepted)
+wire               eu_pmem_cen   = ~(eu_mb_en & ~|eu_mb_wr & (eu_mab>=(PMEM_OFFSET>>1)));
+wire        [15:0] eu_pmem_addr  = eu_mab-(PMEM_OFFSET>>1);
+
+// Front-end access
+wire               fe_pmem_cen   = ~(fe_mb_en & (fe_mab>=(PMEM_OFFSET>>1)));
+wire        [15:0] fe_pmem_addr  = fe_mab-(PMEM_OFFSET>>1);
+
+// Debug interface access
+wire               dbg_pmem_cen  = ~(dbg_mem_en & (dbg_mem_addr[15:1]>=(PMEM_OFFSET>>1)));
+wire        [15:0] dbg_pmem_addr = {1'b0, dbg_mem_addr[15:1]}-(PMEM_OFFSET>>1);
+
+   
+// ROM Interface (Execution unit has priority)
+wire [`PMEM_MSB:0] pmem_addr     = ~dbg_pmem_cen ? dbg_pmem_addr[`PMEM_MSB:0] :
+                                   ~eu_pmem_cen  ? eu_pmem_addr[`PMEM_MSB:0]  : fe_pmem_addr[`PMEM_MSB:0];
+wire               pmem_cen      =  fe_pmem_cen & eu_pmem_cen & dbg_pmem_cen;
+wire         [1:0] pmem_wen      = ~dbg_mem_wr;
+wire        [15:0] pmem_din      =  dbg_mem_dout;
+
+wire               fe_pmem_wait  = (~fe_pmem_cen & ~eu_pmem_cen);
+
+
+// Peripherals
+//--------------------
+wire              dbg_per_en   =  dbg_mem_en & (dbg_mem_addr[15:1]<(`PER_SIZE>>1));
+wire              eu_per_en    =  eu_mb_en   & (eu_mab<(`PER_SIZE>>1));
+
+wire       [15:0] per_din      =  dbg_mem_en ? dbg_mem_dout               : eu_mdb_out;
+wire        [1:0] per_we       =  dbg_mem_en ? dbg_mem_wr                 : eu_mb_wr;
+wire              per_en       =  dbg_mem_en ? dbg_per_en                 : eu_per_en;
+wire [`PER_MSB:0] per_addr_mux =  dbg_mem_en ? dbg_mem_addr[`PER_MSB+1:1] : eu_mab[`PER_MSB:0];
+wire       [14:0] per_addr_ful =  {{15-`PER_AWIDTH{1'b0}}, per_addr_mux};
+wire       [13:0] per_addr     =   per_addr_ful[13:0];
+
+reg   [15:0] per_dout_val;
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst)  per_dout_val <= 16'h0000;
+  else          per_dout_val <= per_dout;
+
+
+// Frontend data Mux
+//---------------------------------
+// Whenever the frontend doesn't access the ROM,  backup the data
+
+// Detect whenever the data should be backuped and restored
+reg        fe_pmem_cen_dly;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst) fe_pmem_cen_dly <=  1'b0;
+  else         fe_pmem_cen_dly <=  fe_pmem_cen;
+
+wire fe_pmem_save    = ( fe_pmem_cen & ~fe_pmem_cen_dly) & ~dbg_halt_st;
+wire fe_pmem_restore = (~fe_pmem_cen &  fe_pmem_cen_dly) |  dbg_halt_st;
+
+`ifdef CLOCK_GATING
+wire mclk_bckup;
+omsp_clock_gate clock_gate_bckup (.gclk(mclk_bckup),
+                                  .clk (mclk), .enable(fe_pmem_save), .scan_enable(scan_enable));
+`else
+wire mclk_bckup = mclk;
+`endif
+   
+reg  [15:0] pmem_dout_bckup;
+always @(posedge mclk_bckup or posedge puc_rst)
+  if (puc_rst)           pmem_dout_bckup     <=  16'h0000;
+`ifdef CLOCK_GATING
+  else                   pmem_dout_bckup     <=  pmem_dout;
+`else
+  else if (fe_pmem_save) pmem_dout_bckup     <=  pmem_dout;
+`endif
+
+// Mux between the ROM data and the backup
+reg         pmem_dout_bckup_sel;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)              pmem_dout_bckup_sel <=  1'b0;
+  else if (fe_pmem_save)    pmem_dout_bckup_sel <=  1'b1;
+  else if (fe_pmem_restore) pmem_dout_bckup_sel <=  1'b0;
+    
+assign fe_mdb_in = pmem_dout_bckup_sel ? pmem_dout_bckup : pmem_dout;
+
+
+// Execution-Unit data Mux
+//---------------------------------
+
+// Select between peripherals, RAM and ROM
+reg [1:0] eu_mdb_in_sel;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)  eu_mdb_in_sel <= 2'b00;
+  else          eu_mdb_in_sel <= {~eu_pmem_cen, per_en};
+
+// Mux
+assign      eu_mdb_in      = eu_mdb_in_sel[1] ? pmem_dout    :
+                             eu_mdb_in_sel[0] ? per_dout_val : dmem_dout;
+
+// Debug interface  data Mux
+//---------------------------------
+
+// Select between peripherals, RAM and ROM
+`ifdef DBG_EN
+reg   [1:0] dbg_mem_din_sel;
+always @(posedge mclk or posedge puc_rst)
+  if (puc_rst)  dbg_mem_din_sel <= 2'b00;
+  else          dbg_mem_din_sel <= {~dbg_pmem_cen, dbg_per_en};
+
+`else
+wire  [1:0] dbg_mem_din_sel  = 2'b00;
+`endif
+       
+// Mux
+assign      dbg_mem_din  = dbg_mem_din_sel[1] ? pmem_dout    :
+                           dbg_mem_din_sel[0] ? per_dout_val : dmem_dout;
+
+   
+endmodule // omsp_mem_backbone
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
diff --git a/tests/openmsp430/rtl/omsp_multiplier.v b/tests/openmsp430/rtl/omsp_multiplier.v
new file mode 100644 (file)
index 0000000..4f7b04c
--- /dev/null
@@ -0,0 +1,420 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_multiplier.v
+// 
+// *Module Description:
+//                       16x16 Hardware multiplier.
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 23 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2009-08-30 18:39:26 +0200 (Sun, 30 Aug 2009) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module  omsp_multiplier (
+
+// OUTPUTs
+    per_dout,                       // Peripheral data output
+
+// INPUTs
+    mclk,                           // Main system clock
+    per_addr,                       // Peripheral address
+    per_din,                        // Peripheral data input
+    per_en,                         // Peripheral enable (high active)
+    per_we,                         // Peripheral write enable (high active)
+    puc_rst,                        // Main system reset
+    scan_enable                     // Scan enable (active during scan shifting)
+);
+
+// OUTPUTs
+//=========
+output       [15:0] per_dout;       // Peripheral data output
+
+// INPUTs
+//=========
+input               mclk;           // Main system clock
+input        [13:0] per_addr;       // Peripheral address
+input        [15:0] per_din;        // Peripheral data input
+input               per_en;         // Peripheral enable (high active)
+input         [1:0] per_we;         // Peripheral write enable (high active)
+input               puc_rst;        // Main system reset
+input               scan_enable;    // Scan enable (active during scan shifting)
+
+
+//=============================================================================
+// 1)  PARAMETER/REGISTERS & WIRE DECLARATION
+//=============================================================================
+
+// Register base address (must be aligned to decoder bit width)
+parameter       [14:0] BASE_ADDR   = 15'h0130;
+
+// Decoder bit width (defines how many bits are considered for address decoding)
+parameter              DEC_WD      =  4;
+
+// Register addresses offset
+parameter [DEC_WD-1:0] OP1_MPY     = 'h0,
+                       OP1_MPYS    = 'h2,
+                       OP1_MAC     = 'h4,
+                       OP1_MACS    = 'h6,
+                       OP2         = 'h8,
+                       RESLO       = 'hA,
+                       RESHI       = 'hC,
+                       SUMEXT      = 'hE;
+
+// Register one-hot decoder utilities
+parameter              DEC_SZ      =  (1 << DEC_WD);
+parameter [DEC_SZ-1:0] BASE_REG    =  {{DEC_SZ-1{1'b0}}, 1'b1};
+
+// Register one-hot decoder
+parameter [DEC_SZ-1:0] OP1_MPY_D   = (BASE_REG << OP1_MPY),
+                       OP1_MPYS_D  = (BASE_REG << OP1_MPYS),
+                       OP1_MAC_D   = (BASE_REG << OP1_MAC),
+                       OP1_MACS_D  = (BASE_REG << OP1_MACS),
+                       OP2_D       = (BASE_REG << OP2),
+                       RESLO_D     = (BASE_REG << RESLO),
+                       RESHI_D     = (BASE_REG << RESHI),
+                       SUMEXT_D    = (BASE_REG << SUMEXT);
+
+
+// Wire pre-declarations
+wire  result_wr;
+wire  result_clr;
+wire  early_read;
+
+
+//============================================================================
+// 2)  REGISTER DECODER
+//============================================================================
+
+// Local register selection
+wire              reg_sel   =  per_en & (per_addr[13:DEC_WD-1]==BASE_ADDR[14:DEC_WD]);
+
+// Register local address
+wire [DEC_WD-1:0] reg_addr  =  {per_addr[DEC_WD-2:0], 1'b0};
+
+// Register address decode
+wire [DEC_SZ-1:0] reg_dec   =  (OP1_MPY_D   &  {DEC_SZ{(reg_addr == OP1_MPY  )}})  |
+                               (OP1_MPYS_D  &  {DEC_SZ{(reg_addr == OP1_MPYS )}})  |
+                               (OP1_MAC_D   &  {DEC_SZ{(reg_addr == OP1_MAC  )}})  |
+                               (OP1_MACS_D  &  {DEC_SZ{(reg_addr == OP1_MACS )}})  |
+                               (OP2_D       &  {DEC_SZ{(reg_addr == OP2      )}})  |
+                               (RESLO_D     &  {DEC_SZ{(reg_addr == RESLO    )}})  |
+                               (RESHI_D     &  {DEC_SZ{(reg_addr == RESHI    )}})  |
+                               (SUMEXT_D    &  {DEC_SZ{(reg_addr == SUMEXT   )}});
+                  
+// Read/Write probes
+wire              reg_write =  |per_we & reg_sel;
+wire              reg_read  = ~|per_we & reg_sel;
+
+// Read/Write vectors
+wire [DEC_SZ-1:0] reg_wr    = reg_dec & {DEC_SZ{reg_write}};
+wire [DEC_SZ-1:0] reg_rd    = reg_dec & {DEC_SZ{reg_read}};
+
+
+//============================================================================
+// 3) REGISTERS
+//============================================================================
+
+// OP1 Register
+//-----------------   
+reg  [15:0] op1;
+
+wire        op1_wr = reg_wr[OP1_MPY]  |
+                     reg_wr[OP1_MPYS] |
+                     reg_wr[OP1_MAC]  |
+                     reg_wr[OP1_MACS];
+
+`ifdef CLOCK_GATING
+wire        mclk_op1;
+omsp_clock_gate clock_gate_op1 (.gclk(mclk_op1),
+                                .clk (mclk), .enable(op1_wr), .scan_enable(scan_enable));
+`else
+wire        mclk_op1 = mclk;
+`endif
+
+always @ (posedge mclk_op1 or posedge puc_rst)
+  if (puc_rst)      op1 <=  16'h0000;
+`ifdef CLOCK_GATING
+  else              op1 <=  per_din;
+`else
+  else if (op1_wr)  op1 <=  per_din;
+`endif
+
+wire [15:0] op1_rd  = op1;
+
+   
+// OP2 Register
+//-----------------   
+reg  [15:0] op2;
+
+wire        op2_wr = reg_wr[OP2];
+
+`ifdef CLOCK_GATING
+wire        mclk_op2;
+omsp_clock_gate clock_gate_op2 (.gclk(mclk_op2),
+                                .clk (mclk), .enable(op2_wr), .scan_enable(scan_enable));
+`else
+wire        mclk_op2 = mclk;
+`endif
+
+always @ (posedge mclk_op2 or posedge puc_rst)
+  if (puc_rst)      op2 <=  16'h0000;
+`ifdef CLOCK_GATING
+  else              op2 <=  per_din;
+`else
+  else if (op2_wr)  op2 <=  per_din;
+`endif
+
+wire [15:0] op2_rd  = op2;
+
+   
+// RESLO Register
+//-----------------   
+reg  [15:0] reslo;
+
+wire [15:0] reslo_nxt;
+wire        reslo_wr = reg_wr[RESLO];
+
+`ifdef CLOCK_GATING
+wire        reslo_en = reslo_wr | result_clr | result_wr;
+wire        mclk_reslo;
+omsp_clock_gate clock_gate_reslo (.gclk(mclk_reslo),
+                                  .clk (mclk), .enable(reslo_en), .scan_enable(scan_enable));
+`else
+wire        mclk_reslo = mclk;
+`endif
+
+always @ (posedge mclk_reslo or posedge puc_rst)
+  if (puc_rst)         reslo <=  16'h0000;
+  else if (reslo_wr)   reslo <=  per_din;
+  else if (result_clr) reslo <=  16'h0000;
+`ifdef CLOCK_GATING
+  else                 reslo <=  reslo_nxt;
+`else
+  else if (result_wr)  reslo <=  reslo_nxt;
+`endif
+
+wire [15:0] reslo_rd = early_read ? reslo_nxt : reslo;
+
+
+// RESHI Register
+//-----------------   
+reg  [15:0] reshi;
+
+wire [15:0] reshi_nxt;
+wire        reshi_wr = reg_wr[RESHI];
+
+`ifdef CLOCK_GATING
+wire        reshi_en = reshi_wr | result_clr | result_wr;
+wire        mclk_reshi;
+omsp_clock_gate clock_gate_reshi (.gclk(mclk_reshi),
+                                  .clk (mclk), .enable(reshi_en), .scan_enable(scan_enable));
+`else
+wire        mclk_reshi = mclk;
+`endif
+
+always @ (posedge mclk_reshi or posedge puc_rst)
+  if (puc_rst)         reshi <=  16'h0000;
+  else if (reshi_wr)   reshi <=  per_din;
+  else if (result_clr) reshi <=  16'h0000;
+`ifdef CLOCK_GATING
+  else                 reshi <=  reshi_nxt;
+`else
+  else if (result_wr)  reshi <=  reshi_nxt;
+`endif
+
+wire [15:0] reshi_rd = early_read ? reshi_nxt  : reshi;
+
+// SUMEXT Register
+//-----------------   
+reg  [1:0] sumext_s;
+
+wire [1:0] sumext_s_nxt;
+
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst)         sumext_s <=  2'b00;
+  else if (op2_wr)     sumext_s <=  2'b00;
+  else if (result_wr)  sumext_s <=  sumext_s_nxt;
+
+wire [15:0] sumext_nxt = {{14{sumext_s_nxt[1]}}, sumext_s_nxt};
+wire [15:0] sumext     = {{14{sumext_s[1]}},     sumext_s};
+wire [15:0] sumext_rd  = early_read ? sumext_nxt : sumext;
+
+
+//============================================================================
+// 4) DATA OUTPUT GENERATION
+//============================================================================
+
+// Data output mux
+wire [15:0] op1_mux    = op1_rd     & {16{reg_rd[OP1_MPY]  |
+                                          reg_rd[OP1_MPYS] |
+                                          reg_rd[OP1_MAC]  |
+                                          reg_rd[OP1_MACS]}};
+wire [15:0] op2_mux    = op2_rd     & {16{reg_rd[OP2]}};
+wire [15:0] reslo_mux  = reslo_rd   & {16{reg_rd[RESLO]}};
+wire [15:0] reshi_mux  = reshi_rd   & {16{reg_rd[RESHI]}};
+wire [15:0] sumext_mux = sumext_rd  & {16{reg_rd[SUMEXT]}};
+
+wire [15:0] per_dout   = op1_mux    |
+                         op2_mux    |
+                         reslo_mux  |
+                         reshi_mux  |
+                         sumext_mux;
+
+
+//============================================================================
+// 5) HARDWARE MULTIPLIER FUNCTIONAL LOGIC
+//============================================================================
+
+// Multiplier configuration
+//--------------------------
+
+// Detect signed mode
+reg sign_sel;
+always @ (posedge mclk_op1 or posedge puc_rst)
+  if (puc_rst)     sign_sel <=  1'b0;
+`ifdef CLOCK_GATING
+  else             sign_sel <=  reg_wr[OP1_MPYS] | reg_wr[OP1_MACS];
+`else
+  else if (op1_wr) sign_sel <=  reg_wr[OP1_MPYS] | reg_wr[OP1_MACS];
+`endif
+
+
+// Detect accumulate mode
+reg acc_sel;
+always @ (posedge mclk_op1 or posedge puc_rst)
+  if (puc_rst)     acc_sel  <=  1'b0;
+`ifdef CLOCK_GATING
+  else             acc_sel  <=  reg_wr[OP1_MAC]  | reg_wr[OP1_MACS];
+`else
+  else if (op1_wr) acc_sel  <=  reg_wr[OP1_MAC]  | reg_wr[OP1_MACS];
+`endif
+
+
+// Detect whenever the RESHI and RESLO registers should be cleared
+assign      result_clr = op2_wr & ~acc_sel;
+
+// Combine RESHI & RESLO 
+wire [31:0] result     = {reshi, reslo};
+
+   
+// 16x16 Multiplier (result computed in 1 clock cycle)
+//-----------------------------------------------------
+`ifdef MPY_16x16
+
+// Detect start of a multiplication
+reg cycle;
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst) cycle <=  1'b0;
+  else         cycle <=  op2_wr;
+
+assign result_wr = cycle;
+
+// Expand the operands to support signed & unsigned operations
+wire signed [16:0] op1_xp = {sign_sel & op1[15], op1};
+wire signed [16:0] op2_xp = {sign_sel & op2[15], op2};
+
+
+// 17x17 signed multiplication
+wire signed [33:0] product = op1_xp * op2_xp;
+
+// Accumulate
+wire [32:0] result_nxt = {1'b0, result} + {1'b0, product[31:0]};
+
+
+// Next register values
+assign reslo_nxt    = result_nxt[15:0];
+assign reshi_nxt    = result_nxt[31:16];
+assign sumext_s_nxt =  sign_sel ? {2{result_nxt[31]}} :
+                                  {1'b0, result_nxt[32]};
+
+
+// Since the MAC is completed within 1 clock cycle,
+// an early read can't happen.
+assign early_read   = 1'b0;
+
+
+// 16x8 Multiplier (result computed in 2 clock cycles)
+//-----------------------------------------------------
+`else
+  
+// Detect start of a multiplication
+reg [1:0] cycle;
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst) cycle <=  2'b00;
+  else         cycle <=  {cycle[0], op2_wr};
+
+assign result_wr = |cycle;
+
+
+// Expand the operands to support signed & unsigned operations
+wire signed [16:0] op1_xp    = {sign_sel & op1[15], op1};
+wire signed  [8:0] op2_hi_xp = {sign_sel & op2[15], op2[15:8]};
+wire signed  [8:0] op2_lo_xp = {              1'b0, op2[7:0]};
+wire signed  [8:0] op2_xp    = cycle[0] ? op2_hi_xp : op2_lo_xp;
+
+     
+// 17x9 signed multiplication
+wire signed [25:0] product    = op1_xp * op2_xp;
+
+wire        [31:0] product_xp = cycle[0] ? {product[23:0], 8'h00} :
+                                           {{8{sign_sel & product[23]}}, product[23:0]};
+   
+// Accumulate
+wire [32:0] result_nxt  = {1'b0, result} + {1'b0, product_xp[31:0]};
+
+
+// Next register values
+assign reslo_nxt    = result_nxt[15:0];
+assign reshi_nxt    = result_nxt[31:16];
+assign sumext_s_nxt =  sign_sel ? {2{result_nxt[31]}} :
+                                  {1'b0, result_nxt[32] | sumext_s[0]};
+
+// Since the MAC is completed within 2 clock cycle,
+// an early read can happen during the second cycle.
+assign early_read   = cycle[1];
+
+`endif
+
+
+endmodule // omsp_multiplier
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
diff --git a/tests/openmsp430/rtl/omsp_register_file.v b/tests/openmsp430/rtl/omsp_register_file.v
new file mode 100644 (file)
index 0000000..2ccd249
--- /dev/null
@@ -0,0 +1,618 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_register_file.v
+// 
+// *Module Description:
+//                       openMSP430 Register files
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 134 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2012-03-22 21:31:06 +0100 (Thu, 22 Mar 2012) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module  omsp_register_file (
+
+// OUTPUTs
+    cpuoff,                       // Turns off the CPU
+    gie,                          // General interrupt enable
+    oscoff,                       // Turns off LFXT1 clock input
+    pc_sw,                        // Program counter software value
+    pc_sw_wr,                     // Program counter software write
+    reg_dest,                     // Selected register destination content
+    reg_src,                      // Selected register source content
+    scg0,                         // System clock generator 1. Turns off the DCO
+    scg1,                         // System clock generator 1. Turns off the SMCLK
+    status,                       // R2 Status {V,N,Z,C}
+
+// INPUTs
+    alu_stat,                     // ALU Status {V,N,Z,C}
+    alu_stat_wr,                  // ALU Status write {V,N,Z,C}
+    inst_bw,                      // Decoded Inst: byte width
+    inst_dest,                    // Register destination selection
+    inst_src,                     // Register source selection
+    mclk,                         // Main system clock
+    pc,                           // Program counter
+    puc_rst,                      // Main system reset
+    reg_dest_val,                 // Selected register destination value
+    reg_dest_wr,                  // Write selected register destination
+    reg_pc_call,                  // Trigger PC update for a CALL instruction
+    reg_sp_val,                   // Stack Pointer next value
+    reg_sp_wr,                    // Stack Pointer write
+    reg_sr_wr,                    // Status register update for RETI instruction
+    reg_sr_clr,                   // Status register clear for interrupts
+    reg_incr,                     // Increment source register
+    scan_enable                   // Scan enable (active during scan shifting)
+);
+
+// OUTPUTs
+//=========
+output                     cpuoff;       // Turns off the CPU
+output                     gie;          // General interrupt enable
+output                     oscoff;       // Turns off LFXT1 clock input
+output       [15:0] pc_sw;        // Program counter software value
+output              pc_sw_wr;     // Program counter software write
+output       [15:0] reg_dest;     // Selected register destination content
+output       [15:0] reg_src;      // Selected register source content
+output              scg0;         // System clock generator 1. Turns off the DCO
+output              scg1;         // System clock generator 1. Turns off the SMCLK
+output        [3:0] status;       // R2 Status {V,N,Z,C}
+
+// INPUTs
+//=========
+input         [3:0] alu_stat;     // ALU Status {V,N,Z,C}
+input         [3:0] alu_stat_wr;  // ALU Status write {V,N,Z,C}
+input               inst_bw;      // Decoded Inst: byte width
+input        [15:0] inst_dest;    // Register destination selection
+input        [15:0] inst_src;     // Register source selection
+input               mclk;         // Main system clock
+input        [15:0] pc;           // Program counter
+input               puc_rst;      // Main system reset
+input        [15:0] reg_dest_val; // Selected register destination value
+input               reg_dest_wr;  // Write selected register destination
+input               reg_pc_call;  // Trigger PC update for a CALL instruction
+input        [15:0] reg_sp_val;   // Stack Pointer next value
+input               reg_sp_wr;    // Stack Pointer write
+input               reg_sr_wr;    // Status register update for RETI instruction
+input               reg_sr_clr;   // Status register clear for interrupts
+input               reg_incr;     // Increment source register
+input               scan_enable;  // Scan enable (active during scan shifting)
+
+
+//=============================================================================
+// 1)  AUTOINCREMENT UNIT
+//=============================================================================
+
+wire [15:0] inst_src_in;
+wire [15:0] incr_op         = (inst_bw & ~inst_src_in[1]) ? 16'h0001 : 16'h0002;
+wire [15:0] reg_incr_val    = reg_src+incr_op;
+
+wire [15:0] reg_dest_val_in = inst_bw ? {8'h00,reg_dest_val[7:0]} : reg_dest_val;
+
+
+//=============================================================================
+// 2)  SPECIAL REGISTERS (R1/R2/R3)
+//=============================================================================
+
+// Source input selection mask (for interrupt support)
+//-----------------------------------------------------
+
+assign inst_src_in = reg_sr_clr ? 16'h0004 : inst_src;
+
+
+// R0: Program counter
+//---------------------
+
+wire [15:0] r0       = pc;
+
+wire [15:0] pc_sw    = reg_dest_val_in;
+wire        pc_sw_wr = (inst_dest[0] & reg_dest_wr) | reg_pc_call;
+
+
+// R1: Stack pointer
+//-------------------
+reg [15:0] r1;
+wire       r1_wr  = inst_dest[1] & reg_dest_wr;
+wire       r1_inc = inst_src_in[1]  & reg_incr;
+
+`ifdef CLOCK_GATING
+wire       r1_en  = r1_wr | reg_sp_wr | r1_inc;
+wire       mclk_r1;
+omsp_clock_gate clock_gate_r1 (.gclk(mclk_r1),
+                               .clk (mclk), .enable(r1_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r1 = mclk;
+`endif
+
+always @(posedge mclk_r1 or posedge puc_rst)
+  if (puc_rst)        r1 <= 16'h0000;
+  else if (r1_wr)     r1 <= reg_dest_val_in & 16'hfffe;
+  else if (reg_sp_wr) r1 <= reg_sp_val      & 16'hfffe;
+`ifdef CLOCK_GATING
+  else                r1 <= reg_incr_val    & 16'hfffe;
+`else
+  else if (r1_inc)    r1 <= reg_incr_val    & 16'hfffe;
+`endif
+
+
+// R2: Status register
+//---------------------
+reg  [15:0] r2;
+wire        r2_wr  = (inst_dest[2] & reg_dest_wr) | reg_sr_wr;
+
+`ifdef CLOCK_GATING                                                              //      -- WITH CLOCK GATING --
+wire        r2_c   = alu_stat_wr[0] ? alu_stat[0]          : reg_dest_val_in[0]; // C
+
+wire        r2_z   = alu_stat_wr[1] ? alu_stat[1]          : reg_dest_val_in[1]; // Z
+
+wire        r2_n   = alu_stat_wr[2] ? alu_stat[2]          : reg_dest_val_in[2]; // N
+
+wire  [7:3] r2_nxt = r2_wr          ? reg_dest_val_in[7:3] : r2[7:3];
+
+wire        r2_v   = alu_stat_wr[3] ? alu_stat[3]          : reg_dest_val_in[8]; // V
+
+wire        r2_en  = |alu_stat_wr | r2_wr | reg_sr_clr;
+wire        mclk_r2;
+omsp_clock_gate clock_gate_r2 (.gclk(mclk_r2),
+                               .clk (mclk), .enable(r2_en), .scan_enable(scan_enable));
+
+`else                                                                            //      -- WITHOUT CLOCK GATING --
+wire        r2_c   = alu_stat_wr[0] ? alu_stat[0]          :
+                     r2_wr          ? reg_dest_val_in[0]   : r2[0];              // C
+
+wire        r2_z   = alu_stat_wr[1] ? alu_stat[1]          :
+                     r2_wr          ? reg_dest_val_in[1]   : r2[1];              // Z
+
+wire        r2_n   = alu_stat_wr[2] ? alu_stat[2]          :
+                     r2_wr          ? reg_dest_val_in[2]   : r2[2];              // N
+
+wire  [7:3] r2_nxt = r2_wr          ? reg_dest_val_in[7:3] : r2[7:3];
+
+wire        r2_v   = alu_stat_wr[3] ? alu_stat[3]          :
+                     r2_wr          ? reg_dest_val_in[8]   : r2[8];              // V
+
+
+wire        mclk_r2 = mclk;
+`endif
+
+`ifdef ASIC
+   `ifdef CPUOFF_EN
+   wire [15:0] cpuoff_mask = 16'h0010;
+   `else
+   wire [15:0] cpuoff_mask = 16'h0000;
+   `endif
+   `ifdef OSCOFF_EN
+   wire [15:0] oscoff_mask = 16'h0020;
+   `else
+   wire [15:0] oscoff_mask = 16'h0000;
+   `endif
+   `ifdef SCG0_EN
+   wire [15:0] scg0_mask   = 16'h0040;
+   `else
+   wire [15:0] scg0_mask   = 16'h0000;
+   `endif
+   `ifdef SCG1_EN
+   wire [15:0] scg1_mask   = 16'h0080;
+   `else
+   wire [15:0] scg1_mask   = 16'h0000;
+   `endif
+`else
+   wire [15:0] cpuoff_mask = 16'h0010; // For the FPGA version: - the CPUOFF mode is emulated
+   wire [15:0] oscoff_mask = 16'h0020; //                       - the SCG1 mode is emulated
+   wire [15:0] scg0_mask   = 16'h0000; //                       - the SCG0 is not supported
+   wire [15:0] scg1_mask   = 16'h0080; //                       - the SCG1 mode is emulated
+`endif
+   
+   wire [15:0] r2_mask     = cpuoff_mask | oscoff_mask | scg0_mask | scg1_mask | 16'h010f;
+always @(posedge mclk_r2 or posedge puc_rst)
+  if (puc_rst)         r2 <= 16'h0000;
+  else if (reg_sr_clr) r2 <= 16'h0000;
+  else                 r2 <= {7'h00, r2_v, r2_nxt, r2_n, r2_z, r2_c} & r2_mask;
+
+assign status = {r2[8], r2[2:0]};
+assign gie    =  r2[3];
+assign cpuoff =  r2[4] | (r2_nxt[4] & r2_wr & cpuoff_mask[4]);
+assign oscoff =  r2[5];
+assign scg0   =  r2[6];
+assign scg1   =  r2[7];
+
+
+// R3: Constant generator
+//-------------------------------------------------------------
+// Note: the auto-increment feature is not implemented for R3
+//       because the @R3+ addressing mode is used for constant
+//       generation (#-1).
+reg [15:0] r3;
+wire       r3_wr  = inst_dest[3] & reg_dest_wr;
+
+`ifdef CLOCK_GATING
+wire       r3_en   = r3_wr;
+wire       mclk_r3;
+omsp_clock_gate clock_gate_r3 (.gclk(mclk_r3),
+                               .clk (mclk), .enable(r3_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r3 = mclk;
+`endif
+
+always @(posedge mclk_r3 or posedge puc_rst)
+  if (puc_rst)     r3 <= 16'h0000;
+`ifdef CLOCK_GATING
+  else             r3 <= reg_dest_val_in;
+`else
+  else if (r3_wr)  r3 <= reg_dest_val_in;
+`endif
+
+
+//=============================================================================
+// 4)  GENERAL PURPOSE REGISTERS (R4...R15)
+//=============================================================================
+
+// R4
+//------------
+reg [15:0] r4;
+wire       r4_wr  = inst_dest[4] & reg_dest_wr;
+wire       r4_inc = inst_src_in[4]  & reg_incr;
+
+`ifdef CLOCK_GATING
+wire       r4_en  = r4_wr | r4_inc;
+wire       mclk_r4;
+omsp_clock_gate clock_gate_r4 (.gclk(mclk_r4),
+                               .clk (mclk), .enable(r4_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r4 = mclk;
+`endif
+
+always @(posedge mclk_r4 or posedge puc_rst)
+  if (puc_rst)      r4  <= 16'h0000;
+  else if (r4_wr)   r4  <= reg_dest_val_in;
+`ifdef CLOCK_GATING
+  else              r4  <= reg_incr_val;
+`else
+  else if (r4_inc)  r4  <= reg_incr_val;
+`endif
+
+// R5
+//------------
+reg [15:0] r5;
+wire       r5_wr  = inst_dest[5] & reg_dest_wr;
+wire       r5_inc = inst_src_in[5]  & reg_incr;
+
+`ifdef CLOCK_GATING
+wire       r5_en  = r5_wr | r5_inc;
+wire       mclk_r5;
+omsp_clock_gate clock_gate_r5 (.gclk(mclk_r5),
+                               .clk (mclk), .enable(r5_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r5 = mclk;
+`endif
+
+always @(posedge mclk_r5 or posedge puc_rst)
+  if (puc_rst)      r5  <= 16'h0000;
+  else if (r5_wr)   r5  <= reg_dest_val_in;
+`ifdef CLOCK_GATING
+  else              r5  <= reg_incr_val;
+`else
+  else if (r5_inc)  r5  <= reg_incr_val;
+`endif
+
+// R6
+//------------
+reg [15:0] r6;
+wire       r6_wr  = inst_dest[6] & reg_dest_wr;
+wire       r6_inc = inst_src_in[6]  & reg_incr;
+
+`ifdef CLOCK_GATING
+wire       r6_en  = r6_wr | r6_inc;
+wire       mclk_r6;
+omsp_clock_gate clock_gate_r6 (.gclk(mclk_r6),
+                               .clk (mclk), .enable(r6_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r6 = mclk;
+`endif
+
+always @(posedge mclk_r6 or posedge puc_rst)
+  if (puc_rst)      r6  <= 16'h0000;
+  else if (r6_wr)   r6  <= reg_dest_val_in;
+`ifdef CLOCK_GATING
+  else              r6  <= reg_incr_val;
+`else
+  else if (r6_inc)  r6  <= reg_incr_val;
+`endif
+
+// R7
+//------------
+reg [15:0] r7;
+wire       r7_wr  = inst_dest[7] & reg_dest_wr;
+wire       r7_inc = inst_src_in[7]  & reg_incr;
+
+`ifdef CLOCK_GATING
+wire       r7_en  = r7_wr | r7_inc;
+wire       mclk_r7;
+omsp_clock_gate clock_gate_r7 (.gclk(mclk_r7),
+                               .clk (mclk), .enable(r7_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r7 = mclk;
+`endif
+
+always @(posedge mclk_r7 or posedge puc_rst)
+  if (puc_rst)      r7  <= 16'h0000;
+  else if (r7_wr)   r7  <= reg_dest_val_in;
+`ifdef CLOCK_GATING
+  else              r7  <= reg_incr_val;
+`else
+  else if (r7_inc)  r7  <= reg_incr_val;
+`endif
+
+// R8
+//------------
+reg [15:0] r8;
+wire       r8_wr  = inst_dest[8] & reg_dest_wr;
+wire       r8_inc = inst_src_in[8]  & reg_incr;
+
+`ifdef CLOCK_GATING
+wire       r8_en  = r8_wr | r8_inc;
+wire       mclk_r8;
+omsp_clock_gate clock_gate_r8 (.gclk(mclk_r8),
+                               .clk (mclk), .enable(r8_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r8 = mclk;
+`endif
+
+always @(posedge mclk_r8 or posedge puc_rst)
+  if (puc_rst)      r8  <= 16'h0000;
+  else if (r8_wr)   r8  <= reg_dest_val_in;
+`ifdef CLOCK_GATING
+  else              r8  <= reg_incr_val;
+`else
+  else if (r8_inc)  r8  <= reg_incr_val;
+`endif
+
+// R9
+//------------
+reg [15:0] r9;
+wire       r9_wr  = inst_dest[9] & reg_dest_wr;
+wire       r9_inc = inst_src_in[9]  & reg_incr;
+
+`ifdef CLOCK_GATING
+wire       r9_en  = r9_wr | r9_inc;
+wire       mclk_r9;
+omsp_clock_gate clock_gate_r9 (.gclk(mclk_r9),
+                               .clk (mclk), .enable(r9_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r9 = mclk;
+`endif
+
+always @(posedge mclk_r9 or posedge puc_rst)
+  if (puc_rst)      r9  <= 16'h0000;
+  else if (r9_wr)   r9  <= reg_dest_val_in;
+`ifdef CLOCK_GATING
+  else              r9  <= reg_incr_val;
+`else
+  else if (r9_inc)  r9  <= reg_incr_val;
+`endif
+
+// R10
+//------------
+reg [15:0] r10;
+wire       r10_wr  = inst_dest[10] & reg_dest_wr;
+wire       r10_inc = inst_src_in[10]  & reg_incr;
+
+`ifdef CLOCK_GATING
+wire       r10_en  = r10_wr | r10_inc;
+wire       mclk_r10;
+omsp_clock_gate clock_gate_r10 (.gclk(mclk_r10),
+                                .clk (mclk), .enable(r10_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r10 = mclk;
+`endif
+
+always @(posedge mclk_r10 or posedge puc_rst)
+  if (puc_rst)      r10 <= 16'h0000;
+  else if (r10_wr)  r10 <= reg_dest_val_in;
+`ifdef CLOCK_GATING
+  else              r10 <= reg_incr_val;
+`else
+  else if (r10_inc) r10 <= reg_incr_val;
+`endif
+
+// R11
+//------------
+reg [15:0] r11;
+wire       r11_wr  = inst_dest[11] & reg_dest_wr;
+wire       r11_inc = inst_src_in[11]  & reg_incr;
+
+`ifdef CLOCK_GATING
+wire       r11_en  = r11_wr | r11_inc;
+wire       mclk_r11;
+omsp_clock_gate clock_gate_r11 (.gclk(mclk_r11),
+                                .clk (mclk), .enable(r11_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r11 = mclk;
+`endif
+
+always @(posedge mclk_r11 or posedge puc_rst)
+  if (puc_rst)      r11 <= 16'h0000;
+  else if (r11_wr)  r11 <= reg_dest_val_in;
+`ifdef CLOCK_GATING
+  else              r11 <= reg_incr_val;
+`else
+  else if (r11_inc) r11 <= reg_incr_val;
+`endif
+
+// R12
+//------------
+reg [15:0] r12;
+wire       r12_wr  = inst_dest[12] & reg_dest_wr;
+wire       r12_inc = inst_src_in[12]  & reg_incr;
+
+`ifdef CLOCK_GATING
+wire       r12_en  = r12_wr | r12_inc;
+wire       mclk_r12;
+omsp_clock_gate clock_gate_r12 (.gclk(mclk_r12),
+                                .clk (mclk), .enable(r12_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r12 = mclk;
+`endif
+
+always @(posedge mclk_r12 or posedge puc_rst)
+  if (puc_rst)      r12 <= 16'h0000;
+  else if (r12_wr)  r12 <= reg_dest_val_in;
+`ifdef CLOCK_GATING
+  else              r12 <= reg_incr_val;
+`else
+  else if (r12_inc) r12 <= reg_incr_val;
+`endif
+
+// R13
+//------------
+reg [15:0] r13;
+wire       r13_wr  = inst_dest[13] & reg_dest_wr;
+wire       r13_inc = inst_src_in[13]  & reg_incr;
+
+`ifdef CLOCK_GATING
+wire       r13_en  = r13_wr | r13_inc;
+wire       mclk_r13;
+omsp_clock_gate clock_gate_r13 (.gclk(mclk_r13),
+                                .clk (mclk), .enable(r13_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r13 = mclk;
+`endif
+
+always @(posedge mclk_r13 or posedge puc_rst)
+  if (puc_rst)      r13 <= 16'h0000;
+  else if (r13_wr)  r13 <= reg_dest_val_in;
+`ifdef CLOCK_GATING
+  else              r13 <= reg_incr_val;
+`else
+  else if (r13_inc) r13 <= reg_incr_val;
+`endif
+
+// R14
+//------------
+reg [15:0] r14;
+wire       r14_wr  = inst_dest[14] & reg_dest_wr;
+wire       r14_inc = inst_src_in[14]  & reg_incr;
+
+`ifdef CLOCK_GATING
+wire       r14_en  = r14_wr | r14_inc;
+wire       mclk_r14;
+omsp_clock_gate clock_gate_r14 (.gclk(mclk_r14),
+                                .clk (mclk), .enable(r14_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r14 = mclk;
+`endif
+
+always @(posedge mclk_r14 or posedge puc_rst)
+  if (puc_rst)      r14 <= 16'h0000;
+  else if (r14_wr)  r14 <= reg_dest_val_in;
+`ifdef CLOCK_GATING
+  else              r14 <= reg_incr_val;
+`else
+  else if (r14_inc) r14 <= reg_incr_val;
+`endif
+
+// R15
+//------------
+reg [15:0] r15;
+wire       r15_wr  = inst_dest[15] & reg_dest_wr;
+wire       r15_inc = inst_src_in[15]  & reg_incr;
+
+`ifdef CLOCK_GATING
+wire       r15_en  = r15_wr | r15_inc;
+wire       mclk_r15;
+omsp_clock_gate clock_gate_r15 (.gclk(mclk_r15),
+                                .clk (mclk), .enable(r15_en), .scan_enable(scan_enable));
+`else
+wire       mclk_r15 = mclk;
+`endif
+
+always @(posedge mclk_r15 or posedge puc_rst)
+  if (puc_rst)      r15 <= 16'h0000;
+  else if (r15_wr)  r15 <= reg_dest_val_in;
+ `ifdef CLOCK_GATING
+  else              r15 <= reg_incr_val;
+`else
+ else if (r15_inc)  r15 <= reg_incr_val;
+`endif
+
+
+//=============================================================================
+// 5)  READ MUX
+//=============================================================================
+
+assign reg_src  = (r0      & {16{inst_src_in[0]}})   | 
+                  (r1      & {16{inst_src_in[1]}})   | 
+                  (r2      & {16{inst_src_in[2]}})   | 
+                  (r3      & {16{inst_src_in[3]}})   | 
+                  (r4      & {16{inst_src_in[4]}})   | 
+                  (r5      & {16{inst_src_in[5]}})   | 
+                  (r6      & {16{inst_src_in[6]}})   | 
+                  (r7      & {16{inst_src_in[7]}})   | 
+                  (r8      & {16{inst_src_in[8]}})   | 
+                  (r9      & {16{inst_src_in[9]}})   | 
+                  (r10     & {16{inst_src_in[10]}})  | 
+                  (r11     & {16{inst_src_in[11]}})  | 
+                  (r12     & {16{inst_src_in[12]}})  | 
+                  (r13     & {16{inst_src_in[13]}})  | 
+                  (r14     & {16{inst_src_in[14]}})  | 
+                  (r15     & {16{inst_src_in[15]}});
+
+assign reg_dest = (r0      & {16{inst_dest[0]}})  | 
+                  (r1      & {16{inst_dest[1]}})  | 
+                  (r2      & {16{inst_dest[2]}})  | 
+                  (r3      & {16{inst_dest[3]}})  | 
+                  (r4      & {16{inst_dest[4]}})  | 
+                  (r5      & {16{inst_dest[5]}})  | 
+                  (r6      & {16{inst_dest[6]}})  | 
+                  (r7      & {16{inst_dest[7]}})  | 
+                  (r8      & {16{inst_dest[8]}})  | 
+                  (r9      & {16{inst_dest[9]}})  | 
+                  (r10     & {16{inst_dest[10]}}) | 
+                  (r11     & {16{inst_dest[11]}}) | 
+                  (r12     & {16{inst_dest[12]}}) | 
+                  (r13     & {16{inst_dest[13]}}) | 
+                  (r14     & {16{inst_dest[14]}}) | 
+                  (r15     & {16{inst_dest[15]}});
+
+
+endmodule // omsp_register_file
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
diff --git a/tests/openmsp430/rtl/omsp_scan_mux.v b/tests/openmsp430/rtl/omsp_scan_mux.v
new file mode 100644 (file)
index 0000000..9a90647
--- /dev/null
@@ -0,0 +1,75 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_scan_mux.v
+// 
+// *Module Description:
+//                       Generic mux for scan mode
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 103 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $
+//----------------------------------------------------------------------------
+
+module  omsp_scan_mux (
+
+// OUTPUTs
+    data_out,                      // Scan mux data output
+
+// INPUTs
+    data_in_scan,                  // Selected data input for scan mode
+    data_in_func,                  // Selected data input for functional mode
+    scan_mode                      // Scan mode
+);
+
+// OUTPUTs
+//=========
+output              data_out;      // Scan mux data output
+
+// INPUTs
+//=========
+input               data_in_scan;  // Selected data input for scan mode
+input               data_in_func;  // Selected data input for functional mode
+input               scan_mode;     // Scan mode
+
+
+//=============================================================================
+// 1)  SCAN MUX
+//=============================================================================
+
+assign  data_out  =  scan_mode ? data_in_scan : data_in_func;
+
+
+endmodule // omsp_scan_mux
+
+
diff --git a/tests/openmsp430/rtl/omsp_sfr.v b/tests/openmsp430/rtl/omsp_sfr.v
new file mode 100644 (file)
index 0000000..bc8c11a
--- /dev/null
@@ -0,0 +1,353 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_sfr.v
+// 
+// *Module Description:
+//                       Processor Special function register
+//                       Non-Maskable Interrupt generation
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 134 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2012-03-22 21:31:06 +0100 (Thu, 22 Mar 2012) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module  omsp_sfr (
+
+// OUTPUTs
+    cpu_id,                       // CPU ID
+    nmi_pnd,                      // NMI Pending
+    nmi_wkup,                     // NMI Wakeup
+    per_dout,                     // Peripheral data output
+    wdtie,                        // Watchdog-timer interrupt enable
+    wdtifg_sw_clr,                // Watchdog-timer interrupt flag software clear
+    wdtifg_sw_set,                // Watchdog-timer interrupt flag software set
+
+// INPUTs
+    mclk,                         // Main system clock
+    nmi,                          // Non-maskable interrupt (asynchronous)
+    nmi_acc,                      // Non-Maskable interrupt request accepted
+    per_addr,                     // Peripheral address
+    per_din,                      // Peripheral data input
+    per_en,                       // Peripheral enable (high active)
+    per_we,                       // Peripheral write enable (high active)
+    puc_rst,                      // Main system reset
+    scan_mode,                    // Scan mode
+    wdtifg,                       // Watchdog-timer interrupt flag
+    wdtnmies                      // Watchdog-timer NMI edge selection
+);
+
+// OUTPUTs
+//=========
+output       [31:0] cpu_id;       // CPU ID
+output              nmi_pnd;      // NMI Pending
+output              nmi_wkup;     // NMI Wakeup
+output       [15:0] per_dout;     // Peripheral data output
+output              wdtie;        // Watchdog-timer interrupt enable
+output              wdtifg_sw_clr;// Watchdog-timer interrupt flag software clear
+output              wdtifg_sw_set;// Watchdog-timer interrupt flag software set
+
+// INPUTs
+//=========
+input               mclk;         // Main system clock
+input               nmi;          // Non-maskable interrupt (asynchronous)
+input               nmi_acc;      // Non-Maskable interrupt request accepted
+input        [13:0] per_addr;     // Peripheral address
+input        [15:0] per_din;      // Peripheral data input
+input               per_en;       // Peripheral enable (high active)
+input         [1:0] per_we;       // Peripheral write enable (high active)
+input               puc_rst;      // Main system reset
+input               scan_mode;    // Scan mode
+input               wdtifg;       // Watchdog-timer interrupt flag
+input               wdtnmies;     // Watchdog-timer NMI edge selection
+
+
+//=============================================================================
+// 1)  PARAMETER DECLARATION
+//=============================================================================
+
+// Register base address (must be aligned to decoder bit width)
+parameter       [14:0] BASE_ADDR   = 15'h0000;
+
+// Decoder bit width (defines how many bits are considered for address decoding)
+parameter              DEC_WD      =  3;
+
+// Register addresses offset
+parameter [DEC_WD-1:0] IE1         =  'h0,
+                       IFG1        =  'h2,
+                       CPU_ID_LO   =  'h4,
+                       CPU_ID_HI   =  'h6;
+
+// Register one-hot decoder utilities
+parameter              DEC_SZ      =  (1 << DEC_WD);
+parameter [DEC_SZ-1:0] BASE_REG    =  {{DEC_SZ-1{1'b0}}, 1'b1};
+
+// Register one-hot decoder
+parameter [DEC_SZ-1:0] IE1_D       = (BASE_REG << IE1),
+                       IFG1_D      = (BASE_REG << IFG1),
+                       CPU_ID_LO_D = (BASE_REG << CPU_ID_LO),
+                       CPU_ID_HI_D = (BASE_REG << CPU_ID_HI);
+
+
+//============================================================================
+// 2)  REGISTER DECODER
+//============================================================================
+
+// Local register selection
+wire              reg_sel      =  per_en & (per_addr[13:DEC_WD-1]==BASE_ADDR[14:DEC_WD]);
+
+// Register local address
+wire [DEC_WD-1:0] reg_addr     =  {1'b0, per_addr[DEC_WD-2:0]};
+
+// Register address decode
+wire [DEC_SZ-1:0] reg_dec      = (IE1_D        &  {DEC_SZ{(reg_addr==(IE1       >>1))}})  |
+                                 (IFG1_D       &  {DEC_SZ{(reg_addr==(IFG1      >>1))}})  |
+                                 (CPU_ID_LO_D  &  {DEC_SZ{(reg_addr==(CPU_ID_LO >>1))}})  |
+                                 (CPU_ID_HI_D  &  {DEC_SZ{(reg_addr==(CPU_ID_HI >>1))}});
+
+// Read/Write probes
+wire              reg_lo_write =  per_we[0] & reg_sel;
+wire              reg_hi_write =  per_we[1] & reg_sel;
+wire              reg_read     = ~|per_we   & reg_sel;
+
+// Read/Write vectors
+wire [DEC_SZ-1:0] reg_hi_wr    = reg_dec & {DEC_SZ{reg_hi_write}};
+wire [DEC_SZ-1:0] reg_lo_wr    = reg_dec & {DEC_SZ{reg_lo_write}};
+wire [DEC_SZ-1:0] reg_rd       = reg_dec & {DEC_SZ{reg_read}};
+
+
+//============================================================================
+// 3) REGISTERS
+//============================================================================
+
+// IE1 Register
+//--------------
+wire [7:0] ie1;
+wire       ie1_wr  = IE1[0] ? reg_hi_wr[IE1] : reg_lo_wr[IE1];
+wire [7:0] ie1_nxt = IE1[0] ? per_din[15:8]  : per_din[7:0];
+
+`ifdef NMI
+reg        nmie;
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst)      nmie  <=  1'b0;
+  else if (nmi_acc) nmie  <=  1'b0; 
+  else if (ie1_wr)  nmie  <=  ie1_nxt[4];    
+`else
+wire       nmie  =  1'b0;
+`endif
+
+`ifdef WATCHDOG
+reg        wdtie;
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst)      wdtie <=  1'b0;
+  else if (ie1_wr)  wdtie <=  ie1_nxt[0];    
+`else
+wire       wdtie =  1'b0;    
+`endif
+
+assign  ie1 = {3'b000, nmie, 3'b000, wdtie};
+
+
+// IFG1 Register
+//---------------
+wire [7:0] ifg1;
+
+wire       ifg1_wr  = IFG1[0] ? reg_hi_wr[IFG1] : reg_lo_wr[IFG1];
+wire [7:0] ifg1_nxt = IFG1[0] ? per_din[15:8]   : per_din[7:0];
+
+`ifdef NMI
+reg        nmiifg;
+wire       nmi_edge;
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst)       nmiifg <=  1'b0;
+  else if (nmi_edge) nmiifg <=  1'b1;
+  else if (ifg1_wr)  nmiifg <=  ifg1_nxt[4];
+`else
+wire       nmiifg = 1'b0;
+`endif
+
+`ifdef WATCHDOG
+assign  wdtifg_sw_clr = ifg1_wr & ~ifg1_nxt[0];
+assign  wdtifg_sw_set = ifg1_wr &  ifg1_nxt[0];
+`else
+assign  wdtifg_sw_clr = 1'b0;
+assign  wdtifg_sw_set = 1'b0;
+`endif
+
+assign  ifg1 = {3'b000, nmiifg, 3'b000, wdtifg};
+
+
+// CPU_ID Register (READ ONLY)
+//-----------------------------
+//              -------------------------------------------------------------------
+// CPU_ID_LO:  | 15  14  13  12  11  10  9  |  8  7  6  5  4  |  3   |   2  1  0   |
+//             |----------------------------+-----------------+------+-------------|
+//             |        PER_SPACE           |   USER_VERSION  | ASIC | CPU_VERSION |
+//              --------------------------------------------------------------------
+// CPU_ID_HI:  |   15  14  13  12  11  10   |   9  8  7  6  5  4  3  2  1   |   0  |
+//             |----------------------------+-------------------------------+------|
+//             |         PMEM_SIZE          |            DMEM_SIZE          |  MPY |
+//              -------------------------------------------------------------------
+
+wire  [2:0] cpu_version  =  `CPU_VERSION;
+`ifdef ASIC
+wire        cpu_asic     =  1'b1;
+`else
+wire        cpu_asic     =  1'b0;
+`endif
+wire  [4:0] user_version =  `USER_VERSION;
+wire  [6:0] per_space    = (`PER_SIZE  >> 9);  // cpu_id_per  *  512 = peripheral space size
+`ifdef MULTIPLIER
+wire        mpy_info     =  1'b1;
+`else
+wire        mpy_info     =  1'b0;
+`endif
+wire  [8:0] dmem_size    = (`DMEM_SIZE >> 7);  // cpu_id_dmem *  128 = data memory size
+wire  [5:0] pmem_size    = (`PMEM_SIZE >> 10); // cpu_id_pmem * 1024 = program memory size
+
+assign      cpu_id       = {pmem_size,
+                           dmem_size,
+                           mpy_info,
+                           per_space,
+                           user_version,
+                           cpu_asic,
+                            cpu_version};
+
+
+//============================================================================
+// 4) DATA OUTPUT GENERATION
+//============================================================================
+
+// Data output mux
+wire [15:0] ie1_rd        = {8'h00, (ie1  &  {8{reg_rd[IE1]}})}  << (8 & {4{IE1[0]}});
+wire [15:0] ifg1_rd       = {8'h00, (ifg1 &  {8{reg_rd[IFG1]}})} << (8 & {4{IFG1[0]}});
+wire [15:0] cpu_id_lo_rd  = cpu_id[15:0]  & {16{reg_rd[CPU_ID_LO]}};
+wire [15:0] cpu_id_hi_rd  = cpu_id[31:16] & {16{reg_rd[CPU_ID_HI]}};
+
+wire [15:0] per_dout =  ie1_rd       |
+                        ifg1_rd      |
+                        cpu_id_lo_rd |
+                        cpu_id_hi_rd;
+
+
+//=============================================================================
+// 5)  NMI GENERATION
+//=============================================================================
+// NOTE THAT THE NMI INPUT IS ASSUMED TO BE NON-GLITCHY
+`ifdef NMI
+
+//-----------------------------------
+// Edge selection
+//-----------------------------------
+wire nmi_pol = nmi ^ wdtnmies;
+
+//-----------------------------------
+// Pulse capture and synchronization
+//-----------------------------------
+`ifdef SYNC_NMI
+  `ifdef ASIC
+   // Glitch free reset for the event capture
+   reg    nmi_capture_rst;
+   always @(posedge mclk or posedge puc_rst)
+     if (puc_rst) nmi_capture_rst <= 1'b1;
+     else         nmi_capture_rst <= ifg1_wr & ~ifg1_nxt[4];
+   // NMI event capture
+   wire   nmi_capture;
+   omsp_wakeup_cell wakeup_cell_nmi (
+                                    .wkup_out   (nmi_capture),     // Wakup signal (asynchronous)
+                                    .scan_clk   (mclk),            // Scan clock
+                                    .scan_mode  (scan_mode),       // Scan mode
+                                    .scan_rst   (puc_rst),         // Scan reset
+                                    .wkup_clear (nmi_capture_rst), // Glitch free wakeup event clear
+                                    .wkup_event (nmi_pol)          // Glitch free asynchronous wakeup event
+   );
+  `else
+   wire   nmi_capture = nmi_pol;
+  `endif
+
+   // Synchronization
+   wire   nmi_s;
+   omsp_sync_cell sync_cell_nmi (
+       .data_out  (nmi_s),
+       .data_in   (nmi_capture),
+       .clk       (mclk),
+       .rst       (puc_rst)
+   );
+
+`else
+   wire   nmi_capture = nmi_pol;
+   wire   nmi_s       = nmi_pol;
+`endif
+
+//-----------------------------------
+// NMI Pending flag
+//-----------------------------------
+
+// Delay
+reg  nmi_dly;
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst) nmi_dly <= 1'b0;
+  else         nmi_dly <= nmi_s;
+
+// Edge detection
+assign      nmi_edge  = ~nmi_dly & nmi_s;
+
+// NMI pending
+wire        nmi_pnd   = nmiifg & nmie;
+
+// NMI wakeup
+`ifdef ASIC
+wire        nmi_wkup;
+omsp_and_gate and_nmi_wkup (.y(nmi_wkup), .a(nmi_capture ^ nmi_dly), .b(nmie));
+`else
+wire        nmi_wkup  = 1'b0;
+`endif
+
+`else
+
+wire        nmi_pnd   = 1'b0;
+wire        nmi_wkup  = 1'b0;
+
+`endif
+
+endmodule // omsp_sfr
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
diff --git a/tests/openmsp430/rtl/omsp_sync_cell.v b/tests/openmsp430/rtl/omsp_sync_cell.v
new file mode 100644 (file)
index 0000000..ece0682
--- /dev/null
@@ -0,0 +1,80 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_sync_cell.v
+// 
+// *Module Description:
+//                       Generic synchronizer for the openMSP430
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 103 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $
+//----------------------------------------------------------------------------
+
+module  omsp_sync_cell (
+
+// OUTPUTs
+    data_out,                      // Synchronized data output
+
+// INPUTs
+    clk,                           // Receiving clock
+    data_in,                       // Asynchronous data input
+    rst                            // Receiving reset (active high)
+);
+
+// OUTPUTs
+//=========
+output              data_out;      // Synchronized data output
+
+// INPUTs
+//=========
+input               clk;          // Receiving clock
+input               data_in;      // Asynchronous data input
+input               rst;          // Receiving reset (active high)
+
+
+//=============================================================================
+// 1)  SYNCHRONIZER
+//=============================================================================
+
+reg  [1:0] data_sync;
+
+always @(posedge clk or posedge rst)
+  if (rst) data_sync <=  2'b00;
+  else     data_sync <=  {data_sync[0], data_in};
+
+assign     data_out   =   data_sync[1];
+
+
+endmodule // omsp_sync_cell
+
diff --git a/tests/openmsp430/rtl/omsp_sync_reset.v b/tests/openmsp430/rtl/omsp_sync_reset.v
new file mode 100644 (file)
index 0000000..15a158b
--- /dev/null
@@ -0,0 +1,78 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_sync_reset.v
+// 
+// *Module Description:
+//                       Generic reset synchronizer for the openMSP430
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 103 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $
+//----------------------------------------------------------------------------
+
+module  omsp_sync_reset (
+
+// OUTPUTs
+    rst_s,                        // Synchronized reset
+
+// INPUTs
+    clk,                          // Receiving clock
+    rst_a                         // Asynchronous reset
+);
+
+// OUTPUTs
+//=========
+output              rst_s;        // Synchronized reset
+
+// INPUTs
+//=========
+input               clk;          // Receiving clock
+input               rst_a;        // Asynchronous reset
+
+
+//=============================================================================
+// 1)  SYNCHRONIZER
+//=============================================================================
+
+reg    [1:0] data_sync;
+
+always @(posedge clk or posedge rst_a)
+  if (rst_a) data_sync <=  2'b11;
+  else       data_sync <=  {data_sync[0], 1'b0};
+
+assign       rst_s      =   data_sync[1];
+
+
+endmodule // omsp_sync_reset
+
diff --git a/tests/openmsp430/rtl/omsp_wakeup_cell.v b/tests/openmsp430/rtl/omsp_wakeup_cell.v
new file mode 100644 (file)
index 0000000..6e5fcd8
--- /dev/null
@@ -0,0 +1,108 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_wakeup_cell.v
+// 
+// *Module Description:
+//                       Generic Wakeup cell
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 103 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $
+//----------------------------------------------------------------------------
+
+module  omsp_wakeup_cell (
+
+// OUTPUTs
+    wkup_out,                  // Wakup signal (asynchronous)
+
+// INPUTs
+    scan_clk,                  // Scan clock
+    scan_mode,                 // Scan mode
+    scan_rst,                  // Scan reset
+    wkup_clear,                // Glitch free wakeup event clear
+    wkup_event                 // Glitch free asynchronous wakeup event
+);
+
+// OUTPUTs
+//=========
+output         wkup_out;       // Wakup signal (asynchronous)
+
+// INPUTs
+//=========
+input          scan_clk;       // Scan clock
+input          scan_mode;      // Scan mode
+input          scan_rst;       // Scan reset
+input          wkup_clear;     // Glitch free wakeup event clear
+input          wkup_event;     // Glitch free asynchronous wakeup event
+
+
+//=============================================================================
+// 1)  AND GATE
+//=============================================================================
+
+// Scan stuff for the ASIC mode
+`ifdef ASIC
+   wire wkup_rst;
+   omsp_scan_mux scan_mux_rst (
+                               .scan_mode    (scan_mode),
+                               .data_in_scan (scan_rst),
+                               .data_in_func (wkup_clear),
+                               .data_out     (wkup_rst)
+   );
+
+   wire wkup_clk;
+   omsp_scan_mux scan_mux_clk (
+                               .scan_mode    (scan_mode),
+                               .data_in_scan (scan_clk),
+                               .data_in_func (wkup_event),
+                               .data_out     (wkup_clk)
+   );
+
+`else
+   wire wkup_rst  =  wkup_clear;
+   wire wkup_clk  =  wkup_event;
+`endif
+
+// Wakeup capture
+reg    wkup_out;
+always @(posedge wkup_clk or posedge wkup_rst)
+  if (wkup_rst) wkup_out <= 1'b0;
+  else          wkup_out <= 1'b1;
+
+
+endmodule // omsp_wakeup_cell
+
+
+
+
diff --git a/tests/openmsp430/rtl/omsp_watchdog.v b/tests/openmsp430/rtl/omsp_watchdog.v
new file mode 100644 (file)
index 0000000..f7cedda
--- /dev/null
@@ -0,0 +1,556 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_watchdog.v
+// 
+// *Module Description:
+//                       Watchdog Timer
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 134 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2012-03-22 21:31:06 +0100 (Thu, 22 Mar 2012) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module  omsp_watchdog (
+
+// OUTPUTs
+    per_dout,                       // Peripheral data output
+    wdt_irq,                        // Watchdog-timer interrupt
+    wdt_reset,                      // Watchdog-timer reset
+    wdt_wkup,                       // Watchdog Wakeup
+    wdtifg,                         // Watchdog-timer interrupt flag
+    wdtnmies,                       // Watchdog-timer NMI edge selection
+
+// INPUTs
+    aclk,                           // ACLK
+    aclk_en,                        // ACLK enable
+    dbg_freeze,                     // Freeze Watchdog counter
+    mclk,                           // Main system clock
+    per_addr,                       // Peripheral address
+    per_din,                        // Peripheral data input
+    per_en,                         // Peripheral enable (high active)
+    per_we,                         // Peripheral write enable (high active)
+    por,                            // Power-on reset
+    puc_rst,                        // Main system reset
+    scan_enable,                    // Scan enable (active during scan shifting)
+    scan_mode,                      // Scan mode
+    smclk,                          // SMCLK
+    smclk_en,                       // SMCLK enable
+    wdtie,                          // Watchdog timer interrupt enable
+    wdtifg_irq_clr,                 // Watchdog-timer interrupt flag irq accepted clear
+    wdtifg_sw_clr,                  // Watchdog-timer interrupt flag software clear
+    wdtifg_sw_set                   // Watchdog-timer interrupt flag software set
+);
+
+// OUTPUTs
+//=========
+output       [15:0] per_dout;       // Peripheral data output
+output              wdt_irq;        // Watchdog-timer interrupt
+output              wdt_reset;      // Watchdog-timer reset
+output              wdt_wkup;       // Watchdog Wakeup
+output              wdtifg;         // Watchdog-timer interrupt flag
+output              wdtnmies;       // Watchdog-timer NMI edge selection
+
+// INPUTs
+//=========
+input               aclk;           // ACLK
+input               aclk_en;        // ACLK enable
+input               dbg_freeze;     // Freeze Watchdog counter
+input               mclk;           // Main system clock
+input        [13:0] per_addr;       // Peripheral address
+input        [15:0] per_din;        // Peripheral data input
+input               per_en;         // Peripheral enable (high active)
+input         [1:0] per_we;         // Peripheral write enable (high active)
+input               por;            // Power-on reset
+input               puc_rst;        // Main system reset
+input               scan_enable;    // Scan enable (active during scan shifting)
+input               scan_mode;      // Scan mode
+input               smclk;          // SMCLK
+input               smclk_en;       // SMCLK enable
+input               wdtie;          // Watchdog timer interrupt enable
+input               wdtifg_irq_clr; // Clear Watchdog-timer interrupt flag
+input               wdtifg_sw_clr;  // Watchdog-timer interrupt flag software clear
+input               wdtifg_sw_set;  // Watchdog-timer interrupt flag software set
+
+
+//=============================================================================
+// 1)  PARAMETER DECLARATION
+//=============================================================================
+
+// Register base address (must be aligned to decoder bit width)
+parameter       [14:0] BASE_ADDR   = 15'h0120;
+
+// Decoder bit width (defines how many bits are considered for address decoding)
+parameter              DEC_WD      =  2;
+
+// Register addresses offset
+parameter [DEC_WD-1:0] WDTCTL      = 'h0;
+
+// Register one-hot decoder utilities
+parameter              DEC_SZ      =  (1 << DEC_WD);
+parameter [DEC_SZ-1:0] BASE_REG    =  {{DEC_SZ-1{1'b0}}, 1'b1};
+
+// Register one-hot decoder
+parameter [DEC_SZ-1:0] WDTCTL_D    = (BASE_REG << WDTCTL);
+
+
+//============================================================================
+// 2)  REGISTER DECODER
+//============================================================================
+
+// Local register selection
+wire              reg_sel   =  per_en & (per_addr[13:DEC_WD-1]==BASE_ADDR[14:DEC_WD]);
+
+// Register local address
+wire [DEC_WD-1:0] reg_addr  =  {per_addr[DEC_WD-2:0], 1'b0};
+
+// Register address decode
+wire [DEC_SZ-1:0] reg_dec   =  (WDTCTL_D & {DEC_SZ{(reg_addr==WDTCTL)}});
+
+// Read/Write probes
+wire              reg_write =  |per_we & reg_sel;
+wire              reg_read  = ~|per_we & reg_sel;
+
+// Read/Write vectors
+wire [DEC_SZ-1:0] reg_wr    = reg_dec & {DEC_SZ{reg_write}};
+wire [DEC_SZ-1:0] reg_rd    = reg_dec & {DEC_SZ{reg_read}};
+
+
+//============================================================================
+// 3) REGISTERS
+//============================================================================
+
+// WDTCTL Register
+//-----------------
+// WDTNMI is not implemented and therefore masked
+   
+reg  [7:0] wdtctl;
+
+wire       wdtctl_wr = reg_wr[WDTCTL];
+
+`ifdef CLOCK_GATING
+wire       mclk_wdtctl;
+omsp_clock_gate clock_gate_wdtctl (.gclk(mclk_wdtctl),
+                                   .clk (mclk), .enable(wdtctl_wr), .scan_enable(scan_enable));
+`else
+wire       mclk_wdtctl = mclk;
+`endif
+
+`ifdef NMI
+parameter [7:0] WDTNMIES_MASK = 8'h40;
+`else
+parameter [7:0] WDTNMIES_MASK = 8'h00;
+`endif
+
+`ifdef ASIC
+  `ifdef WATCHDOG_MUX
+parameter [7:0] WDTSSEL_MASK  = 8'h04;
+  `else
+parameter [7:0] WDTSSEL_MASK  = 8'h00;
+  `endif
+`else
+parameter [7:0] WDTSSEL_MASK  = 8'h04;
+`endif
+
+parameter [7:0] WDTCTL_MASK   = (8'b1001_0011 | WDTSSEL_MASK | WDTNMIES_MASK);
+   
+always @ (posedge mclk_wdtctl or posedge puc_rst)
+  if (puc_rst)        wdtctl <=  8'h00;
+`ifdef CLOCK_GATING
+  else                wdtctl <=  per_din[7:0] & WDTCTL_MASK;
+`else
+  else if (wdtctl_wr) wdtctl <=  per_din[7:0] & WDTCTL_MASK;
+`endif
+
+wire       wdtpw_error = wdtctl_wr & (per_din[15:8]!=8'h5a);
+wire       wdttmsel    = wdtctl[4];
+wire       wdtnmies    = wdtctl[6];
+
+
+//============================================================================
+// 4) DATA OUTPUT GENERATION
+//============================================================================
+
+`ifdef NMI
+parameter [7:0] WDTNMI_RD_MASK  = 8'h20;
+`else
+parameter [7:0] WDTNMI_RD_MASK  = 8'h00;
+`endif
+`ifdef WATCHDOG_MUX
+parameter [7:0] WDTSSEL_RD_MASK = 8'h00;
+`else
+  `ifdef WATCHDOG_NOMUX_ACLK
+parameter [7:0] WDTSSEL_RD_MASK = 8'h04;
+  `else
+parameter [7:0] WDTSSEL_RD_MASK = 8'h00;
+  `endif
+`endif
+parameter [7:0] WDTCTL_RD_MASK  = WDTNMI_RD_MASK | WDTSSEL_RD_MASK;
+
+// Data output mux
+wire [15:0] wdtctl_rd  = {8'h69, wdtctl | WDTCTL_RD_MASK} & {16{reg_rd[WDTCTL]}};
+wire [15:0] per_dout   =  wdtctl_rd;
+
+
+//=============================================================================
+// 5)  WATCHDOG TIMER (ASIC IMPLEMENTATION)
+//=============================================================================
+`ifdef ASIC
+
+// Watchdog clock source selection
+//---------------------------------
+wire wdt_clk;
+
+`ifdef WATCHDOG_MUX
+omsp_clock_mux clock_mux_watchdog (
+   .clk_out   (wdt_clk),
+   .clk_in0   (smclk),
+   .clk_in1   (aclk),
+   .reset     (puc_rst),
+   .scan_mode (scan_mode),
+   .select    (wdtctl[2])
+);
+`else
+  `ifdef WATCHDOG_NOMUX_ACLK
+     assign wdt_clk =  aclk;
+  `else
+     assign wdt_clk =  smclk;
+  `endif
+`endif
+
+// Reset synchronizer for the watchdog local clock domain
+//--------------------------------------------------------
+   
+wire wdt_rst_noscan;
+wire wdt_rst;
+
+// Reset Synchronizer
+omsp_sync_reset sync_reset_por (
+    .rst_s        (wdt_rst_noscan),
+    .clk          (wdt_clk),
+    .rst_a        (puc_rst)
+);
+
+// Scan Reset Mux
+omsp_scan_mux scan_mux_wdt_rst (
+    .scan_mode    (scan_mode),
+    .data_in_scan (puc_rst),
+    .data_in_func (wdt_rst_noscan),
+    .data_out     (wdt_rst)
+);
+   
+
+// Watchog counter clear (synchronization)
+//-----------------------------------------
+
+// Toggle bit whenever the watchog needs to be cleared
+reg        wdtcnt_clr_toggle;
+wire       wdtcnt_clr_detect = (wdtctl_wr & per_din[3]);
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst)                wdtcnt_clr_toggle <= 1'b0;
+  else if (wdtcnt_clr_detect) wdtcnt_clr_toggle <= ~wdtcnt_clr_toggle;
+
+// Synchronization
+wire wdtcnt_clr_sync;
+omsp_sync_cell sync_cell_wdtcnt_clr (
+    .data_out  (wdtcnt_clr_sync),
+    .data_in   (wdtcnt_clr_toggle),
+    .clk       (wdt_clk),
+    .rst       (wdt_rst)
+);
+
+// Edge detection
+reg wdtcnt_clr_sync_dly;
+always @ (posedge wdt_clk or posedge wdt_rst)
+  if (wdt_rst)  wdtcnt_clr_sync_dly <= 1'b0;
+  else          wdtcnt_clr_sync_dly <= wdtcnt_clr_sync;
+
+wire wdtqn_edge;
+wire wdtcnt_clr = (wdtcnt_clr_sync ^ wdtcnt_clr_sync_dly) | wdtqn_edge;
+
+
+// Watchog counter increment (synchronization)
+//----------------------------------------------
+wire wdtcnt_incr;
+
+omsp_sync_cell sync_cell_wdtcnt_incr (
+    .data_out  (wdtcnt_incr),
+    .data_in   (~wdtctl[7] & ~dbg_freeze),
+    .clk       (wdt_clk),
+    .rst       (wdt_rst)
+);
+
+
+// Watchdog 16 bit counter
+//--------------------------
+reg  [15:0] wdtcnt;
+
+wire [15:0] wdtcnt_nxt  = wdtcnt+16'h0001;
+
+`ifdef CLOCK_GATING
+wire       wdtcnt_en   = wdtcnt_clr | wdtcnt_incr;
+wire       wdt_clk_cnt;
+omsp_clock_gate clock_gate_wdtcnt (.gclk(wdt_clk_cnt),
+                                   .clk (wdt_clk), .enable(wdtcnt_en), .scan_enable(scan_enable));
+`else
+wire       wdt_clk_cnt = wdt_clk;
+`endif
+
+always @ (posedge wdt_clk_cnt or posedge wdt_rst)
+  if (wdt_rst)           wdtcnt <= 16'h0000;
+  else if (wdtcnt_clr)   wdtcnt <= 16'h0000;
+`ifdef CLOCK_GATING
+  else                   wdtcnt <= wdtcnt_nxt;
+`else
+  else if (wdtcnt_incr)  wdtcnt <= wdtcnt_nxt;
+`endif
+
+
+// Local synchronizer for the wdtctl.WDTISx
+// configuration (note that we can live with
+// a full bus synchronizer as it won't hurt
+// if we get a wrong WDTISx value for a
+// single clock cycle)
+//--------------------------------------------
+reg [1:0] wdtisx_s;
+reg [1:0] wdtisx_ss;
+always @ (posedge wdt_clk_cnt or posedge wdt_rst)
+  if (wdt_rst)
+    begin
+       wdtisx_s  <=  2'h0;
+       wdtisx_ss <=  2'h0;
+    end
+  else
+    begin
+       wdtisx_s  <=  wdtctl[1:0];
+       wdtisx_ss <=  wdtisx_s;
+    end
+
+
+// Interval selection mux
+//--------------------------
+reg        wdtqn;
+
+always @(wdtisx_ss or wdtcnt_nxt)
+    case(wdtisx_ss)
+      2'b00  : wdtqn =  wdtcnt_nxt[15];
+      2'b01  : wdtqn =  wdtcnt_nxt[13];
+      2'b10  : wdtqn =  wdtcnt_nxt[9];
+      default: wdtqn =  wdtcnt_nxt[6];
+    endcase
+
+
+// Watchdog event detection
+//-----------------------------
+
+// Interval end detection
+assign     wdtqn_edge =  (wdtqn & wdtcnt_incr);
+
+// Toggle bit for the transmition to the MCLK domain
+reg        wdt_evt_toggle;
+always @ (posedge wdt_clk_cnt or posedge wdt_rst)
+  if (wdt_rst)         wdt_evt_toggle <= 1'b0;
+  else if (wdtqn_edge) wdt_evt_toggle <= ~wdt_evt_toggle;
+
+// Synchronize in the MCLK domain
+wire       wdt_evt_toggle_sync;
+omsp_sync_cell sync_cell_wdt_evt (
+    .data_out  (wdt_evt_toggle_sync),
+    .data_in   (wdt_evt_toggle),
+    .clk       (mclk),
+    .rst       (puc_rst)
+);
+
+// Delay for edge detection of the toggle bit
+reg        wdt_evt_toggle_sync_dly;
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst) wdt_evt_toggle_sync_dly <= 1'b0;
+  else         wdt_evt_toggle_sync_dly <= wdt_evt_toggle_sync;
+
+wire       wdtifg_evt =  (wdt_evt_toggle_sync_dly ^ wdt_evt_toggle_sync) | wdtpw_error;
+
+
+// Watchdog wakeup generation
+//-------------------------------------------------------------
+
+// Clear wakeup when the watchdog flag is cleared (glitch free)
+reg  wdtifg_clr_reg;
+wire wdtifg_clr;
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst) wdtifg_clr_reg <= 1'b1;
+  else         wdtifg_clr_reg <= wdtifg_clr;
+
+// Set wakeup when the watchdog event is detected (glitch free)
+reg  wdtqn_edge_reg;
+always @ (posedge wdt_clk_cnt or posedge wdt_rst)
+  if (wdt_rst) wdtqn_edge_reg <= 1'b0;
+  else         wdtqn_edge_reg <= wdtqn_edge;
+
+// Watchdog wakeup cell
+wire wdt_wkup_pre;
+omsp_wakeup_cell wakeup_cell_wdog (
+                                  .wkup_out   (wdt_wkup_pre),    // Wakup signal (asynchronous)
+                                  .scan_clk   (mclk),            // Scan clock
+                                  .scan_mode  (scan_mode),       // Scan mode
+                                  .scan_rst   (puc_rst),         // Scan reset
+                                  .wkup_clear (wdtifg_clr_reg),  // Glitch free wakeup event clear
+                                  .wkup_event (wdtqn_edge_reg)   // Glitch free asynchronous wakeup event
+);
+
+// When not in HOLD, the watchdog can generate a wakeup when:
+//     - in interval mode (if interrupts are enabled)
+//     - in reset mode (always)
+reg  wdt_wkup_en;
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst) wdt_wkup_en <= 1'b0;
+  else         wdt_wkup_en <= ~wdtctl[7] & (~wdttmsel | (wdttmsel & wdtie));
+
+// Make wakeup when not enabled
+wire wdt_wkup;
+omsp_and_gate and_wdt_wkup (.y(wdt_wkup), .a(wdt_wkup_pre), .b(wdt_wkup_en));
+
+
+// Watchdog interrupt flag
+//------------------------------
+reg        wdtifg;
+
+wire       wdtifg_set =  wdtifg_evt                  |  wdtifg_sw_set;
+assign     wdtifg_clr =  (wdtifg_irq_clr & wdttmsel) |  wdtifg_sw_clr;
+
+always @ (posedge mclk or posedge por)
+  if (por)             wdtifg <=  1'b0;
+  else if (wdtifg_set) wdtifg <=  1'b1;
+  else if (wdtifg_clr) wdtifg <=  1'b0;
+
+
+// Watchdog interrupt generation
+//---------------------------------
+wire    wdt_irq       = wdttmsel & wdtifg & wdtie;
+
+
+// Watchdog reset generation
+//-----------------------------
+reg     wdt_reset;
+
+always @ (posedge mclk or posedge por)
+  if (por) wdt_reset <= 1'b0;
+  else     wdt_reset <= wdtpw_error | (wdtifg_set & ~wdttmsel);
+
+
+
+//=============================================================================
+// 6)  WATCHDOG TIMER (FPGA IMPLEMENTATION)
+//=============================================================================
+`else
+
+// Watchdog clock source selection
+//---------------------------------
+wire  clk_src_en = wdtctl[2] ? aclk_en : smclk_en;
+
+
+// Watchdog 16 bit counter
+//--------------------------
+reg [15:0] wdtcnt;
+
+wire        wdtifg_evt;
+wire        wdtcnt_clr  = (wdtctl_wr & per_din[3]) | wdtifg_evt;
+wire        wdtcnt_incr = ~wdtctl[7] & clk_src_en & ~dbg_freeze;
+
+wire [15:0] wdtcnt_nxt  = wdtcnt+16'h0001;
+
+always @ (posedge mclk or posedge puc_rst)
+  if (puc_rst)           wdtcnt <= 16'h0000;
+  else if (wdtcnt_clr)   wdtcnt <= 16'h0000;
+  else if (wdtcnt_incr)  wdtcnt <= wdtcnt_nxt;
+
+   
+// Interval selection mux
+//--------------------------
+reg        wdtqn;
+
+always @(wdtctl or wdtcnt_nxt)
+    case(wdtctl[1:0])
+      2'b00  : wdtqn =  wdtcnt_nxt[15];
+      2'b01  : wdtqn =  wdtcnt_nxt[13];
+      2'b10  : wdtqn =  wdtcnt_nxt[9];
+      default: wdtqn =  wdtcnt_nxt[6];
+    endcase
+
+
+// Watchdog event detection
+//-----------------------------
+
+assign     wdtifg_evt =  (wdtqn & wdtcnt_incr) | wdtpw_error;
+
+
+// Watchdog interrupt flag
+//------------------------------
+reg        wdtifg;
+
+wire       wdtifg_set =  wdtifg_evt                  |  wdtifg_sw_set;
+wire       wdtifg_clr =  (wdtifg_irq_clr & wdttmsel) |  wdtifg_sw_clr;
+
+always @ (posedge mclk or posedge por)
+  if (por)             wdtifg <=  1'b0;
+  else if (wdtifg_set) wdtifg <=  1'b1;
+  else if (wdtifg_clr) wdtifg <=  1'b0;
+
+
+// Watchdog interrupt generation
+//---------------------------------
+wire    wdt_irq       = wdttmsel & wdtifg & wdtie;
+wire    wdt_wkup      =  1'b0;
+
+
+// Watchdog reset generation
+//-----------------------------
+reg     wdt_reset;
+
+always @ (posedge mclk or posedge por)
+  if (por) wdt_reset <= 1'b0;
+  else     wdt_reset <= wdtpw_error | (wdtifg_set & ~wdttmsel);
+
+
+`endif
+
+
+endmodule // omsp_watchdog
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
diff --git a/tests/openmsp430/rtl/openMSP430.v b/tests/openmsp430/rtl/openMSP430.v
new file mode 100644 (file)
index 0000000..938548a
--- /dev/null
@@ -0,0 +1,584 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: openMSP430.v
+// 
+// *Module Description:
+//                       openMSP430 Top level file
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 134 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2012-03-22 21:31:06 +0100 (Thu, 22 Mar 2012) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module  openMSP430 (
+
+// OUTPUTs
+    aclk,                          // ASIC ONLY: ACLK
+    aclk_en,                       // FPGA ONLY: ACLK enable
+    dbg_freeze,                    // Freeze peripherals
+    dbg_uart_txd,                  // Debug interface: UART TXD
+    dco_enable,                    // ASIC ONLY: Fast oscillator enable
+    dco_wkup,                      // ASIC ONLY: Fast oscillator wake-up (asynchronous)
+    dmem_addr,                     // Data Memory address
+    dmem_cen,                      // Data Memory chip enable (low active)
+    dmem_din,                      // Data Memory data input
+    dmem_wen,                      // Data Memory write enable (low active)
+    irq_acc,                       // Interrupt request accepted (one-hot signal)
+    lfxt_enable,                   // ASIC ONLY: Low frequency oscillator enable
+    lfxt_wkup,                     // ASIC ONLY: Low frequency oscillator wake-up (asynchronous)
+    mclk,                          // Main system clock
+    per_addr,                      // Peripheral address
+    per_din,                       // Peripheral data input
+    per_we,                        // Peripheral write enable (high active)
+    per_en,                        // Peripheral enable (high active)
+    pmem_addr,                     // Program Memory address
+    pmem_cen,                      // Program Memory chip enable (low active)
+    pmem_din,                      // Program Memory data input (optional)
+    pmem_wen,                      // Program Memory write enable (low active) (optional)
+    puc_rst,                       // Main system reset
+    smclk,                         // ASIC ONLY: SMCLK
+    smclk_en,                      // FPGA ONLY: SMCLK enable
+
+// INPUTs
+    cpu_en,                        // Enable CPU code execution (asynchronous and non-glitchy)
+    dbg_en,                        // Debug interface enable (asynchronous and non-glitchy)
+    dbg_uart_rxd,                  // Debug interface: UART RXD (asynchronous)
+    dco_clk,                       // Fast oscillator (fast clock)
+    dmem_dout,                     // Data Memory data output
+    irq,                           // Maskable interrupts
+    lfxt_clk,                      // Low frequency oscillator (typ 32kHz)
+    nmi,                           // Non-maskable interrupt (asynchronous)
+    per_dout,                      // Peripheral data output
+    pmem_dout,                     // Program Memory data output
+    reset_n,                       // Reset Pin (low active, asynchronous and non-glitchy)
+    scan_enable,                   // ASIC ONLY: Scan enable (active during scan shifting)
+    scan_mode,                     // ASIC ONLY: Scan mode
+    wkup                           // ASIC ONLY: System Wake-up (asynchronous and non-glitchy)
+);
+
+// OUTPUTs
+//=========
+output               aclk;         // ASIC ONLY: ACLK
+output               aclk_en;      // FPGA ONLY: ACLK enable
+output               dbg_freeze;   // Freeze peripherals
+output               dbg_uart_txd; // Debug interface: UART TXD
+output               dco_enable;   // ASIC ONLY: Fast oscillator enable
+output               dco_wkup;     // ASIC ONLY: Fast oscillator wake-up (asynchronous)
+output [`DMEM_MSB:0] dmem_addr;    // Data Memory address
+output               dmem_cen;     // Data Memory chip enable (low active)
+output        [15:0] dmem_din;     // Data Memory data input
+output         [1:0] dmem_wen;     // Data Memory write enable (low active)
+output        [13:0] irq_acc;      // Interrupt request accepted (one-hot signal)
+output               lfxt_enable;  // ASIC ONLY: Low frequency oscillator enable
+output               lfxt_wkup;    // ASIC ONLY: Low frequency oscillator wake-up (asynchronous)
+output               mclk;         // Main system clock
+output        [13:0] per_addr;     // Peripheral address
+output        [15:0] per_din;      // Peripheral data input
+output         [1:0] per_we;       // Peripheral write enable (high active)
+output               per_en;       // Peripheral enable (high active)
+output [`PMEM_MSB:0] pmem_addr;    // Program Memory address
+output               pmem_cen;     // Program Memory chip enable (low active)
+output        [15:0] pmem_din;     // Program Memory data input (optional)
+output         [1:0] pmem_wen;     // Program Memory write enable (low active) (optional)
+output               puc_rst;      // Main system reset
+output               smclk;        // ASIC ONLY: SMCLK
+output               smclk_en;     // FPGA ONLY: SMCLK enable
+
+
+// INPUTs
+//=========
+input                cpu_en;       // Enable CPU code execution (asynchronous and non-glitchy)
+input                dbg_en;       // Debug interface enable (asynchronous and non-glitchy)
+input                dbg_uart_rxd; // Debug interface: UART RXD (asynchronous)
+input                dco_clk;      // Fast oscillator (fast clock)
+input         [15:0] dmem_dout;    // Data Memory data output
+input                [13:0] irq;          // Maskable interrupts
+input                lfxt_clk;     // Low frequency oscillator (typ 32kHz)
+input                       nmi;          // Non-maskable interrupt (asynchronous and non-glitchy)
+input         [15:0] per_dout;     // Peripheral data output
+input         [15:0] pmem_dout;    // Program Memory data output
+input                reset_n;      // Reset Pin (active low, asynchronous and non-glitchy)
+input                scan_enable;  // ASIC ONLY: Scan enable (active during scan shifting)
+input                scan_mode;    // ASIC ONLY: Scan mode
+input                wkup;         // ASIC ONLY: System Wake-up (asynchronous and non-glitchy)
+
+
+
+//=============================================================================
+// 1)  INTERNAL WIRES/REGISTERS/PARAMETERS DECLARATION
+//=============================================================================
+
+wire          [7:0] inst_ad;
+wire          [7:0] inst_as;
+wire         [11:0] inst_alu;
+wire                inst_bw;
+wire                inst_irq_rst;
+wire                inst_mov;
+wire         [15:0] inst_dest;
+wire         [15:0] inst_dext;
+wire         [15:0] inst_sext;
+wire          [7:0] inst_so;
+wire         [15:0] inst_src;
+wire          [2:0] inst_type;
+wire          [7:0] inst_jmp;
+wire          [3:0] e_state;
+wire                exec_done;
+wire                decode_noirq;
+wire                cpu_en_s;
+wire                cpuoff;
+wire                oscoff;
+wire                scg0;
+wire                scg1;
+wire                por;
+wire                gie;
+wire                mclk_enable;
+wire                mclk_wkup;
+wire         [31:0] cpu_id;
+
+wire         [15:0] eu_mab;
+wire         [15:0] eu_mdb_in;
+wire         [15:0] eu_mdb_out;
+wire          [1:0] eu_mb_wr;
+wire                eu_mb_en;
+wire         [15:0] fe_mab;
+wire         [15:0] fe_mdb_in;
+wire                fe_mb_en;
+wire                fe_pmem_wait;
+
+wire                pc_sw_wr;
+wire         [15:0] pc_sw;
+wire         [15:0] pc;
+wire         [15:0] pc_nxt;
+
+wire                nmi_acc;
+wire                nmi_pnd;
+wire                nmi_wkup;
+
+wire                wdtie;
+wire                wdtnmies;
+wire                wdtifg;
+wire                wdt_irq;
+wire                wdt_wkup;
+wire                wdt_reset;
+wire                wdtifg_sw_clr;
+wire                wdtifg_sw_set;
+
+wire                dbg_clk;
+wire                dbg_rst;
+wire                dbg_en_s;
+wire                dbg_halt_st;
+wire                dbg_halt_cmd;
+wire                dbg_mem_en;
+wire                dbg_reg_wr;
+wire                dbg_cpu_reset;
+wire         [15:0] dbg_mem_addr;
+wire         [15:0] dbg_mem_dout;
+wire         [15:0] dbg_mem_din;
+wire         [15:0] dbg_reg_din;
+wire          [1:0] dbg_mem_wr;
+wire                puc_pnd_set;
+   
+wire         [15:0] per_dout_or;
+wire         [15:0] per_dout_sfr;
+wire         [15:0] per_dout_wdog;
+wire         [15:0] per_dout_mpy;
+wire         [15:0] per_dout_clk;
+
+   
+//=============================================================================
+// 2)  GLOBAL CLOCK & RESET MANAGEMENT
+//=============================================================================
+
+omsp_clock_module clock_module_0 (
+
+// OUTPUTs
+    .aclk         (aclk),          // ACLK
+    .aclk_en      (aclk_en),       // ACLK enablex
+    .cpu_en_s     (cpu_en_s),      // Enable CPU code execution (synchronous)
+    .dbg_clk      (dbg_clk),       // Debug unit clock
+    .dbg_en_s     (dbg_en_s),      // Debug interface enable (synchronous)
+    .dbg_rst      (dbg_rst),       // Debug unit reset
+    .dco_enable   (dco_enable),    // Fast oscillator enable
+    .dco_wkup     (dco_wkup),      // Fast oscillator wake-up (asynchronous)
+    .lfxt_enable  (lfxt_enable),   // Low frequency oscillator enable
+    .lfxt_wkup    (lfxt_wkup),     // Low frequency oscillator wake-up (asynchronous)
+    .mclk         (mclk),          // Main system clock
+    .per_dout     (per_dout_clk),  // Peripheral data output
+    .por          (por),           // Power-on reset
+    .puc_pnd_set  (puc_pnd_set),   // PUC pending set for the serial debug interface
+    .puc_rst      (puc_rst),       // Main system reset
+    .smclk        (smclk),         // SMCLK
+    .smclk_en     (smclk_en),      // SMCLK enable
+            
+// INPUTs
+    .cpu_en       (cpu_en),        // Enable CPU code execution (asynchronous)
+    .cpuoff       (cpuoff),        // Turns off the CPU
+    .dbg_cpu_reset(dbg_cpu_reset), // Reset CPU from debug interface
+    .dbg_en       (dbg_en),        // Debug interface enable (asynchronous)
+    .dco_clk      (dco_clk),       // Fast oscillator (fast clock)
+    .lfxt_clk     (lfxt_clk),      // Low frequency oscillator (typ 32kHz)
+    .mclk_enable  (mclk_enable),   // Main System Clock enable
+    .mclk_wkup    (mclk_wkup),     // Main System Clock wake-up (asynchronous)
+    .oscoff       (oscoff),        // Turns off LFXT1 clock input
+    .per_addr     (per_addr),      // Peripheral address
+    .per_din      (per_din),       // Peripheral data input
+    .per_en       (per_en),        // Peripheral enable (high active)
+    .per_we       (per_we),        // Peripheral write enable (high active)
+    .reset_n      (reset_n),       // Reset Pin (low active, asynchronous)
+    .scan_enable  (scan_enable),   // Scan enable (active during scan shifting)
+    .scan_mode    (scan_mode),     // Scan mode
+    .scg0         (scg0),          // System clock generator 1. Turns off the DCO
+    .scg1         (scg1),          // System clock generator 1. Turns off the SMCLK
+    .wdt_reset    (wdt_reset)      // Watchdog-timer reset
+);
+
+   
+//=============================================================================
+// 3)  FRONTEND (<=> FETCH & DECODE)
+//=============================================================================
+
+omsp_frontend frontend_0 (
+
+// OUTPUTs
+    .dbg_halt_st  (dbg_halt_st),   // Halt/Run status from CPU
+    .decode_noirq (decode_noirq),  // Frontend decode instruction
+    .e_state      (e_state),       // Execution state
+    .exec_done    (exec_done),     // Execution completed
+    .inst_ad      (inst_ad),       // Decoded Inst: destination addressing mode
+    .inst_as      (inst_as),       // Decoded Inst: source addressing mode
+    .inst_alu     (inst_alu),      // ALU control signals
+    .inst_bw      (inst_bw),       // Decoded Inst: byte width
+    .inst_dest    (inst_dest),     // Decoded Inst: destination (one hot)
+    .inst_dext    (inst_dext),     // Decoded Inst: destination extended instruction word
+    .inst_irq_rst (inst_irq_rst),  // Decoded Inst: Reset interrupt
+    .inst_jmp     (inst_jmp),      // Decoded Inst: Conditional jump
+    .inst_mov     (inst_mov),      // Decoded Inst: mov instruction
+    .inst_sext    (inst_sext),     // Decoded Inst: source extended instruction word
+    .inst_so      (inst_so),       // Decoded Inst: Single-operand arithmetic
+    .inst_src     (inst_src),      // Decoded Inst: source (one hot)
+    .inst_type    (inst_type),     // Decoded Instruction type
+    .irq_acc      (irq_acc),       // Interrupt request accepted
+    .mab          (fe_mab),        // Frontend Memory address bus
+    .mb_en        (fe_mb_en),      // Frontend Memory bus enable
+    .mclk_enable  (mclk_enable),   // Main System Clock enable
+    .mclk_wkup    (mclk_wkup),     // Main System Clock wake-up (asynchronous)
+    .nmi_acc      (nmi_acc),       // Non-Maskable interrupt request accepted
+    .pc           (pc),            // Program counter
+    .pc_nxt       (pc_nxt),        // Next PC value (for CALL & IRQ)
+                            
+// INPUTs
+    .cpu_en_s     (cpu_en_s),      // Enable CPU code execution (synchronous)
+    .cpuoff       (cpuoff),        // Turns off the CPU
+    .dbg_halt_cmd (dbg_halt_cmd),  // Halt CPU command
+    .dbg_reg_sel  (dbg_mem_addr[3:0]), // Debug selected register for rd/wr access
+    .fe_pmem_wait (fe_pmem_wait),  // Frontend wait for Instruction fetch
+    .gie          (gie),           // General interrupt enable
+    .irq          (irq),           // Maskable interrupts
+    .mclk         (mclk),          // Main system clock
+    .mdb_in       (fe_mdb_in),     // Frontend Memory data bus input
+    .nmi_pnd      (nmi_pnd),       // Non-maskable interrupt pending
+    .nmi_wkup     (nmi_wkup),      // NMI Wakeup
+    .pc_sw        (pc_sw),         // Program counter software value
+    .pc_sw_wr     (pc_sw_wr),      // Program counter software write
+    .puc_rst      (puc_rst),       // Main system reset
+    .scan_enable  (scan_enable),   // Scan enable (active during scan shifting)
+    .wdt_irq      (wdt_irq),       // Watchdog-timer interrupt
+    .wdt_wkup     (wdt_wkup),      // Watchdog Wakeup
+    .wkup         (wkup)           // System Wake-up (asynchronous)
+);
+
+
+//=============================================================================
+// 4)  EXECUTION UNIT
+//=============================================================================
+
+omsp_execution_unit execution_unit_0 (
+
+// OUTPUTs
+    .cpuoff       (cpuoff),        // Turns off the CPU
+    .dbg_reg_din  (dbg_reg_din),   // Debug unit CPU register data input
+    .mab          (eu_mab),        // Memory address bus
+    .mb_en        (eu_mb_en),      // Memory bus enable
+    .mb_wr        (eu_mb_wr),      // Memory bus write transfer
+    .mdb_out      (eu_mdb_out),    // Memory data bus output
+    .oscoff       (oscoff),        // Turns off LFXT1 clock input
+    .pc_sw        (pc_sw),         // Program counter software value
+    .pc_sw_wr     (pc_sw_wr),      // Program counter software write
+    .scg0         (scg0),          // System clock generator 1. Turns off the DCO
+    .scg1         (scg1),          // System clock generator 1. Turns off the SMCLK
+
+// INPUTs
+    .dbg_halt_st  (dbg_halt_st),   // Halt/Run status from CPU
+    .dbg_mem_dout (dbg_mem_dout),  // Debug unit data output
+    .dbg_reg_wr   (dbg_reg_wr),    // Debug unit CPU register write
+    .e_state      (e_state),       // Execution state
+    .exec_done    (exec_done),     // Execution completed
+    .gie          (gie),           // General interrupt enable
+    .inst_ad      (inst_ad),       // Decoded Inst: destination addressing mode
+    .inst_as      (inst_as),       // Decoded Inst: source addressing mode
+    .inst_alu     (inst_alu),      // ALU control signals
+    .inst_bw      (inst_bw),       // Decoded Inst: byte width
+    .inst_dest    (inst_dest),     // Decoded Inst: destination (one hot)
+    .inst_dext    (inst_dext),     // Decoded Inst: destination extended instruction word
+    .inst_irq_rst (inst_irq_rst),  // Decoded Inst: reset interrupt
+    .inst_jmp     (inst_jmp),      // Decoded Inst: Conditional jump
+    .inst_mov     (inst_mov),      // Decoded Inst: mov instruction
+    .inst_sext    (inst_sext),     // Decoded Inst: source extended instruction word
+    .inst_so      (inst_so),       // Decoded Inst: Single-operand arithmetic
+    .inst_src     (inst_src),      // Decoded Inst: source (one hot)
+    .inst_type    (inst_type),     // Decoded Instruction type
+    .mclk         (mclk),          // Main system clock
+    .mdb_in       (eu_mdb_in),     // Memory data bus input
+    .pc           (pc),            // Program counter
+    .pc_nxt       (pc_nxt),        // Next PC value (for CALL & IRQ)
+    .puc_rst      (puc_rst),       // Main system reset
+    .scan_enable  (scan_enable)    // Scan enable (active during scan shifting)
+);
+
+
+//=============================================================================
+// 5)  MEMORY BACKBONE
+//=============================================================================
+
+omsp_mem_backbone mem_backbone_0 (
+
+// OUTPUTs
+    .dbg_mem_din  (dbg_mem_din),   // Debug unit Memory data input
+    .dmem_addr    (dmem_addr),     // Data Memory address
+    .dmem_cen     (dmem_cen),      // Data Memory chip enable (low active)
+    .dmem_din     (dmem_din),      // Data Memory data input
+    .dmem_wen     (dmem_wen),      // Data Memory write enable (low active)
+    .eu_mdb_in    (eu_mdb_in),     // Execution Unit Memory data bus input
+    .fe_mdb_in    (fe_mdb_in),     // Frontend Memory data bus input
+    .fe_pmem_wait (fe_pmem_wait),  // Frontend wait for Instruction fetch
+    .per_addr     (per_addr),      // Peripheral address
+    .per_din      (per_din),       // Peripheral data input
+    .per_we       (per_we),        // Peripheral write enable (high active)
+    .per_en       (per_en),        // Peripheral enable (high active)
+    .pmem_addr    (pmem_addr),     // Program Memory address
+    .pmem_cen     (pmem_cen),      // Program Memory chip enable (low active)
+    .pmem_din     (pmem_din),      // Program Memory data input (optional)
+    .pmem_wen     (pmem_wen),      // Program Memory write enable (low active) (optional)
+                            
+// INPUTs
+    .dbg_halt_st  (dbg_halt_st),   // Halt/Run status from CPU
+    .dbg_mem_addr (dbg_mem_addr),  // Debug address for rd/wr access
+    .dbg_mem_dout (dbg_mem_dout),  // Debug unit data output
+    .dbg_mem_en   (dbg_mem_en),    // Debug unit memory enable
+    .dbg_mem_wr   (dbg_mem_wr),    // Debug unit memory write
+    .dmem_dout    (dmem_dout),     // Data Memory data output
+    .eu_mab       (eu_mab[15:1]),  // Execution Unit Memory address bus
+    .eu_mb_en     (eu_mb_en),      // Execution Unit Memory bus enable
+    .eu_mb_wr     (eu_mb_wr),      // Execution Unit Memory bus write transfer
+    .eu_mdb_out   (eu_mdb_out),    // Execution Unit Memory data bus output
+    .fe_mab       (fe_mab[15:1]),  // Frontend Memory address bus
+    .fe_mb_en     (fe_mb_en),      // Frontend Memory bus enable
+    .mclk         (mclk),          // Main system clock
+    .per_dout     (per_dout_or),   // Peripheral data output
+    .pmem_dout    (pmem_dout),     // Program Memory data output
+    .puc_rst      (puc_rst),       // Main system reset
+    .scan_enable  (scan_enable)    // Scan enable (active during scan shifting)
+);
+
+
+//=============================================================================
+// 6)  SPECIAL FUNCTION REGISTERS
+//=============================================================================
+omsp_sfr sfr_0 (
+
+// OUTPUTs
+    .cpu_id       (cpu_id),        // CPU ID
+    .nmi_pnd      (nmi_pnd),       // NMI Pending
+    .nmi_wkup     (nmi_wkup),      // NMI Wakeup
+    .per_dout     (per_dout_sfr),  // Peripheral data output
+    .wdtie        (wdtie),         // Watchdog-timer interrupt enable
+    .wdtifg_sw_clr(wdtifg_sw_clr), // Watchdog-timer interrupt flag software clear
+    .wdtifg_sw_set(wdtifg_sw_set), // Watchdog-timer interrupt flag software set
+                            
+// INPUTs
+    .mclk         (mclk),          // Main system clock
+    .nmi          (nmi),           // Non-maskable interrupt (asynchronous)
+    .nmi_acc      (nmi_acc),       // Non-Maskable interrupt request accepted
+    .per_addr     (per_addr),      // Peripheral address
+    .per_din      (per_din),       // Peripheral data input
+    .per_en       (per_en),        // Peripheral enable (high active)
+    .per_we       (per_we),        // Peripheral write enable (high active)
+    .puc_rst      (puc_rst),       // Main system reset
+    .scan_mode    (scan_mode),     // Scan mode
+    .wdtifg       (wdtifg),        // Watchdog-timer interrupt flag
+    .wdtnmies     (wdtnmies)       // Watchdog-timer NMI edge selection
+);
+
+
+//=============================================================================
+// 7)  WATCHDOG TIMER
+//=============================================================================
+`ifdef WATCHDOG
+omsp_watchdog watchdog_0 (
+
+// OUTPUTs
+    .per_dout       (per_dout_wdog), // Peripheral data output
+    .wdt_irq        (wdt_irq),       // Watchdog-timer interrupt
+    .wdt_reset      (wdt_reset),     // Watchdog-timer reset
+    .wdt_wkup       (wdt_wkup),      // Watchdog Wakeup
+    .wdtifg         (wdtifg),        // Watchdog-timer interrupt flag
+    .wdtnmies       (wdtnmies),      // Watchdog-timer NMI edge selection
+                            
+// INPUTs
+    .aclk           (aclk),          // ACLK
+    .aclk_en        (aclk_en),       // ACLK enable
+    .dbg_freeze     (dbg_freeze),    // Freeze Watchdog counter
+    .mclk           (mclk),          // Main system clock
+    .per_addr       (per_addr),      // Peripheral address
+    .per_din        (per_din),       // Peripheral data input
+    .per_en         (per_en),        // Peripheral enable (high active)
+    .per_we         (per_we),        // Peripheral write enable (high active)
+    .por            (por),           // Power-on reset
+    .puc_rst        (puc_rst),       // Main system reset
+    .scan_enable    (scan_enable),   // Scan enable (active during scan shifting)
+    .scan_mode      (scan_mode),     // Scan mode
+    .smclk          (smclk),         // SMCLK
+    .smclk_en       (smclk_en),      // SMCLK enable
+    .wdtie          (wdtie),         // Watchdog-timer interrupt enable
+    .wdtifg_irq_clr (irq_acc[10]),   // Clear Watchdog-timer interrupt flag
+    .wdtifg_sw_clr  (wdtifg_sw_clr), // Watchdog-timer interrupt flag software clear
+    .wdtifg_sw_set  (wdtifg_sw_set)  // Watchdog-timer interrupt flag software set
+);
+`else
+assign per_dout_wdog = 16'h0000;
+assign wdt_irq       =  1'b0;
+assign wdt_reset     =  1'b0;
+assign wdt_wkup      =  1'b0;
+assign wdtifg        =  1'b0;
+assign wdtnmies      =  1'b0;
+`endif
+
+
+//=============================================================================
+// 8)  HARDWARE MULTIPLIER
+//=============================================================================
+`ifdef MULTIPLIER
+omsp_multiplier multiplier_0 (
+
+// OUTPUTs
+    .per_dout     (per_dout_mpy),  // Peripheral data output
+                            
+// INPUTs
+    .mclk         (mclk),          // Main system clock
+    .per_addr     (per_addr),      // Peripheral address
+    .per_din      (per_din),       // Peripheral data input
+    .per_en       (per_en),        // Peripheral enable (high active)
+    .per_we       (per_we),        // Peripheral write enable (high active)
+    .puc_rst      (puc_rst),       // Main system reset
+    .scan_enable  (scan_enable)    // Scan enable (active during scan shifting)
+);
+`else
+assign per_dout_mpy = 16'h0000;
+`endif
+   
+//=============================================================================
+// 9)  PERIPHERALS' OUTPUT BUS
+//=============================================================================
+
+assign  per_dout_or  =  per_dout      |
+                        per_dout_clk  |
+                        per_dout_sfr  |
+                        per_dout_wdog |
+                        per_dout_mpy;
+
+   
+//=============================================================================
+// 10)  DEBUG INTERFACE
+//=============================================================================
+
+`ifdef DBG_EN
+omsp_dbg dbg_0 (
+
+// OUTPUTs
+    .dbg_freeze   (dbg_freeze),    // Freeze peripherals
+    .dbg_halt_cmd (dbg_halt_cmd),  // Halt CPU command
+    .dbg_mem_addr (dbg_mem_addr),  // Debug address for rd/wr access
+    .dbg_mem_dout (dbg_mem_dout),  // Debug unit data output
+    .dbg_mem_en   (dbg_mem_en),    // Debug unit memory enable
+    .dbg_mem_wr   (dbg_mem_wr),    // Debug unit memory write
+    .dbg_reg_wr   (dbg_reg_wr),    // Debug unit CPU register write
+    .dbg_cpu_reset(dbg_cpu_reset), // Reset CPU from debug interface
+    .dbg_uart_txd (dbg_uart_txd),  // Debug interface: UART TXD
+                            
+// INPUTs
+    .cpu_en_s     (cpu_en_s),      // Enable CPU code execution (synchronous)
+    .cpu_id       (cpu_id),        // CPU ID
+    .dbg_clk      (dbg_clk),       // Debug unit clock
+    .dbg_en_s     (dbg_en_s),      // Debug interface enable (synchronous)
+    .dbg_halt_st  (dbg_halt_st),   // Halt/Run status from CPU
+    .dbg_mem_din  (dbg_mem_din),   // Debug unit Memory data input
+    .dbg_reg_din  (dbg_reg_din),   // Debug unit CPU register data input
+    .dbg_rst      (dbg_rst),       // Debug unit reset
+    .dbg_uart_rxd (dbg_uart_rxd),  // Debug interface: UART RXD (asynchronous)
+    .decode_noirq (decode_noirq),  // Frontend decode instruction
+    .eu_mab       (eu_mab),        // Execution-Unit Memory address bus
+    .eu_mb_en     (eu_mb_en),      // Execution-Unit Memory bus enable
+    .eu_mb_wr     (eu_mb_wr),      // Execution-Unit Memory bus write transfer
+    .eu_mdb_in    (eu_mdb_in),     // Memory data bus input
+    .eu_mdb_out   (eu_mdb_out),    // Memory data bus output
+    .exec_done    (exec_done),     // Execution completed
+    .fe_mb_en     (fe_mb_en),      // Frontend Memory bus enable
+    .fe_mdb_in    (fe_mdb_in),     // Frontend Memory data bus input
+    .pc           (pc),            // Program counter
+    .puc_pnd_set  (puc_pnd_set)    // PUC pending set for the serial debug interface
+);
+
+`else
+assign dbg_freeze    =  ~cpu_en_s;
+assign dbg_halt_cmd  =  1'b0;
+assign dbg_mem_addr  = 16'h0000;
+assign dbg_mem_dout  = 16'h0000;
+assign dbg_mem_en    =  1'b0;
+assign dbg_mem_wr    =  2'b00;
+assign dbg_reg_wr    =  1'b0;
+assign dbg_cpu_reset =  1'b0;
+assign dbg_uart_txd  =  1'b0;
+`endif
+
+   
+endmodule // openMSP430
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
diff --git a/tests/openmsp430/rtl/openMSP430_defines.v b/tests/openmsp430/rtl/openMSP430_defines.v
new file mode 100644 (file)
index 0000000..368f7a5
--- /dev/null
@@ -0,0 +1,843 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+// 
+// *File Name: openMSP430_defines.v
+// 
+// *Module Description:
+//                      openMSP430 Configuration file
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 151 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2012-07-23 00:24:11 +0200 (Mon, 23 Jul 2012) $
+//----------------------------------------------------------------------------
+//`define OMSP_NO_INCLUDE
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif
+
+//============================================================================
+//============================================================================
+// BASIC SYSTEM CONFIGURATION
+//============================================================================
+//============================================================================
+//
+// Note: the sum of program, data and peripheral memory spaces must not
+//      exceed 64 kB
+//
+
+// Program Memory Size:
+//                     Uncomment the required memory size
+//-------------------------------------------------------
+//`define PMEM_SIZE_CUSTOM
+//`define PMEM_SIZE_59_KB
+//`define PMEM_SIZE_55_KB
+//`define PMEM_SIZE_54_KB
+//`define PMEM_SIZE_51_KB
+//`define PMEM_SIZE_48_KB
+//`define PMEM_SIZE_41_KB
+//`define PMEM_SIZE_32_KB
+//`define PMEM_SIZE_24_KB
+//`define PMEM_SIZE_16_KB
+//`define PMEM_SIZE_12_KB
+//`define PMEM_SIZE_8_KB
+//`define PMEM_SIZE_4_KB
+`define PMEM_SIZE_2_KB
+//`define PMEM_SIZE_1_KB
+
+
+// Data Memory Size:
+//                     Uncomment the required memory size
+//-------------------------------------------------------
+//`define DMEM_SIZE_CUSTOM
+//`define DMEM_SIZE_32_KB
+//`define DMEM_SIZE_24_KB
+//`define DMEM_SIZE_16_KB
+//`define DMEM_SIZE_10_KB
+//`define DMEM_SIZE_8_KB
+//`define DMEM_SIZE_5_KB
+//`define DMEM_SIZE_4_KB
+//`define DMEM_SIZE_2p5_KB
+//`define DMEM_SIZE_2_KB
+//`define DMEM_SIZE_1_KB
+//`define DMEM_SIZE_512_B
+//`define DMEM_SIZE_256_B
+`define DMEM_SIZE_128_B
+
+
+// Include/Exclude Hardware Multiplier
+`define MULTIPLIER
+
+
+// Include/Exclude Serial Debug interface
+`define DBG_EN
+
+
+//============================================================================
+//============================================================================
+// ADVANCED SYSTEM CONFIGURATION (FOR EXPERIENCED USERS)
+//============================================================================
+//============================================================================
+
+//-------------------------------------------------------
+// Custom user version number
+//-------------------------------------------------------
+// This 5 bit field can be freely used in order to allow
+// custom identification of the system through the debug
+// interface.
+// (see CPU_ID.USER_VERSION field in the documentation)
+//-------------------------------------------------------
+`define USER_VERSION 5'b00000
+
+
+//-------------------------------------------------------
+// Include/Exclude Watchdog timer
+//-------------------------------------------------------
+// When excluded, the following functionality will be
+// lost:
+//        - Watchog (both interval and watchdog modes)
+//        - NMI interrupt edge selection
+//        - Possibility to generate a software PUC reset
+//-------------------------------------------------------
+`define WATCHDOG
+
+
+///-------------------------------------------------------
+// Include/Exclude Non-Maskable-Interrupt support
+//-------------------------------------------------------
+`define NMI
+
+
+//-------------------------------------------------------
+// Input synchronizers
+//-------------------------------------------------------
+// In some cases, the asynchronous input ports might
+// already be synchronized externally.
+// If an extensive CDC design review showed that this
+// is really the case,  the individual synchronizers
+// can be disabled with the following defines.
+//
+// Notes:
+//        - all three signals are all sampled in the MCLK domain
+//
+//        - the dbg_en signal reset the debug interface
+//         when 0. Therefore make sure it is glitch free.
+//
+//-------------------------------------------------------
+`define SYNC_NMI
+//`define SYNC_CPU_EN
+//`define SYNC_DBG_EN
+
+
+//-------------------------------------------------------
+// Peripheral Memory Space:
+//-------------------------------------------------------
+// The original MSP430 architecture map the peripherals
+// from 0x0000 to 0x01FF (i.e. 512B of the memory space).
+// The following defines allow you to expand this space
+// up to 32 kB (i.e. from 0x0000 to 0x7fff).
+// As a consequence, the data memory mapping will be
+// shifted up and a custom linker script will therefore
+// be required by the GCC compiler.
+//-------------------------------------------------------
+//`define PER_SIZE_CUSTOM
+//`define PER_SIZE_32_KB
+//`define PER_SIZE_16_KB
+//`define PER_SIZE_8_KB
+//`define PER_SIZE_4_KB
+//`define PER_SIZE_2_KB
+//`define PER_SIZE_1_KB
+`define PER_SIZE_512_B
+
+
+//-------------------------------------------------------
+// Defines the debugger CPU_CTL.RST_BRK_EN reset value
+// (CPU break on PUC reset)
+//-------------------------------------------------------
+// When defined, the CPU will automatically break after
+// a PUC occurrence by default. This is typically useful
+// when the program memory can only be initialized through
+// the serial debug interface.
+//-------------------------------------------------------
+`define DBG_RST_BRK_EN
+
+
+//============================================================================
+//============================================================================
+// EXPERT SYSTEM CONFIGURATION ( !!!! EXPERTS ONLY !!!! )
+//============================================================================
+//============================================================================
+//
+// IMPORTANT NOTE:  Please update following configuration options ONLY if
+//                 you have a good reason to do so... and if you know what
+//                 you are doing :-P
+//
+//============================================================================
+
+//-------------------------------------------------------
+// Number of hardware breakpoint/watchpoint units
+// (each unit contains two hardware addresses available
+// for breakpoints or watchpoints):
+//   - DBG_HWBRK_0 -> Include hardware breakpoints unit 0
+//   - DBG_HWBRK_1 -> Include hardware breakpoints unit 1
+//   - DBG_HWBRK_2 -> Include hardware breakpoints unit 2
+//   - DBG_HWBRK_3 -> Include hardware breakpoints unit 3
+//-------------------------------------------------------
+// Please keep in mind that hardware breakpoints only
+// make sense whenever the program memory is not an SRAM
+// (i.e. Flash/OTP/ROM/...) or when you are interested
+// in data breakpoints.
+//-------------------------------------------------------
+//`define  DBG_HWBRK_0
+//`define  DBG_HWBRK_1
+//`define  DBG_HWBRK_2
+//`define  DBG_HWBRK_3
+
+
+//-------------------------------------------------------
+// Enable/Disable the hardware breakpoint RANGE mode
+//-------------------------------------------------------
+// When enabled this feature allows the hardware breakpoint
+// units to stop the cpu whenever an instruction or data
+// access lays within an address range.
+// Note that this feature is not supported by GDB.
+//-------------------------------------------------------
+//`define DBG_HWBRK_RANGE
+
+
+//-------------------------------------------------------
+// Custom Program/Data and Peripheral Memory Spaces
+//-------------------------------------------------------
+// The following values are valid only if the
+// corresponding *_SIZE_CUSTOM defines are uncommented:
+//
+//  - *_SIZE   : size of the section in bytes.
+//  - *_AWIDTH : address port width, this value must allow
+//               to address all WORDS of the section
+//               (i.e. the *_SIZE divided by 2)
+//-------------------------------------------------------
+
+// Custom Program memory (enabled with PMEM_SIZE_CUSTOM)
+`define PMEM_CUSTOM_AWIDTH      10
+`define PMEM_CUSTOM_SIZE      2028
+
+// Custom Data memory    (enabled with DMEM_SIZE_CUSTOM)
+`define DMEM_CUSTOM_AWIDTH       6
+`define DMEM_CUSTOM_SIZE       128
+
+// Custom Peripheral memory  (enabled with PER_SIZE_CUSTOM)
+`define PER_CUSTOM_AWIDTH        8
+`define PER_CUSTOM_SIZE        512
+
+
+//-------------------------------------------------------
+// ASIC version
+//-------------------------------------------------------
+// When uncommented, this define will enable the
+// ASIC system configuration section (see below) and
+// will activate scan support for production test.
+//
+// WARNING: if you target an FPGA, leave this define
+//          commented.
+//-------------------------------------------------------
+//`define ASIC
+
+
+//============================================================================
+//============================================================================
+// ASIC SYSTEM CONFIGURATION ( !!!! EXPERTS/PROFESSIONALS ONLY !!!! )
+//============================================================================
+//============================================================================
+`ifdef ASIC
+
+//===============================================================
+// FINE GRAINED CLOCK GATING
+//===============================================================
+
+//-------------------------------------------------------
+// When uncommented, this define will enable the fine
+// grained clock gating of all registers in the core.
+//-------------------------------------------------------
+`define CLOCK_GATING
+
+
+//===============================================================
+// LFXT CLOCK DOMAIN
+//===============================================================
+
+//-------------------------------------------------------
+// When uncommented, this define will enable the lfxt_clk
+// clock domain.
+// When commented out, the whole chip is clocked with dco_clk.
+//-------------------------------------------------------
+`define LFXT_DOMAIN
+
+
+//===============================================================
+// CLOCK MUXES
+//===============================================================
+
+//-------------------------------------------------------
+// MCLK: Clock Mux
+//-------------------------------------------------------
+// When uncommented, this define will enable the
+// MCLK clock MUX allowing the selection between
+// DCO_CLK and LFXT_CLK with the BCSCTL2.SELMx register.
+// When commented, DCO_CLK is selected.
+//-------------------------------------------------------
+`define MCLK_MUX
+
+//-------------------------------------------------------
+// SMCLK: Clock Mux
+//-------------------------------------------------------
+// When uncommented, this define will enable the
+// SMCLK clock MUX allowing the selection between
+// DCO_CLK and LFXT_CLK with the BCSCTL2.SELS register.
+// When commented, DCO_CLK is selected.
+//-------------------------------------------------------
+`define SMCLK_MUX
+
+//-------------------------------------------------------
+// WATCHDOG: Clock Mux
+//-------------------------------------------------------
+// When uncommented, this define will enable the
+// Watchdog clock MUX allowing the selection between
+// ACLK and SMCLK with the WDTCTL.WDTSSEL register.
+// When commented out, ACLK is selected if the
+// WATCHDOG_NOMUX_ACLK define is uncommented, SMCLK is
+// selected otherwise.
+//-------------------------------------------------------
+`define WATCHDOG_MUX
+//`define WATCHDOG_NOMUX_ACLK
+
+
+//===============================================================
+// CLOCK DIVIDERS
+//===============================================================
+
+//-------------------------------------------------------
+// MCLK: Clock divider
+//-------------------------------------------------------
+// When uncommented, this define will enable the
+// MCLK clock divider (/1/2/4/8)
+//-------------------------------------------------------
+`define MCLK_DIVIDER
+
+//-------------------------------------------------------
+// SMCLK: Clock divider (/1/2/4/8)
+//-------------------------------------------------------
+// When uncommented, this define will enable the
+// SMCLK clock divider
+//-------------------------------------------------------
+`define SMCLK_DIVIDER
+
+//-------------------------------------------------------
+// ACLK: Clock divider (/1/2/4/8)
+//-------------------------------------------------------
+// When uncommented, this define will enable the
+// ACLK clock divider
+//-------------------------------------------------------
+`define ACLK_DIVIDER
+
+
+//===============================================================
+// LOW POWER MODES
+//===============================================================
+
+//-------------------------------------------------------
+// LOW POWER MODE: CPUOFF
+//-------------------------------------------------------
+// When uncommented, this define will include the
+// clock gate allowing to switch off MCLK in
+// all low power modes: LPM0, LPM1, LPM2, LPM3, LPM4
+//-------------------------------------------------------
+`define CPUOFF_EN
+
+//-------------------------------------------------------
+// LOW POWER MODE: SCG0
+//-------------------------------------------------------
+// When uncommented, this define will enable the
+// DCO_ENABLE/WKUP port control (always 1 when commented).
+// This allows to switch off the DCO oscillator in the
+// following low power modes: LPM1, LPM3, LPM4
+//-------------------------------------------------------
+`define SCG0_EN
+
+//-------------------------------------------------------
+// LOW POWER MODE: SCG1
+//-------------------------------------------------------
+// When uncommented, this define will include the
+// clock gate allowing to switch off SMCLK in
+// the following low power modes: LPM2, LPM3, LPM4
+//-------------------------------------------------------
+`define SCG1_EN
+
+//-------------------------------------------------------
+// LOW POWER MODE: OSCOFF
+//-------------------------------------------------------
+// When uncommented, this define will include the
+// LFXT_CLK clock gate and enable the LFXT_ENABLE/WKUP
+// port control (always 1 when commented).
+// This allows to switch off the low frequency oscillator
+// in the following low power modes: LPM4
+//-------------------------------------------------------
+`define OSCOFF_EN
+
+
+
+`endif
+
+//==========================================================================//
+//==========================================================================//
+//==========================================================================//
+//==========================================================================//
+//=====        SYSTEM CONSTANTS --- !!!!!!!! DO NOT EDIT !!!!!!!!      =====//
+//==========================================================================//
+//==========================================================================//
+//==========================================================================//
+//==========================================================================//
+
+//
+// PROGRAM, DATA & PERIPHERAL MEMORY CONFIGURATION
+//==================================================
+
+// Program Memory Size
+`ifdef PMEM_SIZE_59_KB
+  `define PMEM_AWIDTH      15
+  `define PMEM_SIZE     60416
+`endif
+`ifdef PMEM_SIZE_55_KB
+  `define PMEM_AWIDTH      15
+  `define PMEM_SIZE     56320
+`endif
+`ifdef PMEM_SIZE_54_KB
+  `define PMEM_AWIDTH      15
+  `define PMEM_SIZE     55296
+`endif
+`ifdef PMEM_SIZE_51_KB
+  `define PMEM_AWIDTH      15
+  `define PMEM_SIZE     52224
+`endif
+`ifdef PMEM_SIZE_48_KB
+  `define PMEM_AWIDTH      15
+  `define PMEM_SIZE     49152
+`endif
+`ifdef PMEM_SIZE_41_KB
+  `define PMEM_AWIDTH      15
+  `define PMEM_SIZE     41984
+`endif
+`ifdef PMEM_SIZE_32_KB
+  `define PMEM_AWIDTH      14
+  `define PMEM_SIZE     32768
+`endif
+`ifdef PMEM_SIZE_24_KB
+  `define PMEM_AWIDTH      14
+  `define PMEM_SIZE     24576
+`endif
+`ifdef PMEM_SIZE_16_KB
+  `define PMEM_AWIDTH      13
+  `define PMEM_SIZE     16384
+`endif
+`ifdef PMEM_SIZE_12_KB
+  `define PMEM_AWIDTH      13
+  `define PMEM_SIZE     12288
+`endif
+`ifdef PMEM_SIZE_8_KB
+  `define PMEM_AWIDTH      12
+  `define PMEM_SIZE      8192
+`endif
+`ifdef PMEM_SIZE_4_KB
+  `define PMEM_AWIDTH      11
+  `define PMEM_SIZE      4096
+`endif
+`ifdef PMEM_SIZE_2_KB
+  `define PMEM_AWIDTH      10
+  `define PMEM_SIZE      2048
+`endif
+`ifdef PMEM_SIZE_1_KB
+  `define PMEM_AWIDTH       9
+  `define PMEM_SIZE      1024
+`endif
+`ifdef PMEM_SIZE_CUSTOM
+  `define PMEM_AWIDTH       `PMEM_CUSTOM_AWIDTH
+  `define PMEM_SIZE         `PMEM_CUSTOM_SIZE
+`endif
+
+// Data Memory Size
+`ifdef DMEM_SIZE_32_KB
+  `define DMEM_AWIDTH       14
+  `define DMEM_SIZE      32768
+`endif
+`ifdef DMEM_SIZE_24_KB
+  `define DMEM_AWIDTH       14
+  `define DMEM_SIZE      24576
+`endif
+`ifdef DMEM_SIZE_16_KB
+  `define DMEM_AWIDTH       13
+  `define DMEM_SIZE      16384
+`endif
+`ifdef DMEM_SIZE_10_KB
+  `define DMEM_AWIDTH       13
+  `define DMEM_SIZE      10240
+`endif
+`ifdef DMEM_SIZE_8_KB
+  `define DMEM_AWIDTH       12
+  `define DMEM_SIZE       8192
+`endif
+`ifdef DMEM_SIZE_5_KB
+  `define DMEM_AWIDTH       12
+  `define DMEM_SIZE       5120
+`endif
+`ifdef DMEM_SIZE_4_KB
+  `define DMEM_AWIDTH       11
+  `define DMEM_SIZE       4096
+`endif
+`ifdef DMEM_SIZE_2p5_KB
+  `define DMEM_AWIDTH       11
+  `define DMEM_SIZE       2560
+`endif
+`ifdef DMEM_SIZE_2_KB
+  `define DMEM_AWIDTH       10
+  `define DMEM_SIZE       2048
+`endif
+`ifdef DMEM_SIZE_1_KB
+  `define DMEM_AWIDTH        9
+  `define DMEM_SIZE       1024
+`endif
+`ifdef DMEM_SIZE_512_B
+  `define DMEM_AWIDTH        8
+  `define DMEM_SIZE        512
+`endif
+`ifdef DMEM_SIZE_256_B
+  `define DMEM_AWIDTH        7
+  `define DMEM_SIZE        256
+`endif
+`ifdef DMEM_SIZE_128_B
+  `define DMEM_AWIDTH        6
+  `define DMEM_SIZE        128
+`endif
+`ifdef DMEM_SIZE_CUSTOM
+  `define DMEM_AWIDTH       `DMEM_CUSTOM_AWIDTH
+  `define DMEM_SIZE         `DMEM_CUSTOM_SIZE
+`endif
+
+// Peripheral Memory Size
+`ifdef PER_SIZE_32_KB
+  `define PER_AWIDTH        14
+  `define PER_SIZE       32768
+`endif
+`ifdef PER_SIZE_16_KB
+  `define PER_AWIDTH        13
+  `define PER_SIZE       16384
+`endif
+`ifdef PER_SIZE_8_KB
+  `define PER_AWIDTH        12
+  `define PER_SIZE        8192
+`endif
+`ifdef PER_SIZE_4_KB
+  `define PER_AWIDTH        11
+  `define PER_SIZE        4096
+`endif
+`ifdef PER_SIZE_2_KB
+  `define PER_AWIDTH        10
+  `define PER_SIZE        2048
+`endif
+`ifdef PER_SIZE_1_KB
+  `define PER_AWIDTH         9
+  `define PER_SIZE        1024
+`endif
+`ifdef PER_SIZE_512_B
+  `define PER_AWIDTH         8
+  `define PER_SIZE         512
+`endif
+`ifdef PER_SIZE_CUSTOM
+  `define PER_AWIDTH        `PER_CUSTOM_AWIDTH
+  `define PER_SIZE          `PER_CUSTOM_SIZE
+`endif
+
+// Data Memory Base Adresses
+`define DMEM_BASE  `PER_SIZE
+
+// Program & Data Memory most significant address bit (for 16 bit words)
+`define PMEM_MSB   `PMEM_AWIDTH-1
+`define DMEM_MSB   `DMEM_AWIDTH-1
+`define PER_MSB    `PER_AWIDTH-1
+
+//
+// STATES, REGISTER FIELDS, ...
+//======================================
+
+// Instructions type
+`define INST_SO  0
+`define INST_JMP 1
+`define INST_TO  2
+
+// Single-operand arithmetic
+`define RRC    0
+`define SWPB   1
+`define RRA    2
+`define SXT    3
+`define PUSH   4
+`define CALL   5
+`define RETI   6
+`define IRQ    7
+
+// Conditional jump
+`define JNE    0
+`define JEQ    1
+`define JNC    2
+`define JC     3
+`define JN     4
+`define JGE    5
+`define JL     6
+`define JMP    7
+
+// Two-operand arithmetic
+`define MOV    0
+`define ADD    1
+`define ADDC   2
+`define SUBC   3
+`define SUB    4
+`define CMP    5
+`define DADD   6
+`define BIT    7
+`define BIC    8
+`define BIS    9
+`define XOR   10
+`define AND   11
+
+// Addressing modes
+`define DIR      0
+`define IDX      1
+`define INDIR    2
+`define INDIR_I  3
+`define SYMB     4
+`define IMM      5
+`define ABS      6
+`define CONST    7
+
+// Instruction state machine
+`define I_IRQ_FETCH 3'h0
+`define I_IRQ_DONE  3'h1
+`define I_DEC       3'h2
+`define I_EXT1      3'h3
+`define I_EXT2      3'h4
+`define I_IDLE      3'h5
+
+// Execution state machine
+// (swapped E_IRQ_0 and E_IRQ_2 values to suppress glitch generation warning from lint tool)
+`define E_IRQ_0     4'h2
+`define E_IRQ_1     4'h1
+`define E_IRQ_2     4'h0
+`define E_IRQ_3     4'h3
+`define E_IRQ_4     4'h4
+`define E_SRC_AD    4'h5
+`define E_SRC_RD    4'h6
+`define E_SRC_WR    4'h7
+`define E_DST_AD    4'h8
+`define E_DST_RD    4'h9
+`define E_DST_WR    4'hA
+`define E_EXEC      4'hB
+`define E_JUMP      4'hC
+`define E_IDLE      4'hD
+
+// ALU control signals
+`define ALU_SRC_INV   0
+`define ALU_INC       1
+`define ALU_INC_C     2
+`define ALU_ADD       3
+`define ALU_AND       4
+`define ALU_OR        5
+`define ALU_XOR       6
+`define ALU_DADD      7
+`define ALU_STAT_7    8
+`define ALU_STAT_F    9
+`define ALU_SHIFT    10
+`define EXEC_NO_WR   11
+
+// Debug interface
+`define DBG_UART_WR   18
+`define DBG_UART_BW   17
+`define DBG_UART_ADDR 16:11
+
+// Debug interface CPU_CTL register
+`define HALT        0
+`define RUN         1
+`define ISTEP       2
+`define SW_BRK_EN   3
+`define FRZ_BRK_EN  4
+`define RST_BRK_EN  5
+`define CPU_RST     6
+
+// Debug interface CPU_STAT register
+`define HALT_RUN    0
+`define PUC_PND     1
+`define SWBRK_PND   3
+`define HWBRK0_PND  4
+`define HWBRK1_PND  5
+
+// Debug interface BRKx_CTL register
+`define BRK_MODE_RD 0
+`define BRK_MODE_WR 1
+`define BRK_MODE    1:0
+`define BRK_EN      2
+`define BRK_I_EN    3
+`define BRK_RANGE   4
+
+// Basic clock module: BCSCTL1 Control Register
+`define DIVAx       5:4
+
+// Basic clock module: BCSCTL2 Control Register
+`define SELMx       7
+`define DIVMx       5:4
+`define SELS        3
+`define DIVSx       2:1
+
+// MCLK Clock gate
+`ifdef CPUOFF_EN
+  `define MCLK_CGATE
+`else
+`ifdef MCLK_DIVIDER
+  `define MCLK_CGATE
+`endif
+`endif
+
+// SMCLK Clock gate
+`ifdef SCG1_EN
+  `define SMCLK_CGATE
+`else
+`ifdef SMCLK_DIVIDER
+  `define SMCLK_CGATE
+`endif
+`endif
+
+//
+// DEBUG INTERFACE EXTRA CONFIGURATION
+//======================================
+
+// Debug interface: CPU version
+`define CPU_VERSION   3'h2
+
+// Debug interface: Software breakpoint opcode
+`define DBG_SWBRK_OP 16'h4343
+
+// Debug UART interface auto data synchronization
+// If the following define is commented out, then
+// the DBG_UART_BAUD and DBG_DCO_FREQ need to be properly
+// defined.
+`define DBG_UART_AUTO_SYNC
+
+// Debug UART interface data rate
+//      In order to properly setup the UART debug interface, you
+//      need to specify the DCO_CLK frequency (DBG_DCO_FREQ) and
+//      the chosen BAUD rate from the UART interface.
+//
+//`define DBG_UART_BAUD    9600
+//`define DBG_UART_BAUD   19200
+//`define DBG_UART_BAUD   38400
+//`define DBG_UART_BAUD   57600
+//`define DBG_UART_BAUD  115200
+//`define DBG_UART_BAUD  230400
+//`define DBG_UART_BAUD  460800
+//`define DBG_UART_BAUD  576000
+//`define DBG_UART_BAUD  921600
+`define DBG_UART_BAUD 2000000
+`define DBG_DCO_FREQ  20000000
+`define DBG_UART_CNT ((`DBG_DCO_FREQ/`DBG_UART_BAUD)-1)
+
+// Debug interface selection
+//             `define DBG_UART -> Enable UART (8N1) debug interface
+//             `define DBG_JTAG -> DON'T UNCOMMENT, NOT SUPPORTED
+//
+`define DBG_UART
+//`define DBG_JTAG
+
+// Debug interface input synchronizer
+`define SYNC_DBG_UART_RXD
+
+// Enable/Disable the hardware breakpoint RANGE mode
+`ifdef DBG_HWBRK_RANGE
+ `define HWBRK_RANGE 1'b1
+`else
+ `define HWBRK_RANGE 1'b0
+`endif
+
+// Counter width for the debug interface UART
+`define DBG_UART_XFER_CNT_W 16
+
+// Check configuration
+`ifdef DBG_EN
+ `ifdef DBG_UART
+   `ifdef DBG_JTAG
+CONFIGURATION ERROR: JTAG AND UART DEBUG INTERFACE ARE BOTH ENABLED
+   `endif
+ `else
+   `ifdef DBG_JTAG
+CONFIGURATION ERROR: JTAG INTERFACE NOT SUPPORTED
+   `else
+CONFIGURATION ERROR: JTAG OR UART DEBUG INTERFACE SHOULD BE ENABLED
+   `endif
+ `endif
+`endif
+
+//
+// MULTIPLIER CONFIGURATION
+//======================================
+
+// If uncommented, the following define selects
+// the 16x16 multiplier (1 cycle) instead of the
+// default 16x8 multplier (2 cycles)
+//`define MPY_16x16
+  
+//======================================
+// CONFIGURATION CHECKS
+//======================================
+`ifdef LFXT_DOMAIN
+`else
+ `ifdef MCLK_MUX
+CONFIGURATION ERROR: THE MCLK_MUX CAN ONLY BE ENABLED IF THE LFXT_DOMAIN IS ENABLED AS WELL
+ `endif
+ `ifdef SMCLK_MUX
+CONFIGURATION ERROR: THE SMCLK_MUX CAN ONLY BE ENABLED IF THE LFXT_DOMAIN IS ENABLED AS WELL
+ `endif   
+ `ifdef WATCHDOG_MUX
+CONFIGURATION ERROR: THE WATCHDOG_MUX CAN ONLY BE ENABLED IF THE LFXT_DOMAIN IS ENABLED AS WELL
+ `else
+   `ifdef WATCHDOG_NOMUX_ACLK
+CONFIGURATION ERROR: THE WATCHDOG_NOMUX_ACLK CAN ONLY BE ENABLED IF THE LFXT_DOMAIN IS ENABLED AS WELL
+   `endif
+ `endif
+ `ifdef OSCOFF_EN
+CONFIGURATION ERROR: THE OSCOFF LOW POWER MODE CAN ONLY BE ENABLED IF THE LFXT_DOMAIN IS ENABLED AS WELL
+ `endif   
+`endif
diff --git a/tests/openmsp430/rtl/openMSP430_undefines.v b/tests/openmsp430/rtl/openMSP430_undefines.v
new file mode 100644 (file)
index 0000000..a399ae7
--- /dev/null
@@ -0,0 +1,732 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// 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 the authors nor the names of its contributors
+//       may be used to endorse or promote products derived from this software
+//       without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+// 
+// *File Name: openMSP430_undefines.v
+// 
+// *Module Description:
+//                      openMSP430 Verilog `undef file
+//
+// *Author(s):
+//              - Olivier Girard,    olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 23 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2009-08-30 18:39:26 +0200 (Sun, 30 Aug 2009) $
+//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+// BASIC SYSTEM CONFIGURATION
+//----------------------------------------------------------------------------
+
+// Program Memory sizes
+`ifdef PMEM_SIZE_59_KB
+`undef PMEM_SIZE_59_KB
+`endif
+`ifdef PMEM_SIZE_55_KB
+`undef PMEM_SIZE_55_KB
+`endif
+`ifdef PMEM_SIZE_54_KB
+`undef PMEM_SIZE_54_KB
+`endif
+`ifdef PMEM_SIZE_51_KB
+`undef PMEM_SIZE_51_KB
+`endif
+`ifdef PMEM_SIZE_48_KB
+`undef PMEM_SIZE_48_KB
+`endif
+`ifdef PMEM_SIZE_41_KB
+`undef PMEM_SIZE_41_KB
+`endif
+`ifdef PMEM_SIZE_32_KB
+`undef PMEM_SIZE_32_KB
+`endif
+`ifdef PMEM_SIZE_24_KB
+`undef PMEM_SIZE_24_KB
+`endif
+`ifdef PMEM_SIZE_16_KB
+`undef PMEM_SIZE_16_KB
+`endif
+`ifdef PMEM_SIZE_12_KB
+`undef PMEM_SIZE_12_KB
+`endif
+`ifdef PMEM_SIZE_8_KB
+`undef PMEM_SIZE_8_KB
+`endif
+`ifdef PMEM_SIZE_4_KB
+`undef PMEM_SIZE_4_KB
+`endif
+`ifdef PMEM_SIZE_2_KB
+`undef PMEM_SIZE_2_KB
+`endif
+`ifdef PMEM_SIZE_1_KB
+`undef PMEM_SIZE_1_KB
+`endif
+
+// Data Memory sizes
+`ifdef DMEM_SIZE_32_KB
+`undef DMEM_SIZE_32_KB
+`endif
+`ifdef DMEM_SIZE_24_KB
+`undef DMEM_SIZE_24_KB
+`endif
+`ifdef DMEM_SIZE_16_KB
+`undef DMEM_SIZE_16_KB
+`endif
+`ifdef DMEM_SIZE_10_KB
+`undef DMEM_SIZE_10_KB
+`endif
+`ifdef DMEM_SIZE_8_KB
+`undef DMEM_SIZE_8_KB
+`endif
+`ifdef DMEM_SIZE_5_KB
+`undef DMEM_SIZE_5_KB
+`endif
+`ifdef DMEM_SIZE_4_KB
+`undef DMEM_SIZE_4_KB
+`endif
+`ifdef DMEM_SIZE_2p5_KB
+`undef DMEM_SIZE_2p5_KB
+`endif
+`ifdef DMEM_SIZE_2_KB
+`undef DMEM_SIZE_2_KB
+`endif
+`ifdef DMEM_SIZE_1_KB
+`undef DMEM_SIZE_1_KB
+`endif
+`ifdef DMEM_SIZE_512_B
+`undef DMEM_SIZE_512_B
+`endif
+`ifdef DMEM_SIZE_256_B
+`undef DMEM_SIZE_256_B
+`endif
+`ifdef DMEM_SIZE_128_B
+`undef DMEM_SIZE_128_B
+`endif
+
+// Include/Exclude Hardware Multiplier
+`ifdef MULTIPLIER
+`undef MULTIPLIER
+`endif
+
+// Include Debug interface
+`ifdef DBG_EN
+`undef DBG_EN
+`endif
+
+
+//----------------------------------------------------------------------------
+// ADVANCED SYSTEM CONFIGURATION (FOR EXPERIENCED USERS)
+//----------------------------------------------------------------------------
+
+// Peripheral Memory Space:
+`ifdef PER_SIZE_32_KB
+`undef PER_SIZE_32_KB
+`endif
+`ifdef PER_SIZE_16_KB
+`undef PER_SIZE_16_KB
+`endif
+`ifdef PER_SIZE_8_KB
+`undef PER_SIZE_8_KB
+`endif
+`ifdef PER_SIZE_4_KB
+`undef PER_SIZE_4_KB
+`endif
+`ifdef PER_SIZE_2_KB
+`undef PER_SIZE_2_KB
+`endif
+`ifdef PER_SIZE_1_KB
+`undef PER_SIZE_1_KB
+`endif
+`ifdef PER_SIZE_512_B
+`undef PER_SIZE_512_B
+`endif
+
+// Let the CPU break after a PUC occurrence by default
+`ifdef DBG_RST_BRK_EN
+`undef DBG_RST_BRK_EN
+`endif
+
+// Custom user version number
+`ifdef USER_VERSION
+`undef USER_VERSION
+`endif
+
+// Include/Exclude Watchdog timer
+`ifdef WATCHDOG
+`undef WATCHDOG
+`endif
+
+// Include/Exclude Non-Maskable-Interrupt support
+`ifdef NMI
+`undef NMI
+`endif
+
+//----------------------------------------------------------------------------
+// EXPERT SYSTEM CONFIGURATION ( !!!! EXPERTS ONLY !!!! )
+//----------------------------------------------------------------------------
+
+// Number of hardware breakpoint units
+`ifdef DBG_HWBRK_0
+`undef DBG_HWBRK_0
+`endif
+`ifdef DBG_HWBRK_1
+`undef DBG_HWBRK_1
+`endif
+`ifdef DBG_HWBRK_2
+`undef DBG_HWBRK_2
+`endif
+`ifdef DBG_HWBRK_3
+`undef DBG_HWBRK_3
+`endif
+
+// Enable/Disable the hardware breakpoint RANGE mode
+`ifdef DBG_HWBRK_RANGE
+`undef DBG_HWBRK_RANGE
+`endif
+
+// Input synchronizers
+`ifdef SYNC_CPU_EN
+`undef SYNC_CPU_EN
+`endif
+`ifdef SYNC_DBG_EN
+`undef SYNC_DBG_EN
+`endif
+`ifdef SYNC_DBG_UART_RXD
+`undef SYNC_DBG_UART_RXD
+`endif
+`ifdef SYNC_NMI
+`undef SYNC_NMI
+`endif
+
+// ASIC version
+`ifdef ASIC
+`undef ASIC
+`endif
+
+
+//----------------------------------------------------------------------------
+// ASIC SYSTEM CONFIGURATION ( !!!! EXPERTS ONLY !!!! )
+//----------------------------------------------------------------------------
+
+// Fine grained clock gating
+`ifdef CLOCK_GATING
+`undef CLOCK_GATING
+`endif
+
+// LFXT clock domain
+`ifdef LFXT_DOMAIN
+`undef LFXT_DOMAIN
+`endif
+
+// MCLK: Clock Mux
+`ifdef MCLK_MUX
+`undef MCLK_MUX
+`endif
+
+// SMCLK: Clock Mux
+`ifdef SMCLK_MUX
+`undef SMCLK_MUX
+`endif
+
+// WATCHDOG: Clock Mux
+`ifdef WATCHDOG_MUX
+`undef WATCHDOG_MUX
+`endif
+
+// MCLK: Clock divider
+`ifdef MCLK_DIVIDER
+`undef MCLK_DIVIDER
+`endif
+
+// SMCLK: Clock divider (/1/2/4/8)
+`ifdef SMCLK_DIVIDER
+`undef SMCLK_DIVIDER
+`endif
+
+// ACLK: Clock divider (/1/2/4/8)
+`ifdef ACLK_DIVIDER
+`undef ACLK_DIVIDER
+`endif
+
+// LOW POWER MODE: CPUOFF
+`ifdef CPUOFF_EN
+`undef CPUOFF_EN
+`endif
+
+// LOW POWER MODE: OSCOFF
+`ifdef OSCOFF_EN
+`undef OSCOFF_EN
+`endif
+
+// LOW POWER MODE: SCG0
+`ifdef SCG0_EN
+`undef SCG0_EN
+`endif
+
+// LOW POWER MODE: SCG1
+`ifdef SCG1_EN
+`undef SCG1_EN
+`endif
+
+
+//==========================================================================//
+//==========================================================================//
+//==========================================================================//
+//==========================================================================//
+//=====        SYSTEM CONSTANTS --- !!!!!!!! DO NOT EDIT !!!!!!!!      =====//
+//==========================================================================//
+//==========================================================================//
+//==========================================================================//
+//==========================================================================//
+
+// Program Memory Size
+`ifdef PMEM_AWIDTH
+`undef PMEM_AWIDTH
+`endif
+`ifdef PMEM_SIZE
+`undef PMEM_SIZE
+`endif
+
+// Data Memory Size
+`ifdef DMEM_AWIDTH
+`undef DMEM_AWIDTH
+`endif
+`ifdef DMEM_SIZE
+`undef DMEM_SIZE
+`endif
+
+// Peripheral Memory Size
+`ifdef PER_AWIDTH
+`undef PER_AWIDTH
+`endif
+`ifdef PER_SIZE
+`undef PER_SIZE
+`endif
+
+// Data Memory Base Adresses
+`ifdef DMEM_BASE
+`undef DMEM_BASE
+`endif
+
+// Program & Data Memory most significant address bit (for 16 bit words)
+`ifdef PMEM_MSB
+`undef PMEM_MSB
+`endif
+`ifdef DMEM_MSB
+`undef DMEM_MSB
+`endif
+`ifdef PER_MSB
+`undef PER_MSB
+`endif
+
+// Instructions type
+`ifdef INST_SO
+`undef INST_SO
+`endif
+`ifdef INST_JMP
+`undef INST_JMP
+`endif
+`ifdef INST_TO
+`undef INST_TO
+`endif
+
+// Single-operand arithmetic
+`ifdef RRC
+`undef RRC
+`endif
+`ifdef SWPB
+`undef SWPB
+`endif
+`ifdef RRA
+`undef RRA
+`endif
+`ifdef SXT
+`undef SXT
+`endif
+`ifdef PUSH
+`undef PUSH
+`endif
+`ifdef CALL
+`undef CALL
+`endif
+`ifdef RETI
+`undef RETI
+`endif
+`ifdef IRQ
+`undef IRQ
+`endif
+
+// Conditional jump
+`ifdef JNE
+`undef JNE
+`endif
+`ifdef JEQ
+`undef JEQ
+`endif
+`ifdef JNC
+`undef JNC
+`endif
+`ifdef JC
+`undef JC
+`endif
+`ifdef JN
+`undef JN
+`endif
+`ifdef JGE
+`undef JGE
+`endif
+`ifdef JL
+`undef JL
+`endif
+`ifdef JMP
+`undef JMP
+`endif
+
+// Two-operand arithmetic
+`ifdef MOV
+`undef MOV
+`endif
+`ifdef ADD
+`undef ADD
+`endif
+`ifdef ADDC
+`undef ADDC
+`endif
+`ifdef SUBC
+`undef SUBC
+`endif
+`ifdef SUB
+`undef SUB
+`endif
+`ifdef CMP
+`undef CMP
+`endif
+`ifdef DADD
+`undef DADD
+`endif
+`ifdef BIT
+`undef BIT
+`endif
+`ifdef BIC
+`undef BIC
+`endif
+`ifdef BIS
+`undef BIS
+`endif
+`ifdef XOR
+`undef XOR
+`endif
+`ifdef AND
+`undef AND
+`endif
+
+// Addressing modes
+`ifdef DIR
+`undef DIR
+`endif
+`ifdef IDX
+`undef IDX
+`endif
+`ifdef INDIR
+`undef INDIR
+`endif
+`ifdef INDIR_I
+`undef INDIR_I
+`endif
+`ifdef SYMB
+`undef SYMB
+`endif
+`ifdef IMM
+`undef IMM
+`endif
+`ifdef ABS
+`undef ABS
+`endif
+`ifdef CONST
+`undef CONST
+`endif
+
+// Instruction state machine
+`ifdef I_IRQ_FETCH
+`undef I_IRQ_FETCH
+`endif
+`ifdef I_IRQ_DONE
+`undef I_IRQ_DONE
+`endif
+`ifdef I_DEC
+`undef I_DEC
+`endif
+`ifdef I_EXT1
+`undef I_EXT1
+`endif
+`ifdef I_EXT2
+`undef I_EXT2
+`endif
+`ifdef I_IDLE
+`undef I_IDLE
+`endif
+
+// Execution state machine
+`ifdef E_IRQ_0
+`undef E_IRQ_0
+`endif
+`ifdef E_IRQ_1
+`undef E_IRQ_1
+`endif
+`ifdef E_IRQ_2
+`undef E_IRQ_2
+`endif
+`ifdef E_IRQ_3
+`undef E_IRQ_3
+`endif
+`ifdef E_IRQ_4
+`undef E_IRQ_4
+`endif
+`ifdef E_SRC_AD
+`undef E_SRC_AD
+`endif
+`ifdef E_SRC_RD
+`undef E_SRC_RD
+`endif
+`ifdef E_SRC_WR
+`undef E_SRC_WR
+`endif
+`ifdef E_DST_AD
+`undef E_DST_AD
+`endif
+`ifdef E_DST_RD
+`undef E_DST_RD
+`endif
+`ifdef E_DST_WR
+`undef E_DST_WR
+`endif
+`ifdef E_EXEC
+`undef E_EXEC
+`endif
+`ifdef E_JUMP
+`undef E_JUMP
+`endif
+`ifdef E_IDLE
+`undef E_IDLE
+`endif
+
+// ALU control signals
+`ifdef ALU_SRC_INV
+`undef ALU_SRC_INV
+`endif
+`ifdef ALU_INC
+`undef ALU_INC
+`endif
+`ifdef ALU_INC_C
+`undef ALU_INC_C
+`endif
+`ifdef ALU_ADD
+`undef ALU_ADD
+`endif
+`ifdef ALU_AND
+`undef ALU_AND
+`endif
+`ifdef ALU_OR
+`undef ALU_OR
+`endif
+`ifdef ALU_XOR
+`undef ALU_XOR
+`endif
+`ifdef ALU_DADD
+`undef ALU_DADD
+`endif
+`ifdef ALU_STAT_7
+`undef ALU_STAT_7
+`endif
+`ifdef ALU_STAT_F
+`undef ALU_STAT_F
+`endif
+`ifdef ALU_SHIFT
+`undef ALU_SHIFT
+`endif
+`ifdef EXEC_NO_WR
+`undef EXEC_NO_WR
+`endif
+
+// Debug interface
+`ifdef DBG_UART_WR
+`undef DBG_UART_WR
+`endif
+`ifdef DBG_UART_BW
+`undef DBG_UART_BW
+`endif
+`ifdef DBG_UART_ADDR
+`undef DBG_UART_ADDR
+`endif
+
+// Debug interface CPU_CTL register
+`ifdef HALT
+`undef HALT
+`endif
+`ifdef RUN
+`undef RUN
+`endif
+`ifdef ISTEP
+`undef ISTEP
+`endif
+`ifdef SW_BRK_EN
+`undef SW_BRK_EN
+`endif
+`ifdef FRZ_BRK_EN
+`undef FRZ_BRK_EN
+`endif
+`ifdef RST_BRK_EN
+`undef RST_BRK_EN
+`endif
+`ifdef CPU_RST
+`undef CPU_RST
+`endif
+
+// Debug interface CPU_STAT register
+`ifdef HALT_RUN
+`undef HALT_RUN
+`endif
+`ifdef PUC_PND
+`undef PUC_PND
+`endif
+`ifdef SWBRK_PND
+`undef SWBRK_PND
+`endif
+`ifdef HWBRK0_PND
+`undef HWBRK0_PND
+`endif
+`ifdef HWBRK1_PND
+`undef HWBRK1_PND
+`endif
+
+// Debug interface BRKx_CTL register
+`ifdef BRK_MODE_RD
+`undef BRK_MODE_RD
+`endif
+`ifdef BRK_MODE_WR
+`undef BRK_MODE_WR
+`endif
+`ifdef BRK_MODE
+`undef BRK_MODE
+`endif
+`ifdef BRK_EN
+`undef BRK_EN
+`endif
+`ifdef BRK_I_EN
+`undef BRK_I_EN
+`endif
+`ifdef BRK_RANGE
+`undef BRK_RANGE
+`endif
+
+// Basic clock module: BCSCTL1 Control Register
+`ifdef DIVAx
+`undef DIVAx
+`endif
+
+// Basic clock module: BCSCTL2 Control Register
+`ifdef SELMx
+`undef SELMx
+`endif
+`ifdef DIVMx
+`undef DIVMx
+`endif
+`ifdef SELS
+`undef SELS
+`endif
+`ifdef DIVSx
+`undef DIVSx
+`endif
+
+// MCLK Clock gate
+`ifdef MCLK_CGATE
+`undef MCLK_CGATE
+`endif
+
+// SMCLK Clock gate
+`ifdef SMCLK_CGATE
+`undef SMCLK_CGATE
+`endif
+
+//
+// DEBUG INTERFACE EXTRA CONFIGURATION
+//======================================
+
+// Debug interface: CPU version
+`ifdef CPU_VERSION
+`undef CPU_VERSION
+`endif
+
+// Debug interface: Software breakpoint opcode
+`ifdef DBG_SWBRK_OP
+`undef DBG_SWBRK_OP
+`endif
+
+// Debug UART interface auto data synchronization
+`ifdef DBG_UART_AUTO_SYNC
+`undef DBG_UART_AUTO_SYNC
+`endif
+
+// Debug UART interface data rate
+`ifdef DBG_UART_BAUD
+`undef DBG_UART_BAUD
+`endif
+`ifdef DBG_DCO_FREQ
+`undef DBG_DCO_FREQ
+`endif
+`ifdef DBG_UART_CNT
+`undef DBG_UART_CNT
+`endif
+
+// Debug interface selection
+`ifdef DBG_UART
+`undef DBG_UART
+`endif
+`ifdef DBG_JTAG
+`undef DBG_JTAG
+`endif
+
+// Enable/Disable the hardware breakpoint RANGE mode
+`ifdef HWBRK_RANGE
+`undef HWBRK_RANGE
+`endif
+
+// Counter width for the debug interface UART
+`ifdef DBG_UART_XFER_CNT_W
+`undef DBG_UART_XFER_CNT_W
+`endif
+
+//
+// MULTIPLIER CONFIGURATION
+//======================================
+
+`ifdef MPY_16x16
+`undef MPY_16x16
+`endif
diff --git a/tests/openmsp430/run-fm.do b/tests/openmsp430/run-fm.do
new file mode 100644 (file)
index 0000000..766d974
--- /dev/null
@@ -0,0 +1,37 @@
+
+set hdlin_ignore_full_case false
+set hdlin_ignore_parallel_case false
+set svf_ignore_unqualified_fsm_information true
+set hdlin_warn_on_mismatch_message "FMR_ELAB-115 FMR_VLOG-079 FMR_VLOG-091"
+
+read_verilog -container r -libname WORK -01 rtl/omsp_alu.v
+read_verilog -container r -libname WORK -01 rtl/omsp_and_gate.v
+read_verilog -container r -libname WORK -01 rtl/omsp_clock_gate.v
+read_verilog -container r -libname WORK -01 rtl/omsp_clock_module.v
+read_verilog -container r -libname WORK -01 rtl/omsp_clock_mux.v
+read_verilog -container r -libname WORK -01 rtl/omsp_dbg_hwbrk.v
+read_verilog -container r -libname WORK -01 rtl/omsp_dbg_uart.v
+read_verilog -container r -libname WORK -01 rtl/omsp_dbg.v
+read_verilog -container r -libname WORK -01 rtl/omsp_execution_unit.v
+read_verilog -container r -libname WORK -01 rtl/omsp_frontend.v
+read_verilog -container r -libname WORK -01 rtl/omsp_mem_backbone.v
+read_verilog -container r -libname WORK -01 rtl/omsp_multiplier.v
+read_verilog -container r -libname WORK -01 rtl/omsp_register_file.v
+read_verilog -container r -libname WORK -01 rtl/omsp_scan_mux.v
+read_verilog -container r -libname WORK -01 rtl/omsp_sfr.v
+read_verilog -container r -libname WORK -01 rtl/omsp_sync_cell.v
+read_verilog -container r -libname WORK -01 rtl/omsp_sync_reset.v
+read_verilog -container r -libname WORK -01 rtl/omsp_wakeup_cell.v
+read_verilog -container r -libname WORK -01 rtl/omsp_watchdog.v
+read_verilog -container r -libname WORK -01 rtl/openMSP430.v
+set_top r:/WORK/openMSP430
+
+read_verilog -container i -libname WORK -01 synth.v
+read_verilog -container i -technology_library -libname TECH_WORK -01 ../../techlibs/stdcells_sim.v
+read_verilog -container i -technology_library -libname TECH_WORK -01 sim_mul.v
+set_top i:/WORK/openMSP430
+
+source fsm_info.txt
+
+if ![verify] start_gui exit
+
diff --git a/tests/openmsp430/run-fm.sh b/tests/openmsp430/run-fm.sh
new file mode 100644 (file)
index 0000000..5fd1c6c
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+if [ -n "$REMOTE_YOSYS_ROOT" ]; then
+       rsync --exclude=".svn" --exclude="*.log" -rv -e "${REMOTE_YOSYS_SSH:-ssh} -C" "$REMOTE_YOSYS_ROOT"/tests/openmsp430/. .
+fi
+fm_shell -64 -file run-fm.do 2>&1 | tee run-fm.log
diff --git a/tests/openmsp430/run-synth.sh b/tests/openmsp430/run-synth.sh
new file mode 100644 (file)
index 0000000..e4d6bc7
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+time ../../yosys -b "verilog -noexpr" -o synth.v -tl synth.log -s run-synth.ys \
+               rtl/omsp_*.v rtl/openMSP430.v 2>&1 | egrep '^\[[0-9.]+\] (ERROR|-- |[0-9]+\.)'
diff --git a/tests/openmsp430/run-synth.ys b/tests/openmsp430/run-synth.ys
new file mode 100644 (file)
index 0000000..af39147
--- /dev/null
@@ -0,0 +1,11 @@
+hierarchy -check -top openMSP430
+proc
+opt
+memory
+opt
+fsm -fm_set_fsm_file fsm_info.txt
+opt
+techmap
+opt
+abc
+opt
diff --git a/tests/openmsp430/sim_mul.v b/tests/openmsp430/sim_mul.v
new file mode 100644 (file)
index 0000000..8762bb2
--- /dev/null
@@ -0,0 +1,29 @@
+
+module \$mul (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+input [A_WIDTH-1:0] A;
+generate if (A_SIGNED) begin:A_BUF
+       wire signed [A_WIDTH-1:0] val = A;
+end else begin:A_BUF
+       wire [A_WIDTH-1:0] val = A;
+end endgenerate
+
+input [B_WIDTH-1:0] B;
+generate if (B_SIGNED) begin:B_BUF
+       wire signed [B_WIDTH-1:0] val = B;
+end else begin:B_BUF
+       wire [B_WIDTH-1:0] val = B;
+end endgenerate
+
+output [Y_WIDTH-1:0] Y;
+
+assign Y = A_BUF.val * B_BUF.val;
+
+endmodule
+
diff --git a/tests/or1200/config.patch b/tests/or1200/config.patch
new file mode 100644 (file)
index 0000000..7826ede
--- /dev/null
@@ -0,0 +1,46 @@
+Index: or1200_defines.v
+===================================================================
+--- or1200_defines.v   (revision 812)
++++ or1200_defines.v   (working copy)
+@@ -56,7 +56,7 @@
+ //
+ //`define OR1200_VERBOSE
+-//  `define OR1200_ASIC
++`define OR1200_ASIC
+ ////////////////////////////////////////////////////////
+ //
+ // Typical configuration for an ASIC
+@@ -69,7 +69,7 @@
+ //`define OR1200_ARTISAN_SSP
+ //`define OR1200_ARTISAN_SDP
+ //`define OR1200_ARTISAN_STP
+-`define OR1200_VIRTUALSILICON_SSP
++//`define OR1200_VIRTUALSILICON_SSP
+ //`define OR1200_VIRTUALSILICON_STP_T1
+ //`define OR1200_VIRTUALSILICON_STP_T2
+@@ -96,17 +96,17 @@
+ //
+ // Select between ASIC optimized and generic multiplier
+ //
+-//`define OR1200_ASIC_MULTP2_32X32
+-`define OR1200_GENERIC_MULTP2_32X32
++`define OR1200_ASIC_MULTP2_32X32
++//`define OR1200_GENERIC_MULTP2_32X32
+ //
+ // Size/type of insn/data cache if implemented
+ //
+-// `define OR1200_IC_1W_512B
++`define OR1200_IC_1W_512B
+ // `define OR1200_IC_1W_4KB
+-`define OR1200_IC_1W_8KB
+-// `define OR1200_DC_1W_4KB
+-`define OR1200_DC_1W_8KB
++// `define OR1200_IC_1W_8KB
++`define OR1200_DC_1W_4KB
++// `define OR1200_DC_1W_8KB
+ `else
diff --git a/tests/or1200/run-checkout.sh b/tests/or1200/run-checkout.sh
new file mode 100644 (file)
index 0000000..c9d4a10
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash
+rm -rf rtl
+svn co http://opencores.org/ocsvn/openrisc/openrisc/trunk/or1200/rtl/verilog rtl
+( cd rtl; patch -p0 < ../config.patch; )
diff --git a/tests/or1200/run-fm-mods.sh b/tests/or1200/run-fm-mods.sh
new file mode 100644 (file)
index 0000000..6b84877
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash
+if [ -n "$REMOTE_YOSYS_ROOT" ]; then
+       rsync --exclude=".svn" --exclude="*.log" -rv -e "${REMOTE_YOSYS_SSH:-ssh} -C" "$REMOTE_YOSYS_ROOT"/tests/or1200/. .
+fi
+for mod in $( grep '^module or1200_' synth.v | awk -F '[ (]' '{ print $2; }'; )
+do
+       {
+               grep '^set ' run-fm.do
+               grep '^read_verilog -container r ' run-fm.do
+               echo "set_top r:/WORK/$mod"
+               grep '^read_verilog -container i ' run-fm.do
+               echo "set_top i:/WORK/$mod"
+               echo "verify"
+               echo "exit"
+       } > run-fm-${mod}.do
+       fm_shell -64 -file run-fm-${mod}.do 2>&1 | tee run-fm-${mod}.log
+       rsync -v -e "${REMOTE_YOSYS_SSH:-ssh}" run-fm-${mod}.log "$REMOTE_YOSYS_ROOT"/tests/or1200/
+done
+
+echo; echo
+for x in run-fm-*.log; do
+       echo -e "${x%/*}\\t$( egrep '^Verification (SUCCEEDED|FAILED)' $x; )"
+done | expand -t20
+echo; echo
diff --git a/tests/or1200/run-fm.do b/tests/or1200/run-fm.do
new file mode 100644 (file)
index 0000000..ed5c722
--- /dev/null
@@ -0,0 +1,53 @@
+
+set hdlin_ignore_full_case false
+set hdlin_warn_on_mismatch_message "FMR_ELAB-115 FMR_VLOG-079 FMR_VLOG-091"
+
+read_verilog -container r -libname WORK -01 rtl/or1200_alu.v
+read_verilog -container r -libname WORK -01 rtl/or1200_amultp2_32x32.v
+read_verilog -container r -libname WORK -01 rtl/or1200_cfgr.v
+read_verilog -container r -libname WORK -01 rtl/or1200_cpu.v
+read_verilog -container r -libname WORK -01 rtl/or1200_ctrl.v
+read_verilog -container r -libname WORK -01 rtl/or1200_dc_fsm.v
+read_verilog -container r -libname WORK -01 rtl/or1200_dc_ram.v
+read_verilog -container r -libname WORK -01 rtl/or1200_dc_tag.v
+read_verilog -container r -libname WORK -01 rtl/or1200_dc_top.v
+read_verilog -container r -libname WORK -01 rtl/or1200_dmmu_tlb.v
+read_verilog -container r -libname WORK -01 rtl/or1200_dmmu_top.v
+read_verilog -container r -libname WORK -01 rtl/or1200_dpram.v
+read_verilog -container r -libname WORK -01 rtl/or1200_du.v
+read_verilog -container r -libname WORK -01 rtl/or1200_except.v
+read_verilog -container r -libname WORK -01 rtl/or1200_fpu.v
+read_verilog -container r -libname WORK -01 rtl/or1200_freeze.v
+read_verilog -container r -libname WORK -01 rtl/or1200_genpc.v
+read_verilog -container r -libname WORK -01 rtl/or1200_ic_fsm.v
+read_verilog -container r -libname WORK -01 rtl/or1200_ic_ram.v
+read_verilog -container r -libname WORK -01 rtl/or1200_ic_tag.v
+read_verilog -container r -libname WORK -01 rtl/or1200_ic_top.v
+read_verilog -container r -libname WORK -01 rtl/or1200_if.v
+read_verilog -container r -libname WORK -01 rtl/or1200_immu_tlb.v
+read_verilog -container r -libname WORK -01 rtl/or1200_immu_top.v
+read_verilog -container r -libname WORK -01 rtl/or1200_lsu.v
+read_verilog -container r -libname WORK -01 rtl/or1200_mem2reg.v
+read_verilog -container r -libname WORK -01 rtl/or1200_mult_mac.v
+read_verilog -container r -libname WORK -01 rtl/or1200_operandmuxes.v
+read_verilog -container r -libname WORK -01 rtl/or1200_pic.v
+read_verilog -container r -libname WORK -01 rtl/or1200_pm.v
+read_verilog -container r -libname WORK -01 rtl/or1200_qmem_top.v
+read_verilog -container r -libname WORK -01 rtl/or1200_reg2mem.v
+read_verilog -container r -libname WORK -01 rtl/or1200_rf.v
+read_verilog -container r -libname WORK -01 rtl/or1200_sb.v
+read_verilog -container r -libname WORK -01 rtl/or1200_spram_32_bw.v
+read_verilog -container r -libname WORK -01 rtl/or1200_spram.v
+read_verilog -container r -libname WORK -01 rtl/or1200_sprs.v
+read_verilog -container r -libname WORK -01 rtl/or1200_top.v
+read_verilog -container r -libname WORK -01 rtl/or1200_tt.v
+read_verilog -container r -libname WORK -01 rtl/or1200_wb_biu.v
+read_verilog -container r -libname WORK -01 rtl/or1200_wbmux.v
+set_top r:/WORK/or1200_top
+
+read_verilog -container i -libname WORK -01 synth.v
+read_verilog -container i -technology_library -libname TECH_WORK -01 ../../techlibs/stdcells_sim.v
+set_top i:/WORK/or1200_top
+
+if ![verify] start_gui exit
+
diff --git a/tests/or1200/run-fm.sh b/tests/or1200/run-fm.sh
new file mode 100644 (file)
index 0000000..3023809
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+if [ -n "$REMOTE_YOSYS_ROOT" ]; then
+       rsync --exclude=".svn" --exclude="*.log" -rv -e "${REMOTE_YOSYS_SSH:-ssh} -C" "$REMOTE_YOSYS_ROOT"/tests/or1200/. .
+fi
+fm_shell -64 -file run-fm.do 2>&1 | tee run-fm.log
diff --git a/tests/or1200/run-synth.sh b/tests/or1200/run-synth.sh
new file mode 100644 (file)
index 0000000..9f7e43f
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/bash
+time ../../yosys -b "verilog -noexpr" -o synth.v -tl synth.log -s run-synth.ys rtl/or1200_*.v 2>&1 | egrep '^\[[0-9.]+\] (ERROR|--|[0-9]+\.)'
diff --git a/tests/or1200/run-synth.ys b/tests/or1200/run-synth.ys
new file mode 100644 (file)
index 0000000..1f0d8a8
--- /dev/null
@@ -0,0 +1,11 @@
+hierarchy -check -top or1200_top
+proc
+opt
+memory
+opt
+# fsm -norecode
+# opt
+techmap
+opt
+abc
+opt
diff --git a/tests/or1200/run-vg.sh b/tests/or1200/run-vg.sh
new file mode 100644 (file)
index 0000000..54147cf
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash
+time valgrind --leak-check=full --show-reachable=yes --log-file=valgrind.log \
+               ../../yosys -o synth.v -tl synth.log -p "hierarchy -check -top or1200_top" \
+               -p opt_const -p proc -p memory -p opt -p techmap -p opt -p abc -p opt rtl/or1200_*.v
diff --git a/tests/simple/aes_kexp128.v b/tests/simple/aes_kexp128.v
new file mode 100644 (file)
index 0000000..3ee0347
--- /dev/null
@@ -0,0 +1,24 @@
+
+// test taken from aes_core from iwls2005
+
+module aes_key_expand_128(clk, kld, key, wo_0, wo_1, wo_2, wo_3);
+
+input          clk, kld;
+input  [15:0]  key;
+output [3:0]   wo_0, wo_1, wo_2, wo_3;
+reg    [3:0]   w[3:0];
+
+assign wo_0 = w[0];
+assign wo_1 = w[1];
+assign wo_2 = w[2];
+assign wo_3 = w[3];
+
+always @(posedge clk) begin
+       w[0] <= kld ? key[15:12] : w[0];
+       w[1] <= kld ? key[11: 8] : w[0]^w[1];
+       w[2] <= kld ? key[ 7: 4] : w[0]^w[1]^w[2];
+       w[3] <= kld ? key[ 3: 0] : w[0]^w[1]^w[2]^w[3];
+end
+
+endmodule
+
diff --git a/tests/simple/dff_different_styles.v b/tests/simple/dff_different_styles.v
new file mode 100644 (file)
index 0000000..23d89b5
--- /dev/null
@@ -0,0 +1,52 @@
+
+module dff(clk, d, q);
+input clk, d;
+output reg q;
+always @(posedge clk)
+       q <= d;
+endmodule
+
+module dffa(clk, arst, d, q);
+input clk, arst, d;
+output reg q;
+always @(posedge clk or posedge arst) begin
+       if (arst)
+               q <= 1;
+       else
+               q <= d;
+end
+endmodule
+
+module dffa1(clk, arst, d, q);
+input clk, arst, d;
+output reg q;
+always @(posedge clk or negedge arst) begin
+       if (~arst)
+               q <= 0;
+       else
+               q <= d;
+end
+endmodule
+
+module dffa2(clk, arst, d, q);
+input clk, arst, d;
+output reg q;
+always @(posedge clk or negedge arst) begin
+       if (!arst)
+               q <= 0;
+       else
+               q <= d;
+end
+endmodule
+
+module dffa3(clk, arst, d, q);
+input clk, arst, d;
+output reg q;
+always @(posedge clk or negedge arst) begin
+       if (~(!arst))
+               q <= d;
+       else
+               q <= 1;
+end
+endmodule
+
diff --git a/tests/simple/fiedler-cooley.v b/tests/simple/fiedler-cooley.v
new file mode 100644 (file)
index 0000000..9686197
--- /dev/null
@@ -0,0 +1,33 @@
+// borrowed with some modifications from
+// http://www.ee.ed.ac.uk/~gerard/Teach/Verilog/manual/Example/lrgeEx2/cooley.html
+module up3down5(clock, data_in, up, down, carry_out, borrow_out, count_out, parity_out);
+
+input [8:0] data_in;
+input clock, up, down;
+
+output reg [8:0] count_out;
+output reg carry_out, borrow_out, parity_out;
+
+reg [9:0] cnt_up, cnt_dn;
+reg [8:0] count_nxt;
+
+always @(posedge clock)
+begin
+       cnt_dn = count_out - 3'b 101;
+       cnt_up = count_out + 2'b 11;
+
+       case ({up,down})
+               2'b 00 : count_nxt = data_in;
+               2'b 01 : count_nxt = cnt_dn;
+               2'b 10 : count_nxt = cnt_up;
+               2'b 11 : count_nxt = count_out;
+               default : count_nxt = 9'bX;
+       endcase
+
+       parity_out  <= ^count_nxt;
+       carry_out   <= up & cnt_up[9];
+       borrow_out  <= down & cnt_dn[9];
+       count_out   <= count_nxt;
+end
+
+endmodule
diff --git a/tests/simple/fsm.v b/tests/simple/fsm.v
new file mode 100644 (file)
index 0000000..79ca041
--- /dev/null
@@ -0,0 +1,69 @@
+
+// `define ASYNC_RESET
+
+module test(clk, reset, button_a, button_b, red_a, green_a, red_b, green_b);
+
+input clk, reset, button_a, button_b;
+output reg red_a, green_a, red_b, green_b;
+
+(* gentb_constant = 0 *)
+wire reset;
+
+integer state;
+reg [3:0] cnt;
+
+`ifdef ASYNC_RESET
+always @(posedge clk, posedge reset)
+`else
+always @(posedge clk)
+`endif
+begin
+       cnt <= 0;
+       red_a <= 1;
+       red_b <= 1;
+       green_a <= 0;
+       green_b <= 0;
+
+       if (reset)
+               state <= 100;
+       else
+               case (state)
+                       100: begin
+                               if (button_a && !button_b)
+                                       state <= 200;
+                               if (!button_a && button_b)
+                                       state <= 300;
+                       end
+                       200: begin
+                               red_a <= 0;
+                               green_a <= 1;
+                               cnt <= cnt + 1;
+                               if (cnt == 5)
+                                       state <= 210;
+                       end
+                       210: begin
+                               red_a <= 0;
+                               green_a <= cnt[0];
+                               cnt <= cnt + 1;
+                               if (cnt == 10)
+                                       state <= 100;
+                       end
+                       300: begin
+                               red_b <= 0;
+                               green_b <= 1;
+                               cnt <= cnt + 1;
+                               if (cnt == 5)
+                                       state <= 310;
+                       end
+                       310: begin
+                               red_b <= 0;
+                               green_b <= cnt[0];
+                               cnt <= cnt + 1;
+                               if (cnt == 10)
+                                       state <= 100;
+                       end
+               endcase
+end
+
+endmodule
+
diff --git a/tests/simple/generate.v b/tests/simple/generate.v
new file mode 100644 (file)
index 0000000..d458c07
--- /dev/null
@@ -0,0 +1,67 @@
+
+module test1(clk, a, b, y);
+
+input clk;
+input [7:0] a, b;
+output reg [7:0] y;
+
+genvar i, j;
+wire [15:0] tmp1;
+
+generate
+
+       for (i = 0; i < 8; i = i + 1) begin:gen1
+               wire and_wire, or_wire;
+               assign and_wire = a[i] & b[i];
+               assign or_wire = a[i] | b[i];
+               if (i % 2 == 0) begin:gen2true
+                       assign tmp1[i] = and_wire;
+                       assign tmp1[i+8] = or_wire;
+               end else begin:gen2false
+                       assign tmp1[i] = or_wire;
+                       assign tmp1[i+8] = and_wire;
+               end
+       end
+
+       for (i = 0; i < 8; i = i + 1) begin:gen3
+               wire [4:0] tmp2;
+               for (j = 0; j <= 4; j = j + 1) begin:gen4
+                       wire tmpbuf;
+                       assign tmpbuf = tmp1[i+2*j];
+                       assign tmp2[j] = tmpbuf;
+               end
+               always @(posedge clk)
+                       y[i] <= ^tmp2;
+       end
+
+endgenerate
+
+endmodule
+
+// ------------------------------------------
+
+module test2(clk, a, b, y);
+
+input clk;
+input [7:0] a, b;
+output reg [8:0] y;
+
+integer i;
+reg [8:0] carry;
+
+always @(posedge clk) begin
+       carry[0] = 0;
+       for (i = 0; i < 8; i = i + 1) begin
+               casez ({a[i], b[i], carry[i]})
+                       3'b?11, 3'b1?1, 3'b11?:
+                               carry[i+1] = 1;
+                       default:
+                               carry[i+1] = 0;
+               endcase
+               y[i] = a[i] ^ b[i] ^ carry[i];
+       end
+       y[8] = carry[8];
+end
+
+endmodule
+
diff --git a/tests/simple/i2c_master_tests.v b/tests/simple/i2c_master_tests.v
new file mode 100644 (file)
index 0000000..f8f5640
--- /dev/null
@@ -0,0 +1,62 @@
+// one of my early test cases was the OpenCores I2C master
+// This is a collection of stripped down code snippets from
+// this core that triggered bugs in early versions of yosys.
+
+// from i2c_master_bit_ctrl
+module test01(clk, rst, nReset, al);
+
+       input clk, rst, nReset;
+       output reg al;
+
+       reg cmd_stop;
+       always @(posedge clk or negedge nReset)
+         if (~nReset)
+           cmd_stop <= #1 1'b0;
+         else if (rst)
+           cmd_stop <= #1 1'b0;
+
+       always @(posedge clk or negedge nReset)
+         if (~nReset)
+           al <= #1 1'b0;
+         else if (rst)
+           al <= #1 1'b0;
+         else
+           al <= #1 ~cmd_stop;
+
+endmodule
+
+// from i2c_master_bit_ctrl
+module test02(clk, slave_wait, clk_cnt, cmd, cmd_stop, cnt);
+
+       input clk, slave_wait, clk_cnt;
+       input cmd;
+
+       output reg cmd_stop;
+
+       reg clk_en;
+       output reg [15:0] cnt;
+
+       always @(posedge clk)
+         if (~|cnt)
+           if (~slave_wait)
+             begin
+                 cnt    <= #1 clk_cnt;
+                 clk_en <= #1 1'b1;
+             end
+           else
+             begin
+                 cnt    <= #1 cnt;
+                 clk_en <= #1 1'b0;
+             end
+         else
+           begin
+                cnt    <= #1 cnt - 16'h1;
+               clk_en <= #1 1'b0;
+           end
+
+       always @(posedge clk)
+         if (clk_en)
+           cmd_stop <= #1 cmd;
+
+endmodule
+
diff --git a/tests/simple/loops.v b/tests/simple/loops.v
new file mode 100644 (file)
index 0000000..77cdcd8
--- /dev/null
@@ -0,0 +1,79 @@
+
+// a simple test case extracted from systemcaes (as included in iwls2005)
+// this design has latches (or logic loops) for the two temp variables.
+// this latches (or logic loops) must be removed in the final synthesis results
+
+module aes(
+       // inputs
+       input [3:0] addroundkey_data_i,
+       input [3:0] addroundkey_data_reg,
+       input [3:0] addroundkey_round,
+       input [3:0] key_i,
+       input [3:0] keysched_new_key_o,
+       input [3:0] round,
+       input addroundkey_start_i,
+       input keysched_ready_o,
+
+       // outputs
+       output reg [3:0] keysched_last_key_i,
+       output reg [3:0] keysched_round_i,
+       output reg [3:0] next_addroundkey_data_reg,
+       output reg [3:0] next_addroundkey_round,
+       output reg [3:0] round_data_var,
+       output reg keysched_start_i,
+       output reg next_addroundkey_ready_o
+);
+
+// temp variables
+reg [3:0] data_var;
+reg [3:0] round_key_var;
+
+always @*
+begin
+       keysched_start_i = 0;
+       keysched_round_i = addroundkey_round;
+       round_data_var = addroundkey_data_reg;
+       next_addroundkey_data_reg = addroundkey_data_reg;
+       next_addroundkey_ready_o = 0;
+       next_addroundkey_round = addroundkey_round;
+
+       if (addroundkey_round == 1 || addroundkey_round == 0)
+               keysched_last_key_i = key_i;
+       else
+               keysched_last_key_i = keysched_new_key_o;
+       
+       if (round == 0 && addroundkey_start_i)
+       begin
+               data_var = addroundkey_data_i;  
+               round_key_var = key_i;
+               round_data_var = round_key_var ^ data_var;
+               next_addroundkey_data_reg = round_data_var;
+               next_addroundkey_ready_o = 1;
+       end
+       else if (addroundkey_start_i && round != 0)
+       begin
+               keysched_last_key_i = key_i;
+               keysched_start_i = 1;
+               keysched_round_i = 1;
+               next_addroundkey_round = 1;
+       end
+       else if (addroundkey_round != round && keysched_ready_o)
+       begin
+               next_addroundkey_round = addroundkey_round + 1;
+               keysched_last_key_i = keysched_new_key_o;
+               keysched_start_i = 1;
+               keysched_round_i = addroundkey_round + 1;
+       end
+       else if (addroundkey_round == round && keysched_ready_o)
+       begin
+               data_var = addroundkey_data_i;  
+               round_key_var = keysched_new_key_o;
+               round_data_var = round_key_var ^ data_var;
+               next_addroundkey_data_reg = round_data_var;
+               next_addroundkey_ready_o = 1;
+               next_addroundkey_round = 0;
+       end
+end
+
+endmodule
+
diff --git a/tests/simple/mem2reg.v b/tests/simple/mem2reg.v
new file mode 100644 (file)
index 0000000..7be32b0
--- /dev/null
@@ -0,0 +1,17 @@
+module test1(in_addr, in_data, out_addr, out_data);
+
+input [1:0] in_addr, out_addr;
+input [3:0] in_data;
+output reg [3:0] out_data;
+
+reg [3:0] array [2:0];
+
+always @* begin
+       array[0] = 0;
+       array[1] = 23;
+       array[2] = 42;
+       array[in_addr] = in_data;
+       out_data = array[out_addr];
+end
+
+endmodule
diff --git a/tests/simple/memory.v b/tests/simple/memory.v
new file mode 100644 (file)
index 0000000..c25bcd9
--- /dev/null
@@ -0,0 +1,19 @@
+
+module test01(clk, wr_en, wr_addr, wr_value, rd_addr, rd_value);
+
+input clk, wr_en;
+input [3:0] wr_addr, rd_addr;
+input [7:0] wr_value;
+output reg [7:0] rd_value;
+
+reg [7:0] data [15:0];
+
+always @(posedge clk)
+       if (wr_en)
+               data[wr_addr] <= wr_value;
+
+always @(posedge clk)
+       rd_value <= data[rd_addr];
+
+endmodule
+
diff --git a/tests/simple/muxtree.v b/tests/simple/muxtree.v
new file mode 100644 (file)
index 0000000..6996206
--- /dev/null
@@ -0,0 +1,50 @@
+
+// test case generated from IWLS 2005 usb_phy core
+// (triggered a bug in opt_muxtree pass)
+
+module usb_tx_phy(clk, rst, DataOut_i, TxValid_i, hold_reg);
+
+input          clk;
+input          rst;
+input          DataOut_i;
+input          TxValid_i;
+output reg     hold_reg;
+
+reg            state, next_state;
+reg            ld_sop_d;
+reg            ld_data_d;
+
+always @(posedge clk)
+       if(ld_sop_d)
+               hold_reg <= 0;
+       else
+               hold_reg <= DataOut_i;
+
+always @(posedge clk)
+       if(!rst)        state <= 0;
+       else            state <= next_state;
+
+always @(state or TxValid_i)
+   begin
+       next_state = state;
+
+       ld_sop_d = 1'b0;
+       ld_data_d = 1'b0;
+
+       case(state)     // synopsys full_case parallel_case
+          0:
+                       if(TxValid_i)
+                          begin
+                               ld_sop_d = 1'b1;
+                               next_state = 1;
+                          end
+          1:
+                       if(TxValid_i)
+                          begin
+                               ld_data_d = 1'b1;
+                               next_state = 0;
+                          end
+       endcase
+   end
+
+endmodule
diff --git a/tests/simple/omsp_dbg_uart.v b/tests/simple/omsp_dbg_uart.v
new file mode 100644 (file)
index 0000000..dc8860d
--- /dev/null
@@ -0,0 +1,34 @@
+
+module  omsp_dbg_uart (dbg_clk, dbg_rst, mem_burst, cmd_valid);
+
+input dbg_clk;
+input dbg_rst;
+input mem_burst;
+output cmd_valid;
+
+reg [2:0] uart_state;
+reg [2:0] uart_state_nxt;
+
+wire xfer_done;
+
+parameter  RX_SYNC  = 3'h0;
+parameter  RX_CMD   = 3'h1;
+parameter  RX_DATA = 3'h2;
+
+always @(uart_state or mem_burst)
+  case (uart_state)
+    RX_SYNC  : uart_state_nxt =  RX_CMD;
+    RX_CMD   : uart_state_nxt =  mem_burst ? RX_DATA : RX_SYNC;
+    RX_DATA : uart_state_nxt =  RX_SYNC;
+    default  : uart_state_nxt =  RX_CMD;
+  endcase
+   
+always @(posedge dbg_clk or posedge dbg_rst)
+  if (dbg_rst) uart_state <= RX_SYNC;
+  else if (xfer_done | mem_burst) uart_state <= uart_state_nxt;
+
+assign cmd_valid = (uart_state==RX_CMD) & xfer_done;
+assign xfer_done = uart_state!=RX_SYNC;
+   
+endmodule
+
diff --git a/tests/simple/operators.v b/tests/simple/operators.v
new file mode 100644 (file)
index 0000000..b9bbc13
--- /dev/null
@@ -0,0 +1,97 @@
+
+module test(clk, mode, u1, s1, u2, s2, y);
+
+input clk;
+input [5:0] mode;
+
+input [3:0] u1, u2;
+input signed [3:0] s1, s2;
+
+output reg [7:0] y;
+
+always @(posedge clk) begin
+       y <= 8'h42;
+       case (mode)
+                0: y <= u1 << u2;
+                1: y <= u1 << s2;
+                2: y <= s1 << u2;
+                3: y <= s1 << s2;
+
+                4: y <= u1 >> u2;
+                5: y <= u1 >> s2;
+                6: y <= s1 >> u2;
+                7: y <= s1 >> s2;
+
+                8: y <= u1 <<< u2;
+                9: y <= u1 <<< s2;
+               10: y <= s1 <<< u2;
+               11: y <= s1 <<< s2;
+
+               12: y <= u1 >>> u2;
+               13: y <= u1 >>> s2;
+               14: y <= s1 >>> u2;
+               15: y <= s1 >>> s2;
+
+               16: y <= u1 < u2;
+               17: y <= u1 < s2;
+               18: y <= s1 < u2;
+               19: y <= s1 < s2;
+
+               20: y <= u1 <= u2;
+               21: y <= u1 <= s2;
+               22: y <= s1 <= u2;
+               23: y <= s1 <= s2;
+
+               24: y <= u1 == u2;
+               25: y <= u1 == s2;
+               26: y <= s1 == u2;
+               27: y <= s1 == s2;
+
+               28: y <= u1 != u2;
+               29: y <= u1 != s2;
+               30: y <= s1 != u2;
+               31: y <= s1 != s2;
+
+               32: y <= u1 >= u2;
+               33: y <= u1 >= s2;
+               34: y <= s1 >= u2;
+               35: y <= s1 >= s2;
+
+               36: y <= u1 > u2;
+               37: y <= u1 > s2;
+               38: y <= s1 > u2;
+               39: y <= s1 > s2;
+
+               40: y <= u1 + u2;
+               41: y <= u1 + s2;
+               42: y <= s1 + u2;
+               43: y <= s1 + s2;
+
+               44: y <= u1 - u2;
+               45: y <= u1 - s2;
+               46: y <= s1 - u2;
+               47: y <= s1 - s2;
+
+               48: y <= +u1;
+               49: y <= -u1;
+               50: y <= +s1;
+               51: y <= -s1;
+
+               52: y <= { &u1, ~&u1, |u1, ~|u1, ^u1, ~^u1, ^~u1 };
+               53: y <= { &s1, ~&s1, |s1, ~|s1, ^s1, ~^s1, ^~s1 };
+               54: y <= { &u1[1:0], ~&u1[1:0], |u1[1:0], ~|u1[1:0], ^u1[1:0], ~^u1[1:0], ^~u1[1:0] };
+               55: y <= { &s1[1:0], ~&s1[1:0], |s1[1:0], ~|s1[1:0], ^s1[1:0], ~^s1[1:0], ^~s1[1:0] };
+
+               56: y <= { u1[1:0] && u2[1:0], u1[1:0] && u2[1:0], !u1[1:0] };
+               57: y <= {4{u1[1:0]}};
+               58: y <= {u1, u2} ^ {s1, s2};
+               59: y <= {u1, u2} & {s1, s2};
+
+               60: y <= u1[0] ? u1 : u2;
+               61: y <= u1[0] ? u1 : s2;
+               62: y <= u1[0] ? s1 : u2;
+               63: y <= u1[0] ? s1 : s2;
+       endcase
+end
+
+endmodule
diff --git a/tests/simple/paramods.v b/tests/simple/paramods.v
new file mode 100644 (file)
index 0000000..94fd2df
--- /dev/null
@@ -0,0 +1,37 @@
+
+module test1(a, b, x, y);
+
+input [7:0] a, b;
+output [7:0] x, y;
+
+inc #(.step(3)) inc_a (.in(a), .out(x));
+inc #(.width(4), .step(7)) inc_b (b, y);
+
+endmodule
+
+// -----------------------------------
+
+module test2(a, b, x, y);
+
+input [7:0] a, b;
+output [7:0] x, y;
+
+inc #(5) inc_a (.in(a), .out(x));
+inc #(4, 7) inc_b (b, y);
+
+endmodule
+
+// -----------------------------------
+
+module inc(in, out);
+
+parameter width = 8;
+parameter step = 1;
+
+input [width-1:0] in;
+output [width-1:0] out;
+
+assign out = in + step;
+
+endmodule
+
diff --git a/tests/simple/process.v b/tests/simple/process.v
new file mode 100644 (file)
index 0000000..5325866
--- /dev/null
@@ -0,0 +1,65 @@
+
+module uut(clk, arst, a, b, c, d, e, f,  out1);
+
+input clk, arst, a, b, c, d, e, f;
+output reg [3:0] out1;
+
+always @(posedge clk, posedge arst) begin
+       if (arst)
+               out1 = 0;
+       else begin
+               if (a) begin
+                       case ({b, c})
+                               2'b00:
+                                       out1 = out1 + 9;
+                               2'b01, 2'b10:
+                                       out1 = out1 + 13;
+                       endcase
+                       if (d) begin
+                               out1 = out1 + 2;
+                               out1 = out1 + 1;
+                       end
+                       case ({e, f})
+                               2'b11:
+                                       out1 = out1 + 8;
+                               2'b00:
+                                       ;
+                               default:
+                                       out1 = out1 + 10;
+                       endcase
+                       out1 = out1 ^ 7;
+               end
+               out1 = out1 + 14;
+       end
+end
+
+endmodule
+
+// -------------------------------------------------------------
+
+// extracted from ../asicworld/code_hdl_models_uart.v
+// (triggered a bug in the proc_mux pass)
+module uart (reset, txclk, ld_tx_data, tx_empty, tx_cnt);
+
+input reset;
+input txclk;
+input ld_tx_data;
+
+output reg tx_empty;
+output reg [3:0] tx_cnt;
+
+always @ (posedge txclk)
+if (reset) begin
+  tx_empty      <= 1;
+  tx_cnt        <= 0;
+end else begin
+   if (ld_tx_data) begin
+     tx_empty <= 0;
+   end
+   if (!tx_empty) begin
+     tx_cnt <= tx_cnt + 1;
+   end
+end
+
+endmodule
+
diff --git a/tests/simple/run-test.sh b/tests/simple/run-test.sh
new file mode 100755 (executable)
index 0000000..bf27d15
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+make -C ../.. || exit 1
+exec bash ../tools/autotest.sh *.v
diff --git a/tests/simple/subbytes.v b/tests/simple/subbytes.v
new file mode 100644 (file)
index 0000000..04269a9
--- /dev/null
@@ -0,0 +1,82 @@
+
+// test taken from systemcaes from iwls2005
+
+module subbytes_00(clk, reset, start_i, decrypt_i, data_i, ready_o, data_o, sbox_data_o, sbox_data_i, sbox_decrypt_o);
+
+input clk;
+input reset;
+input start_i;
+input decrypt_i;
+input [31:0] data_i;
+output ready_o;
+output [31:0] data_o;
+output [7:0] sbox_data_o;
+input [7:0] sbox_data_i;
+output sbox_decrypt_o;
+
+reg ready_o;
+reg [31:0] data_o;
+reg [7:0] sbox_data_o;
+reg sbox_decrypt_o;
+
+reg [1:0] state;
+reg [1:0] next_state;
+reg [31:0] data_reg;
+reg [31:0] next_data_reg;
+reg next_ready_o;
+
+always @(posedge clk or negedge reset)
+begin
+       if (!reset) begin
+               data_reg = 0;
+               state = 0;
+               ready_o = 0;
+       end else begin
+               data_reg = next_data_reg;
+               state = next_state;
+               ready_o = next_ready_o;
+       end
+end
+
+reg [31:0] data_i_var, data_reg_128;
+reg [7:0] data_array [3:0];
+reg [7:0] data_reg_var [3:0];
+
+always @(decrypt_i or start_i or state or data_i or sbox_data_i or data_reg)
+begin
+       data_i_var = data_i;
+
+       data_array[0] = data_i_var[ 31: 24];
+       data_array[1] = data_i_var[ 23: 16];
+       data_array[2] = data_i_var[ 15:  8];
+       data_array[3] = data_i_var[  7:  0];
+
+       data_reg_var[0] = data_reg[ 31: 24];
+       data_reg_var[1] = data_reg[ 23: 16];
+       data_reg_var[2] = data_reg[ 15:  8];
+       data_reg_var[3] = data_reg[  7:  0];
+
+       sbox_decrypt_o = decrypt_i;
+       sbox_data_o = data_array[state];
+       next_state = state;
+       next_data_reg = data_reg;
+
+       next_ready_o = 0;
+       data_o = data_reg;
+
+       if (state) begin
+               if (start_i) begin
+                       next_state = 1;
+               end
+       end else begin
+               data_reg_var[state] = sbox_data_i;
+               data_reg_128[ 31: 24] = data_reg_var[0];
+               data_reg_128[ 23: 16] = data_reg_var[1];
+               data_reg_128[ 15:  8] = data_reg_var[2];
+               data_reg_128[  7:  0] = data_reg_var[3];
+               next_data_reg = data_reg_128;
+               next_state = state + 1;
+       end
+end
+
+endmodule
diff --git a/tests/simple/task_func.v b/tests/simple/task_func.v
new file mode 100644 (file)
index 0000000..3a09cbc
--- /dev/null
@@ -0,0 +1,35 @@
+
+module test01(clk, a, b, c, x, y, z, w);
+
+input clk;
+input [7:0] a, b, c;
+output reg [7:0] x, y, z, w;
+
+function [7:0] sum_shift;
+input [3:0] s1, s2, s3;
+sum_shift = s1 + (s2 << 2) + (s3 << 4);
+endfunction
+
+task reset_w;
+w = 0;
+endtask
+
+task add_to;
+output [7:0] out;
+input [7:0] in;
+out = out + in;
+endtask
+
+always @(posedge clk) begin
+       x = sum_shift(a, b, c);
+       y = sum_shift(a[7:4], b[5:2], c[3:0]);
+       z = sum_shift(a[0], b[5:4], c >> 5) ^ sum_shift(1, 2, 3);
+
+       reset_w;
+       add_to(w, x);
+       add_to(w, y);
+       add_to(w, z);
+end
+
+endmodule
+
diff --git a/tests/simple/usb_phy_tetsts.v b/tests/simple/usb_phy_tetsts.v
new file mode 100644 (file)
index 0000000..2375183
--- /dev/null
@@ -0,0 +1,36 @@
+
+// from usb_rx_phy
+module test01(clk, rst, rx_en, fs_ce);
+
+input          clk, rst;
+input          rx_en;
+output reg     fs_ce;
+reg    [1:0]   dpll_next_state;
+reg    [1:0]   dpll_state;
+
+always @(posedge clk)
+       dpll_state <= rst ? 0 : dpll_next_state;
+
+always @*
+   begin
+       fs_ce = 1'b0;
+       case(dpll_state)
+          2'h0:
+               if(rx_en)       dpll_next_state = 2'h0;
+               else            dpll_next_state = 2'h1;
+          2'h1:begin
+               fs_ce = 1'b1;
+               if(rx_en)       dpll_next_state = 2'h3;
+               else            dpll_next_state = 2'h2;
+               end
+          2'h2:
+               if(rx_en)       dpll_next_state = 2'h0;
+               else            dpll_next_state = 2'h3;
+          2'h3:
+               if(rx_en)       dpll_next_state = 2'h0;
+               else            dpll_next_state = 2'h0;
+       endcase
+   end
+
+endmodule
+
diff --git a/tests/simple/values.v b/tests/simple/values.v
new file mode 100644 (file)
index 0000000..9fae4da
--- /dev/null
@@ -0,0 +1,44 @@
+
+module test_signed(a, b, c, d, y);
+
+input [3:0] a, b, c;
+input signed [3:0] d;
+output reg [7:0] y;
+
+always @* begin
+       if (a && b)
+               y = c;
+       else
+               y = d;
+end
+
+endmodule
+
+module test_const(a, y);
+
+input [3:0] a;
+output reg [28:0] y;
+
+always @*
+       case (a)
+               4'b0000: y = 0;
+               4'b0001: y = 11;
+               4'b0010: y = 222;
+               4'b0011: y = 3456;
+               4'b0100: y = 'b10010010;
+               4'b0101: y = 'h123abc;
+               4'b0110: y = 'o1234567;
+               4'b0111: y = 'd3456789;
+               4'b1000: y = 16'b10010010;
+               4'b1001: y = 16'h123abc;
+               4'b1010: y = 16'o1234567;
+               4'b1011: y = 16'd3456789;
+               4'b1100: y = "foobar";
+               4'b1101: y = "foobarfoobarfoobar";
+               4'b1110: y = 16'h1;
+               4'b1111: y = a;
+               default: y = 'bx;
+       endcase
+
+endmodule
+
diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh
new file mode 100755 (executable)
index 0000000..6b22f90
--- /dev/null
@@ -0,0 +1,164 @@
+#!/bin/bash
+
+libs=""
+genvcd=false
+use_isim=false
+verbose=false
+keeprunning=false
+backend_opts="-noattr -noexpr"
+kompare_xst=false
+scriptfiles=""
+toolsdir="$(cd $(dirname $0); pwd)"
+
+if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then
+       ( set -ex;  gcc -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1
+fi
+
+while getopts il:wkvrxs: opt; do
+       case "$opt" in
+               i)
+                       use_isim=true ;;
+               l)
+                       libs="$libs $(cd $(dirname $OPTARG); pwd)/$(basename $OPTARG)";;
+               w)
+                       genvcd=true ;;
+               k)
+                       keeprunning=true ;;
+               v)
+                       verbose=true ;;
+               r)
+                       backend_opts="$backend_opts norename" ;;
+               x)
+                       kompare_xst=true ;;
+               s)
+                       [[ "$OPTARG" == /* ]] || OPTARG="$PWD/$OPTARG"
+                       scriptfiles="$scriptfiles $OPTARG" ;;
+               *)
+                       echo "Usage: $0 [-i] [-w] [-k] [-v] [-r] [-x] [-l libs] [-s script] verilog-files\n" >&2
+                       exit 1
+       esac
+done
+
+create_ref() {
+       if $kompare_xst; then
+               echo "verilog work $1" > $2.prj
+               cat <<- EOT > $2.xst
+                       run
+                       -ifn $2.prj -ifmt mixed -ofn $2 -ofmt NGC -p xc6slx4-3-tqg144
+                       -top $( grep ^module $1 | sed -r 's,[^0-9A-Za-z_]+, ,g' | awk '{ print $2; exit; }'; )
+                       -opt_mode Speed -opt_level 1 -iobuf NO
+               EOT
+               (
+                       set +x
+                       prefix="$2"
+                       xilver=$( ls -v /opt/Xilinx/ | tail -n1; )
+                       case "$( uname -m )" in
+                       x86_64)
+                               set --; . /opt/Xilinx/$xilver/ISE_DS/settings64.sh ;;
+                       *)
+                               set --; . /opt/Xilinx/$xilver/ISE_DS/settings32.sh ;;
+                       esac
+                       set -x
+                       xst -ifn $prefix.xst
+                       netgen -w -ofmt verilog $prefix.ngc $prefix
+               )
+       else
+               cp "$1" "$2.v"
+       fi
+}
+
+compile_and_run() {
+       exe="$1"; output="$2"; shift 2
+       if $use_isim; then
+               (
+                       set +x
+                       files=( "$@" )
+                       xilver=$( ls -v /opt/Xilinx/ | tail -n1; )
+                       case "$( uname -m )" in
+                       x86_64)
+                               set --; . /opt/Xilinx/$xilver/ISE_DS/settings64.sh ;;
+                       *)
+                               set --; . /opt/Xilinx/$xilver/ISE_DS/settings32.sh ;;
+                       esac
+                       set -x
+                       vlogcomp "${files[@]}"
+                       if $kompare_xst; then
+                               fuse -o "$exe" -lib unisims_ver -top testbench -top glbl
+                       else
+                               fuse -o "$exe" -top testbench
+                       fi
+                       { echo "run all"; echo "exit"; } > run-all.tcl
+                       PATH="$PATH:" "$exe" -tclbatch run-all.tcl > "$output"
+               )
+       else
+               iverilog -s testbench -o "$exe" "$@"
+               vvp -n "$exe" > "$output"
+       fi
+}
+
+shift $((OPTIND - 1))
+
+for fn
+do
+       bn=${fn%.v}
+       if [ "$bn" == "$fn" ]; then
+               echo "Invalid argument: $fn" >&2
+               exit 1
+       fi
+       [[ "$bn" == *_tb ]] && continue
+       echo -n "Test: $bn "
+
+       rm -f ${bn}.{err,log}
+       mkdir -p ${bn}.out
+       rm -rf ${bn}.out/*
+
+       body() {
+               cd ${bn}.out
+               cp ../$fn $fn
+               if [ ! -f ../${bn}_tb.v ]; then
+                       "$toolsdir"/../../yosys -b autotest -o ${bn}_tb.v $fn
+               else
+                       cp ../${bn}_tb.v ${bn}_tb.v
+               fi
+               if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi
+               create_ref $fn ${bn}_ref
+               compile_and_run  ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs
+               if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi
+
+               test_count=0
+               test_passes() {
+                       "$toolsdir"/../../yosys -b "verilog $backend_opts" "$@" -o ${bn}_syn${test_count}.v $fn $scriptfiles
+                       compile_and_run ${bn}_tb_syn${test_count} ${bn}_out_syn${test_count} \
+                                       ${bn}_tb.v ${bn}_syn${test_count}.v $libs \
+                                       "$toolsdir"/../../techlibs/simlib.v \
+                                       "$toolsdir"/../../techlibs/stdcells_sim.v
+                       if $genvcd; then mv testbench.vcd ${bn}_syn${test_count}.vcd; fi
+                       $toolsdir/cmp_tbdata ${bn}_out_ref ${bn}_out_syn${test_count}
+                       test_count=$(( test_count + 1 ))
+               }
+
+               if [ -n "$scriptfiles" ]; then
+                       test_passes
+               else
+                       test_passes -p hierarchy -p proc -p memory -p opt -p fsm -p opt
+                       test_passes -p hierarchy -p proc -p memory -p opt -p fsm -p opt -p techmap -p opt
+                       # test_passes -p hierarchy -p proc -p memory -p opt -p techmap -p opt -p abc -p opt
+               fi
+               touch ../${bn}.log
+       }
+
+       if $verbose; then
+               echo ".."
+               echo "Output written to console." > ${bn}.err
+               ( set -ex; body; )
+       else
+               ( set -ex; body; ) > ${bn}.err 2>&1
+       fi
+
+       if [ -f ${bn}.log ]; then
+               mv ${bn}.err ${bn}.log
+               echo "-> ok"
+       else echo "-> ERROR!"; $keeprunning || exit 1; fi
+done
+
+exit 0
diff --git a/tests/tools/cmp_tbdata.c b/tests/tools/cmp_tbdata.c
new file mode 100644 (file)
index 0000000..86485ef
--- /dev/null
@@ -0,0 +1,67 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+int line = 0;
+char buffer1[1024];
+char buffer2[1024];
+
+void check(bool ok)
+{
+       if (ok)
+               return;
+       fprintf(stderr, "Error in testbench output compare (line=%d):\n-%s\n+%s\n", line, buffer1, buffer2);
+       exit(1);
+}
+
+int main(int argc, char **argv)
+{
+       FILE *f1, *f2;
+       bool eof1, eof2;
+       int i;
+
+       check(argc == 3);
+
+       f1 = fopen(argv[1], "r");
+       f2 = fopen(argv[2], "r");
+
+       check(f1 && f2);
+
+       while (!feof(f1) && !feof(f2))
+       {
+               line++;
+               buffer1[0] = 0;
+               buffer2[0] = 0;
+
+               eof1 = fgets(buffer1, 1024, f1) == NULL;
+               eof2 = fgets(buffer2, 1024, f2) == NULL;
+
+               if (*buffer1 && buffer1[strlen(buffer1)-1] == '\n')
+                       buffer1[strlen(buffer1)-1] = 0;
+
+               if (*buffer2 && buffer2[strlen(buffer2)-1] == '\n')
+                       buffer2[strlen(buffer2)-1] = 0;
+
+               check(eof1 == eof2);
+
+               for (i = 0; buffer1[i] || buffer2[i]; i++)
+               {
+                       check(buffer1[i] != 0 && buffer2[i] != 0);
+
+                       // first argument is the reference. An 'z' or 'x'
+                       // here means we don't care about the result.
+                       if (buffer1[i] == 'z' || buffer1[i] == 'x')
+                               continue;
+
+                       check(buffer1[i] == buffer2[i]);
+               }
+       }
+
+       check(feof(f1) && feof(f2));
+
+       fclose(f1);
+       fclose(f2);
+       return 0;
+}
+
diff --git a/tests/tools/profiler.pl b/tests/tools/profiler.pl
new file mode 100755 (executable)
index 0000000..456f634
--- /dev/null
@@ -0,0 +1,55 @@
+#!/usr/bin/perl
+# parse 'yosys -t' logfile and find slow passes
+
+my $max_depth = 0;
+my %last_line_by_depth;
+my %last_time_by_depth;
+
+my @lines_text;
+my @lines_depth;
+my @lines_time;
+
+while (<>)
+{
+       chomp;
+       next unless /^\[([0-9.]+)\] (([0-9]+\.)+)/;
+       my ($this_time, $this_id, $this_header) = ($1, $2, $4);
+
+       push @lines_text, $_;
+       push @lines_depth, 0;
+       push @lines_time, 0;
+
+       my $depth = $this_id;
+       $depth =~ s/[^.]//g;
+       $depth = length $depth;
+       $max_depth = $depth if $depth > $max_depth;
+
+       for (my $i = $depth; $i <= $max_depth; $i++) {
+               next unless exists $last_time_by_depth{$i};
+               $lines_time[$last_line_by_depth{$i}] = $this_time-$last_time_by_depth{$i};
+               delete $last_time_by_depth{$i};
+               delete $last_header_by_depth{$i};
+       }
+
+       $last_time_by_depth{$depth} = $this_time;
+       $last_line_by_depth{$depth} = $#lines_text;
+       $lines_depth[$#lines_text] = $depth;
+}
+
+for (my $depth = 1; $depth <= $max_depth; $depth++) {
+       printf "\nSlow passes on recursion depth %d:\n", $depth;
+       my @lines;
+       for (my $i = 0; $i <= $#lines_text; $i++) {
+               next if $lines_depth[$i] != $depth or $lines_time[$i] < 1.0;
+               push @lines, sprintf("%3d  %08.2f  %s\n", $lines_depth[$i], $lines_time[$i], $lines_text[$i]);
+       }
+       for my $line (sort {$b cmp $a} @lines) {
+               print $line;
+       }
+}
+
+printf "\nFull journal of headers:\n";
+for (my $i = 0; $i <= $#lines_text; $i++) {
+       printf "%3d  %08.2f  %s\n", $lines_depth[$i], $lines_time[$i], $lines_text[$i];
+}
+
diff --git a/tests/tools/rtlview.sh b/tests/tools/rtlview.sh
new file mode 100755 (executable)
index 0000000..6a4adca
--- /dev/null
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+# using Xilinx ISE to display RTL schematics
+
+if [ ! -f "$1" ]; then
+       echo "Usage: $0 <verilog-file>" >&2
+       exit 1
+fi
+
+prjdir="$(dirname $0)/rtlview.tmp"
+mkdir -p "$prjdir"
+
+cp "$1" "$prjdir"/schematic.v
+cp "$(dirname $0)"/../../techlibs/blackbox.v "$prjdir"/blackbox.v
+cd "$prjdir"
+
+if fuser -s ise.out; then
+       echo "ISE already running. Re-create RTL schematic from GUI."
+       exit 1
+fi
+
+xilver=$( ls -v /opt/Xilinx/ | grep '^[0-9]' | tail -n1; )
+
+cat > rtlview.xise << EOT
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<project xmlns="http://www.xilinx.com/XMLSchema" xmlns:xil_pn="http://www.xilinx.com/XMLSchema">
+  <header/>
+  <version xil_pn:ise_version="$xilver" xil_pn:schema_version="2"/>
+
+  <files>
+    <file xil_pn:name="schematic.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="1"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="2"/>
+    </file>
+    <file xil_pn:name="blackbox.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="1"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="2"/>
+    </file>
+  </files>
+
+  <properties>
+    <property xil_pn:name="Device" xil_pn:value="xc6slx4" xil_pn:valueState="default"/>
+    <property xil_pn:name="Device Family" xil_pn:value="Spartan6" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Device Speed Grade/Select ABS Minimum" xil_pn:value="-3" xil_pn:valueState="default"/>
+  </properties>
+
+  <bindings/>
+  <libraries/>
+  <autoManagedFiles/>
+</project>
+EOT
+
+set --
+case "$( uname -m )" in
+x86_64)
+       . /opt/Xilinx/$xilver/ISE_DS/settings64.sh ;;
+*)
+       . /opt/Xilinx/$xilver/ISE_DS/settings32.sh ;;
+esac
+
+ise rtlview.xise > ise.out 2>&1 &
+echo "ISE is now starting up. Create RTL schematic from GUI."
+
diff --git a/tests/tools/vcdcd.pl b/tests/tools/vcdcd.pl
new file mode 100755 (executable)
index 0000000..4875eee
--- /dev/null
@@ -0,0 +1,201 @@
+#!/usr/bin/perl -w
+#
+# Note: You might need to install the Verilog::VCD package using CPAN..
+
+use strict;
+use Data::Dumper;
+use Verilog::VCD qw(parse_vcd list_sigs);
+
+$| = 1;
+
+if ($#ARGV != 1) {
+       print STDERR "\n";
+       print STDERR "VCDCD - Value Change Dump Change Dumper\n";
+       print STDERR "\n";
+       print STDERR "Usage: $0 gold.vcd gate.vcd\n";
+       print STDERR "\n";
+       print STDERR "Compare a known-good (gold) vcd file with a second (gate) vcd file.\n";
+       print STDERR "This is not very efficient -- so use with care with large vcd files.\n";
+       print STDERR "\n";
+       exit 1;
+}
+
+my $fn_gold = $ARGV[0];
+my $fn_gate = $ARGV[1];
+
+print "Finding common signals..\n";
+my @gold_signals = list_sigs($fn_gold);
+my @gate_signals = list_sigs($fn_gate);
+
+my %gold_signals_hash;
+my %gate_signals_hash;
+
+for (@gold_signals) {
+       my $fullname = $_;
+       s/(\[([0-9]+|[0-9]+:[0-9]+)\])$//;
+       $gold_signals_hash{$_}->{$fullname} = 1 unless /(^|\.)_[0-9]+_/;
+}
+
+for (@gate_signals) {
+       my $fullname = $_;
+       s/(\[([0-9]+|[0-9]+:[0-9]+)\])$//;
+       $gate_signals_hash{$_}->{$fullname} = 1 unless /(^|\.)_[0-9]+_/;
+}
+
+my @signals;
+for my $net (sort keys %gold_signals_hash) {
+       next unless exists $gate_signals_hash{$net};
+       # next unless $net eq "tst_bench_top.i2c_top.byte_controller.bit_controller.cnt";
+       my %orig_net_names;
+       print "common signal: $net";
+       for my $fullname (keys $gold_signals_hash{$net}) {
+               $orig_net_names{$fullname} = 1;
+       }
+       for my $fullname (keys $gate_signals_hash{$net}) {
+               $orig_net_names{$fullname} = 1;
+       }
+       for my $_ (sort keys %orig_net_names) {
+               push @signals, $_;
+               print " $1" if /(\[([0-9]+|[0-9]+:[0-9]+)\])$/;
+       }
+       print "\n";
+}
+
+print "Loading gold vcd data..\n";
+my $vcd_gold = parse_vcd($fn_gold, {siglist => \@signals});
+
+print "Loading gate vcd data..\n";
+my $vcd_gate = parse_vcd($fn_gate, {siglist => \@signals});
+
+# print Dumper($vcd_gold);
+# print Dumper($vcd_gate);
+
+my %times;
+my $signal_maxlen = 8;
+my $data_gold = { };
+my $data_gate = { };
+
+sub checklen($$)
+{
+       my ($net, $val) = @_;
+       my $thislen = length $val;
+       $thislen += $1 if $net =~ /\[([0-9]+)\]$/;
+       $thislen += $1 if $net =~ /\[([0-9]+):[0-9]+\]$/;
+       $signal_maxlen = $thislen if $signal_maxlen < $thislen;
+}
+
+print "Processing gold vcd data..\n";
+for my $key (keys %$vcd_gold) {
+       for my $net (@{$vcd_gold->{$key}->{'nets'}}) {
+               my $netname = $net->{'hier'} . "." . $net->{'name'};
+               for my $tv (@{$vcd_gold->{$key}->{'tv'}}) {
+                       my $time = int($tv->[0]);
+                       my $value = $tv->[1];
+                       checklen($netname, $value);
+                       $data_gold->{$time}->{$netname} = $value;
+                       $times{$time} = 1;
+               }
+       }
+}
+
+print "Processing gate vcd data..\n";
+for my $key (keys %$vcd_gate) {
+       for my $net (@{$vcd_gate->{$key}->{'nets'}}) {
+               my $netname = $net->{'hier'} . "." . $net->{'name'};
+               for my $tv (@{$vcd_gate->{$key}->{'tv'}}) {
+                       my $time = int($tv->[0]);
+                       my $value = $tv->[1];
+                       checklen($netname, $value);
+                       $data_gate->{$time}->{$netname} = $value;
+                       $times{$time} = 1;
+               }
+       }
+}
+
+my $diffcount = 0;
+my %state_gold;
+my %state_gate;
+my %signal_sync;
+my %touched_nets;
+
+sub set_state_bit($$$$)
+{
+       my ($state, $net, $bit, $value) = @_;
+       my @data;
+       @data = split //, $state->{$net} if exists $state->{$net};
+       unshift @data, "-" while $#data < $bit;
+       $data[$#data - $bit] = $value;
+       $state->{$net} = join "", @data;
+       $signal_sync{$net} = 1 unless exists $signal_sync{$net};
+       $touched_nets{$net} = 1;
+}
+
+sub set_state($$$)
+{
+       my ($state, $net, $value) = @_;
+
+       if ($net =~ /(.*)\[([0-9]+)\]$/) {
+               set_state_bit($state, $1, $2, $value);
+               return;
+       }
+
+       if ($net =~ /(.*)\[([0-9]+):([0-9]+)\]$/) {
+               my ($n, $u, $d) = ($1, $2, $3);
+               my @bits = split //, $value;
+               my $extbit = $bits[0] eq "1" ? "0" : $bits[0];
+               unshift @bits, $extbit while $#bits < $u - $d;
+               set_state_bit($state, $n, $u--, shift @bits) while $u >= $d;
+               return;
+       }
+
+       $state->{$net} = $value;
+       $signal_sync{$net} = 1 unless exists $signal_sync{$net};
+       $touched_nets{$net} = 1;
+}
+
+sub cmp_signal($$)
+{
+       my ($a, $b) = @_;
+       return 1 if $a eq $b;
+
+       my @a = split //, $a;
+       my @b = split //, $b;
+
+       unshift @a, "-" while $#a < $#b;
+       unshift @b, "-" while $#b < $#a;
+
+       for (my $i = 0; $i <= $#a; $i++) {
+               return 0 if $a[$i] ne "x" && $a[$i] ne $b[$i];
+       }
+
+       return 1;
+}
+
+print "Comparing vcd data..\n";
+for my $time (sort { $a <=> $b } keys %times)
+{
+       %touched_nets = ();
+       for my $net (keys %{$data_gold->{$time}}) {
+               set_state(\%state_gold, $net, $data_gold->{$time}->{$net});
+       }
+       for my $net (keys %{$data_gate->{$time}}) {
+               set_state(\%state_gate, $net, $data_gate->{$time}->{$net});
+       }
+       for my $net (sort keys %touched_nets) {
+               my ($stgo, $stga) = ('-', '-');
+               $stgo = $state_gold{$net} if exists $state_gold{$net};
+               $stga = $state_gate{$net} if exists $state_gate{$net};
+               if (cmp_signal($stgo, $stga)) {
+                       next if $signal_sync{$net};
+                       printf "%-10s %-20d %-*s %-*s %s\n", "<sync>", $time, $signal_maxlen, $stgo, $signal_maxlen, $stga, $net;
+                       $signal_sync{$net} = 1;
+               } else {
+                       printf "\n%-10s %-20s %-*s %-*s %s\n", "count", "time", $signal_maxlen, "gold", $signal_maxlen, "gate", "net" if $diffcount++ == 0;
+                       printf "%-10d %-20d %-*s %-*s %s\n", $diffcount, $time, $signal_maxlen, $stgo, $signal_maxlen, $stga, $net;
+                       $signal_sync{$net} = 0;
+               }
+       }
+}
+
+print "Found $diffcount differences.\n";
+exit ($diffcount > 0 ? 1 : 0);