diff --git a/.gitignore b/.gitignore index 2fe4512..3c0160d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,2 @@ -out -build -env -__pycache* -_impactbatch.log \ No newline at end of file +build/ +out/ diff --git a/.gitmodules b/.gitmodules index e69de29..9f09b32 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "fusesoc_libraries/serv"] + path = fusesoc_libraries/serv + url = git@github.com:Jojojoppe/serv.git +[submodule "fusesoc_libraries/fusesoc-cores"] + path = fusesoc_libraries/fusesoc-cores + url = https://github.com/fusesoc/fusesoc-cores diff --git a/boards/mimas_v1/ip/clk_gen.xco b/boards/mimas_v1/ip/clk_gen.xco deleted file mode 100644 index e917723..0000000 --- a/boards/mimas_v1/ip/clk_gen.xco +++ /dev/null @@ -1,226 +0,0 @@ -SELECT Clocking_Wizard xilinx.com:ip:clk_wiz:3.6 - -CSET calc_done=DONE -CSET clk_in_sel_port=CLK_IN_SEL -CSET clk_out1_port=CLK_OUT1 -CSET clk_out1_use_fine_ps_gui=false -CSET clk_out2_port=CLK_OUT2 -CSET clk_out2_use_fine_ps_gui=false -CSET clk_out3_port=CLK_OUT3 -CSET clk_out3_use_fine_ps_gui=false -CSET clk_out4_port=CLK_OUT4 -CSET clk_out4_use_fine_ps_gui=false -CSET clk_out5_port=CLK_OUT5 -CSET clk_out5_use_fine_ps_gui=false -CSET clk_out6_port=CLK_OUT6 -CSET clk_out6_use_fine_ps_gui=false -CSET clk_out7_port=CLK_OUT7 -CSET clk_out7_use_fine_ps_gui=false -CSET clk_valid_port=CLK_VALID -CSET clkfb_in_n_port=CLKFB_IN_N -CSET clkfb_in_p_port=CLKFB_IN_P -CSET clkfb_in_port=CLKFB_IN -CSET clkfb_in_signaling=SINGLE -CSET clkfb_out_n_port=CLKFB_OUT_N -CSET clkfb_out_p_port=CLKFB_OUT_P -CSET clkfb_out_port=CLKFB_OUT -CSET clkfb_stopped_port=CLKFB_STOPPED -CSET clkin1_jitter_ps=100.0 -CSET clkin1_ui_jitter=0.010 -CSET clkin2_jitter_ps=100.0 -CSET clkin2_ui_jitter=0.010 -CSET clkout1_drives=BUFG -CSET clkout1_requested_duty_cycle=50.000 -CSET clkout1_requested_out_freq=15.000 -CSET clkout1_requested_phase=0.000 -CSET clkout2_drives=BUFG -CSET clkout2_requested_duty_cycle=50.000 -CSET clkout2_requested_out_freq=100.000 -CSET clkout2_requested_phase=0.000 -CSET clkout2_used=false -CSET clkout3_drives=BUFG -CSET clkout3_requested_duty_cycle=50.000 -CSET clkout3_requested_out_freq=100.000 -CSET clkout3_requested_phase=0.000 -CSET clkout3_used=false -CSET clkout4_drives=BUFG -CSET clkout4_requested_duty_cycle=50.000 -CSET clkout4_requested_out_freq=100.000 -CSET clkout4_requested_phase=0.000 -CSET clkout4_used=false -CSET clkout5_drives=BUFG -CSET clkout5_requested_duty_cycle=50.000 -CSET clkout5_requested_out_freq=100.000 -CSET clkout5_requested_phase=0.000 -CSET clkout5_used=false -CSET clkout6_drives=BUFG -CSET clkout6_requested_duty_cycle=50.000 -CSET clkout6_requested_out_freq=100.000 -CSET clkout6_requested_phase=0.000 -CSET clkout6_used=false -CSET clkout7_drives=BUFG -CSET clkout7_requested_duty_cycle=50.000 -CSET clkout7_requested_out_freq=100.000 -CSET clkout7_requested_phase=0.000 -CSET clkout7_used=false -CSET clock_mgr_type=AUTO -CSET component_name=clk_gen -CSET daddr_port=DADDR -CSET dclk_port=DCLK -CSET dcm_clk_feedback=1X -CSET dcm_clk_out1_port=CLKFX -CSET dcm_clk_out2_port=CLK0 -CSET dcm_clk_out3_port=CLK0 -CSET dcm_clk_out4_port=CLK0 -CSET dcm_clk_out5_port=CLK0 -CSET dcm_clk_out6_port=CLK0 -CSET dcm_clkdv_divide=2.0 -CSET dcm_clkfx_divide=20 -CSET dcm_clkfx_multiply=3 -CSET dcm_clkgen_clk_out1_port=CLKFX -CSET dcm_clkgen_clk_out2_port=CLKFX -CSET dcm_clkgen_clk_out3_port=CLKFX -CSET dcm_clkgen_clkfx_divide=1 -CSET dcm_clkgen_clkfx_md_max=0.000 -CSET dcm_clkgen_clkfx_multiply=4 -CSET dcm_clkgen_clkfxdv_divide=2 -CSET dcm_clkgen_clkin_period=10.000 -CSET dcm_clkgen_notes=None -CSET dcm_clkgen_spread_spectrum=NONE -CSET dcm_clkgen_startup_wait=false -CSET dcm_clkin_divide_by_2=false -CSET dcm_clkin_period=10.000 -CSET dcm_clkout_phase_shift=NONE -CSET dcm_deskew_adjust=SYSTEM_SYNCHRONOUS -CSET dcm_notes=None -CSET dcm_phase_shift=0 -CSET dcm_pll_cascade=NONE -CSET dcm_startup_wait=false -CSET den_port=DEN -CSET din_port=DIN -CSET dout_port=DOUT -CSET drdy_port=DRDY -CSET dwe_port=DWE -CSET feedback_source=FDBK_AUTO -CSET in_freq_units=Units_MHz -CSET in_jitter_units=Units_UI -CSET input_clk_stopped_port=INPUT_CLK_STOPPED -CSET jitter_options=UI -CSET jitter_sel=No_Jitter -CSET locked_port=LOCKED -CSET mmcm_bandwidth=OPTIMIZED -CSET mmcm_clkfbout_mult_f=4.000 -CSET mmcm_clkfbout_phase=0.000 -CSET mmcm_clkfbout_use_fine_ps=false -CSET mmcm_clkin1_period=10.000 -CSET mmcm_clkin2_period=10.000 -CSET mmcm_clkout0_divide_f=4.000 -CSET mmcm_clkout0_duty_cycle=0.500 -CSET mmcm_clkout0_phase=0.000 -CSET mmcm_clkout0_use_fine_ps=false -CSET mmcm_clkout1_divide=1 -CSET mmcm_clkout1_duty_cycle=0.500 -CSET mmcm_clkout1_phase=0.000 -CSET mmcm_clkout1_use_fine_ps=false -CSET mmcm_clkout2_divide=1 -CSET mmcm_clkout2_duty_cycle=0.500 -CSET mmcm_clkout2_phase=0.000 -CSET mmcm_clkout2_use_fine_ps=false -CSET mmcm_clkout3_divide=1 -CSET mmcm_clkout3_duty_cycle=0.500 -CSET mmcm_clkout3_phase=0.000 -CSET mmcm_clkout3_use_fine_ps=false -CSET mmcm_clkout4_cascade=false -CSET mmcm_clkout4_divide=1 -CSET mmcm_clkout4_duty_cycle=0.500 -CSET mmcm_clkout4_phase=0.000 -CSET mmcm_clkout4_use_fine_ps=false -CSET mmcm_clkout5_divide=1 -CSET mmcm_clkout5_duty_cycle=0.500 -CSET mmcm_clkout5_phase=0.000 -CSET mmcm_clkout5_use_fine_ps=false -CSET mmcm_clkout6_divide=1 -CSET mmcm_clkout6_duty_cycle=0.500 -CSET mmcm_clkout6_phase=0.000 -CSET mmcm_clkout6_use_fine_ps=false -CSET mmcm_clock_hold=false -CSET mmcm_compensation=ZHOLD -CSET mmcm_divclk_divide=1 -CSET mmcm_notes=None -CSET mmcm_ref_jitter1=0.010 -CSET mmcm_ref_jitter2=0.010 -CSET mmcm_startup_wait=false -CSET num_out_clks=1 -CSET override_dcm=false -CSET override_dcm_clkgen=false -CSET override_mmcm=false -CSET override_pll=false -CSET platform=lin -CSET pll_bandwidth=OPTIMIZED -CSET pll_clk_feedback=CLKFBOUT -CSET pll_clkfbout_mult=4 -CSET pll_clkfbout_phase=0.000 -CSET pll_clkin_period=10.0 -CSET pll_clkout0_divide=128 -CSET pll_clkout0_duty_cycle=0.500 -CSET pll_clkout0_phase=0.000 -CSET pll_clkout1_divide=1 -CSET pll_clkout1_duty_cycle=0.500 -CSET pll_clkout1_phase=0.000 -CSET pll_clkout2_divide=1 -CSET pll_clkout2_duty_cycle=0.500 -CSET pll_clkout2_phase=0.000 -CSET pll_clkout3_divide=1 -CSET pll_clkout3_duty_cycle=0.500 -CSET pll_clkout3_phase=0.000 -CSET pll_clkout4_divide=1 -CSET pll_clkout4_duty_cycle=0.500 -CSET pll_clkout4_phase=0.000 -CSET pll_clkout5_divide=1 -CSET pll_clkout5_duty_cycle=0.500 -CSET pll_clkout5_phase=0.000 -CSET pll_compensation=SYSTEM_SYNCHRONOUS -CSET pll_divclk_divide=1 -CSET pll_notes=None -CSET pll_ref_jitter=0.010 -CSET power_down_port=POWER_DOWN -CSET prim_in_freq=100.000 -CSET prim_in_jitter=0.010 -CSET prim_source=Global_buffer -CSET primary_port=CLK_IN1 -CSET primitive=MMCM -CSET primtype_sel=PLL_BASE -CSET psclk_port=PSCLK -CSET psdone_port=PSDONE -CSET psen_port=PSEN -CSET psincdec_port=PSINCDEC -CSET relative_inclk=REL_PRIMARY -CSET reset_port=RESET -CSET secondary_in_freq=100.000 -CSET secondary_in_jitter=0.010 -CSET secondary_port=CLK_IN2 -CSET secondary_source=Single_ended_clock_capable_pin -CSET ss_mod_freq=250 -CSET ss_mode=CENTER_HIGH -CSET status_port=STATUS -CSET summary_strings=empty -CSET use_clk_valid=false -CSET use_clkfb_stopped=false -CSET use_dyn_phase_shift=false -CSET use_dyn_reconfig=false -CSET use_freeze=false -CSET use_freq_synth=true -CSET use_inclk_stopped=false -CSET use_inclk_switchover=false -CSET use_locked=false -CSET use_max_i_jitter=false -CSET use_min_o_jitter=false -CSET use_min_power=false -CSET use_phase_alignment=true -CSET use_power_down=false -CSET use_reset=false -CSET use_spread_spectrum=false -CSET use_spread_spectrum_1=false -CSET use_status=false - -GENERATE diff --git a/check_formal.sh b/check_formal.sh new file mode 100755 index 0000000..302fbf3 --- /dev/null +++ b/check_formal.sh @@ -0,0 +1,95 @@ +#!/bin/sh + +# Add or remove cores here. Each entry should be a full FuseSoC VLNV. +CORES=" +joppeb:wb:wb_mem32 +joppeb:wb:wb_gpio +joppeb:wb:wb_gpio_banks +joppeb:wb:jtag_wb_bridge +joppeb:wb:wb_timer +" + +if [ -n "$1" ]; then + CORES="$1" +fi + +# Add or remove formal tasks here. +TASKS=" +bmc +cover +prove +" + +total=0 +passed=0 +failed=0 +passed_runs="" +failed_runs="" + +run_task() { + core="$1" + task="$2" + label="$core [$task]" + log_file="" + total=$((total + 1)) + + printf '\n[%d] Running formal %s for %s\n' "$total" "$task" "$core" + + log_file=$(mktemp /tmp/check_formal.XXXXXX) || exit 2 + + if \ + FUSESOC_CORE="$core" \ + FUSESOC_TASK="$task" \ + script -qefc 'fusesoc run --target formal "$FUSESOC_CORE" --taskname "$FUSESOC_TASK"' "$log_file" \ + >/dev/null 2>&1 + then + passed=$((passed + 1)) + passed_runs="$passed_runs +$label" + printf 'Result: PASS (%s)\n' "$label" + rm -f "$log_file" + return 0 + else + failed=$((failed + 1)) + failed_runs="$failed_runs +$label" + printf 'Result: FAIL (%s)\n' "$label" + printf 'Captured log for %s:\n' "$label" + cat "$log_file" #| grep summary + rm -f "$log_file" + return 1 + fi +} + +for core in $CORES; do + for task in $TASKS; do + run_task "$core" "$task" + done +done + +printf '\nFormal run summary\n' +printf ' Total: %d\n' "$total" +printf ' Passed: %d\n' "$passed" +printf ' Failed: %d\n' "$failed" + +if [ -n "$passed_runs" ]; then + printf '\nPassed runs:\n' + printf '%s\n' "$passed_runs" | while IFS= read -r run; do + if [ -n "$run" ]; then + printf ' - %s\n' "$run" + fi + done +fi + +if [ -n "$failed_runs" ]; then + printf '\nFailed runs:\n' + printf '%s\n' "$failed_runs" | while IFS= read -r run; do + if [ -n "$run" ]; then + printf ' - %s\n' "$run" + fi + done +fi + +if [ "$failed" -ne 0 ]; then + exit 1 +fi diff --git a/cores/primitive/clkgen/clkgen.core b/cores/primitive/clkgen/clkgen.core new file mode 100644 index 0000000..cf8b593 --- /dev/null +++ b/cores/primitive/clkgen/clkgen.core @@ -0,0 +1,49 @@ +CAPI=2: + +name: joppeb:primitive:clkgen:1.0 +description: Parameterized clock generator wrapper + +filesets: + wrapper: + files: + - clkgen.v + file_type: verilogSource + generic: + files: + - clkgen_generic_impl.v + file_type: verilogSource + spartan6: + files: + - clkgen_spartan6.v + file_type: verilogSource + +targets: + default: + filesets: + - wrapper + - generic + - spartan6 + toplevel: clkgen + parameters: + - CLK_IN_HZ + - CLKFX_DIVIDE + - CLKFX_MULTIPLY + - CLKDV_DIVIDE + +parameters: + CLK_IN_HZ: + datatype: int + description: Input clock frequency in Hz + paramtype: vlogparam + CLKFX_DIVIDE: + datatype: int + description: DCM CLKFX divide value + paramtype: vlogparam + CLKFX_MULTIPLY: + datatype: int + description: DCM CLKFX multiply value + paramtype: vlogparam + CLKDV_DIVIDE: + datatype: real + description: DCM CLKDV divide value + paramtype: vlogparam diff --git a/cores/primitive/clkgen/clkgen.v b/cores/primitive/clkgen/clkgen.v new file mode 100644 index 0000000..b2a90c5 --- /dev/null +++ b/cores/primitive/clkgen/clkgen.v @@ -0,0 +1,37 @@ +`timescale 1ns/1ps + +// ============================================================================= +// Clock generator +// Stable public wrapper that selects the implementation. +// ============================================================================= +module clkgen #( + parameter integer CLK_IN_HZ = 100000000, + parameter integer CLKFX_DIVIDE = 20, + parameter integer CLKFX_MULTIPLY = 3, + parameter real CLKDV_DIVIDE = 2.0 +)( + input wire clk_in, + output wire clk_out +); +`ifdef FPGA_SPARTAN6 + clkgen_spartan6_impl #( + .CLK_IN_HZ(CLK_IN_HZ), + .CLKFX_DIVIDE(CLKFX_DIVIDE), + .CLKFX_MULTIPLY(CLKFX_MULTIPLY), + .CLKDV_DIVIDE(CLKDV_DIVIDE) + ) impl_i ( + .clk_in(clk_in), + .clk_out(clk_out) + ); +`else + clkgen_generic_impl #( + .CLK_IN_HZ(CLK_IN_HZ), + .CLKFX_DIVIDE(CLKFX_DIVIDE), + .CLKFX_MULTIPLY(CLKFX_MULTIPLY), + .CLKDV_DIVIDE(CLKDV_DIVIDE) + ) impl_i ( + .clk_in(clk_in), + .clk_out(clk_out) + ); +`endif +endmodule diff --git a/cores/primitive/clkgen/clkgen_generic_impl.v b/cores/primitive/clkgen/clkgen_generic_impl.v new file mode 100644 index 0000000..a3addd8 --- /dev/null +++ b/cores/primitive/clkgen/clkgen_generic_impl.v @@ -0,0 +1,29 @@ +`timescale 1ns/1ps + +// ============================================================================= +// Clock generator +// Generic behavioural model. This is intended for simulation only. +// ============================================================================= +module clkgen_generic_impl #( + parameter integer CLK_IN_HZ = 100000000, + parameter integer CLKFX_DIVIDE = 20, + parameter integer CLKFX_MULTIPLY = 3, + parameter real CLKDV_DIVIDE = 2.0 +)( + input wire clk_in, + output reg clk_out +); + real half_period_ns; + + initial begin + clk_out = 1'b0; + half_period_ns = (500000000.0 * CLKFX_DIVIDE) / (CLK_IN_HZ * CLKFX_MULTIPLY); + + // Start oscillation after the source clock becomes active. + @(posedge clk_in); + forever #(half_period_ns) clk_out = ~clk_out; + end + + wire _unused_clkdv_divide; + assign _unused_clkdv_divide = (CLKDV_DIVIDE != 0.0); +endmodule diff --git a/cores/primitive/clkgen/clkgen_spartan6.v b/cores/primitive/clkgen/clkgen_spartan6.v new file mode 100644 index 0000000..c761a6c --- /dev/null +++ b/cores/primitive/clkgen/clkgen_spartan6.v @@ -0,0 +1,79 @@ +`timescale 1ns/1ps + +// ============================================================================= +// Clock generator +// Spartan-6 DCM wrapper with parameterized input and output ratios. +// ============================================================================= +module clkgen_spartan6_impl #( + parameter integer CLK_IN_HZ = 100000000, + parameter integer CLKFX_DIVIDE = 20, + parameter integer CLKFX_MULTIPLY = 3, + parameter real CLKDV_DIVIDE = 2.0 +)( + input wire clk_in, + output wire clk_out +); +`ifdef FPGA_SPARTAN6 + localparam real CLKIN_PERIOD_NS = 1000000000.0 / CLK_IN_HZ; + + wire clkfb; + wire clk0; + wire clkfx; + wire locked_unused; + wire [7:0] status_unused; + + DCM_SP #( + .CLKDV_DIVIDE(CLKDV_DIVIDE), + .CLKFX_DIVIDE(CLKFX_DIVIDE), + .CLKFX_MULTIPLY(CLKFX_MULTIPLY), + .CLKIN_DIVIDE_BY_2("FALSE"), + .CLKIN_PERIOD(CLKIN_PERIOD_NS), + .CLKOUT_PHASE_SHIFT("NONE"), + .CLK_FEEDBACK("1X"), + .DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"), + .PHASE_SHIFT(0), + .STARTUP_WAIT("FALSE") + ) dcm_sp_i ( + .CLKIN(clk_in), + .CLKFB(clkfb), + .CLK0(clk0), + .CLK90(), + .CLK180(), + .CLK270(), + .CLK2X(), + .CLK2X180(), + .CLKFX(clkfx), + .CLKFX180(), + .CLKDV(), + .PSCLK(1'b0), + .PSEN(1'b0), + .PSINCDEC(1'b0), + .PSDONE(), + .LOCKED(locked_unused), + .STATUS(status_unused), + .RST(1'b0), + .DSSEN(1'b0) + ); + + BUFG clkfb_buf_i ( + .I(clk0), + .O(clkfb) + ); + + BUFG clkout_buf_i ( + .I(clkfx), + .O(clk_out) + ); +`else + assign clk_out = 1'b0; + + wire _unused_clk_in; + wire _unused_clkfx_divide; + wire _unused_clkfx_multiply; + wire _unused_clkdv_divide; + assign _unused_clk_in = clk_in; + assign _unused_clkfx_divide = CLKFX_DIVIDE[0]; + assign _unused_clkfx_multiply = CLKFX_MULTIPLY[0]; + assign _unused_clkdv_divide = (CLKDV_DIVIDE != 0.0); +`endif +endmodule diff --git a/cores/primitive/jtag_if/jtag_if.core b/cores/primitive/jtag_if/jtag_if.core new file mode 100644 index 0000000..965a1ef --- /dev/null +++ b/cores/primitive/jtag_if/jtag_if.core @@ -0,0 +1,34 @@ +CAPI=2: + +name: joppeb:primitive:jtag_if:1.0 +description: JTAG user chain interface + +filesets: + wrapper: + files: + - jtag_if.v + file_type: verilogSource + generic: + files: + - jtag_if_generic_impl.v + file_type: verilogSource + spartan6: + files: + - jtag_if_spartan6.v + file_type: verilogSource + +targets: + default: + filesets: + - wrapper + - generic + - spartan6 + toplevel: jtag_if + parameters: + - chain + +parameters: + chain: + datatype: int + description: User chain + paramtype: vlogparam diff --git a/cores/primitive/jtag_if/jtag_if.v b/cores/primitive/jtag_if/jtag_if.v new file mode 100644 index 0000000..f4eee7f --- /dev/null +++ b/cores/primitive/jtag_if/jtag_if.v @@ -0,0 +1,52 @@ +`timescale 1ns/1ps + +// ============================================================================= +// JTAG interface +// Stable public wrapper that selects an implementation. +// ============================================================================= +module jtag_if #( + parameter chain = 1 +)( + input wire i_tdo, + output wire o_tck, + output wire o_tdi, + output wire o_drck, + output wire o_capture, + output wire o_shift, + output wire o_update, + output wire o_runtest, + output wire o_reset, + output wire o_sel +); +`ifdef FPGA_SPARTAN6 + jtag_if_spartan6_impl #( + .chain(chain) + ) impl_i ( + .i_tdo(i_tdo), + .o_tck(o_tck), + .o_tdi(o_tdi), + .o_drck(o_drck), + .o_capture(o_capture), + .o_shift(o_shift), + .o_update(o_update), + .o_runtest(o_runtest), + .o_reset(o_reset), + .o_sel(o_sel) + ); +`else + jtag_if_generic_impl #( + .chain(chain) + ) impl_i ( + .i_tdo(i_tdo), + .o_tck(o_tck), + .o_tdi(o_tdi), + .o_drck(o_drck), + .o_capture(o_capture), + .o_shift(o_shift), + .o_update(o_update), + .o_runtest(o_runtest), + .o_reset(o_reset), + .o_sel(o_sel) + ); +`endif +endmodule diff --git a/rtl/core/jtag_if.v b/cores/primitive/jtag_if/jtag_if_generic_impl.v similarity index 90% rename from rtl/core/jtag_if.v rename to cores/primitive/jtag_if/jtag_if_generic_impl.v index d53b31f..c08919d 100644 --- a/rtl/core/jtag_if.v +++ b/cores/primitive/jtag_if/jtag_if_generic_impl.v @@ -4,7 +4,7 @@ // JTAG interface // Generic stub model with inactive/tied-off outputs. // ============================================================================= -module jtag_if #( +module jtag_if_generic_impl #( parameter chain = 1 )( input wire i_tdo, @@ -30,5 +30,7 @@ module jtag_if #( // Keep lint tools quiet in generic builds where TDO is unused. wire _unused_tdo; + wire _unused_chain; assign _unused_tdo = i_tdo; + assign _unused_chain = chain[0]; endmodule diff --git a/rtl/arch/spartan-6/jtag_if.v b/cores/primitive/jtag_if/jtag_if_spartan6.v similarity index 66% rename from rtl/arch/spartan-6/jtag_if.v rename to cores/primitive/jtag_if/jtag_if_spartan6.v index 6d84f68..a54bfe8 100644 --- a/rtl/arch/spartan-6/jtag_if.v +++ b/cores/primitive/jtag_if/jtag_if_spartan6.v @@ -4,7 +4,7 @@ // JTAG interface // Spartan-6 BSCAN primitive wrapper (USER1 chain). // ============================================================================= -module jtag_if #( +module jtag_if_spartan6_impl #( parameter chain = 1 )( input wire i_tdo, @@ -18,6 +18,7 @@ module jtag_if #( output wire o_reset, output wire o_sel ); +`ifdef FPGA_SPARTAN6 BSCAN_SPARTAN6 #( .JTAG_CHAIN(chain) ) bscan_i ( @@ -32,4 +33,20 @@ module jtag_if #( .TDO(i_tdo), .UPDATE(o_update) ); +`else + assign o_tck = 1'b0; + assign o_tdi = 1'b0; + assign o_drck = 1'b0; + assign o_capture = 1'b0; + assign o_shift = 1'b0; + assign o_update = 1'b0; + assign o_runtest = 1'b0; + assign o_reset = 1'b0; + assign o_sel = 1'b0; + + wire _unused_tdo; + wire _unused_chain; + assign _unused_tdo = i_tdo; + assign _unused_chain = chain[0]; +`endif endmodule diff --git a/cores/primitive/lvds_comparator/lvds_comparator.core b/cores/primitive/lvds_comparator/lvds_comparator.core new file mode 100644 index 0000000..efb8098 --- /dev/null +++ b/cores/primitive/lvds_comparator/lvds_comparator.core @@ -0,0 +1,26 @@ +CAPI=2: + +name: joppeb:primitive:lvds_comparator:1.0 +description: LVDS comparator wrapper + +filesets: + wrapper: + files: + - lvds_comparator.v + file_type: verilogSource + generic: + files: + - lvds_comparator_generic_impl.v + file_type: verilogSource + spartan6: + files: + - lvds_comparator_spartan6.v + file_type: verilogSource + +targets: + default: + filesets: + - wrapper + - generic + - spartan6 + toplevel: lvds_comparator diff --git a/cores/primitive/lvds_comparator/lvds_comparator.v b/cores/primitive/lvds_comparator/lvds_comparator.v new file mode 100644 index 0000000..b3076e4 --- /dev/null +++ b/cores/primitive/lvds_comparator/lvds_comparator.v @@ -0,0 +1,19 @@ +module lvds_comparator( + input wire a, + input wire b, + output wire o +); +`ifdef FPGA_SPARTAN6 + lvds_comparator_spartan6_impl impl_i ( + .a(a), + .b(b), + .o(o) + ); +`else + lvds_comparator_generic_impl impl_i ( + .a(a), + .b(b), + .o(o) + ); +`endif +endmodule \ No newline at end of file diff --git a/cores/primitive/lvds_comparator/lvds_comparator_generic_impl.v b/cores/primitive/lvds_comparator/lvds_comparator_generic_impl.v new file mode 100644 index 0000000..2c495a2 --- /dev/null +++ b/cores/primitive/lvds_comparator/lvds_comparator_generic_impl.v @@ -0,0 +1,7 @@ +module lvds_comparator_generic_impl ( + input wire a, + input wire b, + output wire o +); + assign o = a; +endmodule \ No newline at end of file diff --git a/cores/primitive/lvds_comparator/lvds_comparator_spartan6.v b/cores/primitive/lvds_comparator/lvds_comparator_spartan6.v new file mode 100644 index 0000000..2eeaa04 --- /dev/null +++ b/cores/primitive/lvds_comparator/lvds_comparator_spartan6.v @@ -0,0 +1,14 @@ +module lvds_comparator_spartan6_impl ( + input wire a, + input wire b, + output wire o +); + IBUFDS #( + .DIFF_TERM("FALSE"), + .IOSTANDARD("LVDS33") + ) lvds_buf ( + .O(o), + .I(a), + .IB(b) + ); +endmodule \ No newline at end of file diff --git a/cores/signal/decimate_by_r_q15.v/decimate_by_r_q15.core b/cores/signal/decimate_by_r_q15.v/decimate_by_r_q15.core new file mode 100644 index 0000000..418144c --- /dev/null +++ b/cores/signal/decimate_by_r_q15.v/decimate_by_r_q15.core @@ -0,0 +1,29 @@ +CAPI=2: + +name: joppeb:signal:decimate_by_r_q15:1.0 +description: Q1.15 integer-rate decimator + +filesets: + rtl: + files: + - decimate_by_r_q15.v + file_type: verilogSource + +targets: + default: + filesets: + - rtl + toplevel: decimate_by_r_q15 + parameters: + - R + - CNT_W + +parameters: + R: + datatype: int + description: Integer decimation ratio + paramtype: vlogparam + CNT_W: + datatype: int + description: Counter width for the decimation counter + paramtype: vlogparam diff --git a/rtl/core/decimate_by_r_q15.v b/cores/signal/decimate_by_r_q15.v/decimate_by_r_q15.v similarity index 61% rename from rtl/core/decimate_by_r_q15.v rename to cores/signal/decimate_by_r_q15.v/decimate_by_r_q15.v index 60df0c3..49aedeb 100644 --- a/rtl/core/decimate_by_r_q15.v +++ b/cores/signal/decimate_by_r_q15.v/decimate_by_r_q15.v @@ -3,15 +3,15 @@ // ============================================================================= // Decimator by R // Reduces the effective sample rate by an integer factor R by selecting every -// R-th input sample. Generates a one-cycle 'out_valid' pulse each time a new +// R-th input sample. Generates a one-cycle 'o_valid' pulse each time a new // decimated sample is produced. // // Implements: // For each valid input sample: // if (count == R-1): // count <= 0 -// out_q15 <= in_q15 -// out_valid <= 1 +// o_q15 <= i_q15 +// o_valid <= 1 // else: // count <= count + 1 // @@ -21,12 +21,12 @@ // -- CNT_W : counter bit width, must satisfy 2^CNT_W > R // // inout: -// -- clk : input clock (same rate as 'in_valid') -// -- rst_n : active-low synchronous reset -// -- in_valid : input data strobe; assert 1'b1 if input is always valid -// -- in_q15 : signed 16-bit Q1.15 input sample (full-rate) -// -- out_valid : single-cycle pulse every R samples (decimated rate strobe) -// -- out_q15 : signed 16-bit Q1.15 output sample (decimated stream) +// -- i_clk : input clock (same rate as 'i_valid') +// -- i_rst_n : active-low synchronous reset +// -- i_valid : input data strobe; assert 1'b1 if input is always valid +// -- i_q15 : signed 16-bit Q1.15 input sample (full-rate) +// -- o_valid : single-cycle pulse every R samples (decimated rate strobe) +// -- o_q15 : signed 16-bit Q1.15 output sample (decimated stream) // // Notes: // - This module performs *pure downsampling* (sample selection only). @@ -43,28 +43,28 @@ module decimate_by_r_q15 #( parameter integer R = 400, // decimation factor parameter integer CNT_W = 10 // width so that 2^CNT_W > R (e.g., 10 for 750) )( - input wire clk, - input wire rst_n, - input wire in_valid, // assert 1'b1 if always valid - input wire signed [15:0] in_q15, // Q1.15 sample at full rate - output reg out_valid, // 1-cycle pulse every R samples - output reg signed [15:0] out_q15 // Q1.15 sample at decimated rate + input wire i_clk, + input wire i_rst_n, + input wire i_valid, // assert 1'b1 if always valid + input wire signed [15:0] i_q15, // Q1.15 sample at full rate + output reg o_valid, // 1-cycle pulse every R samples + output reg signed [15:0] o_q15 // Q1.15 sample at decimated rate ); reg [CNT_W-1:0] cnt; - always @(posedge clk or negedge rst_n) begin - if (!rst_n) begin + always @(posedge i_clk or negedge i_rst_n) begin + if (!i_rst_n) begin cnt <= {CNT_W{1'b0}}; - out_valid <= 1'b0; - out_q15 <= 16'sd0; + o_valid <= 1'b0; + o_q15 <= 16'sd0; end else begin - out_valid <= 1'b0; + o_valid <= 1'b0; - if (in_valid) begin + if (i_valid) begin if (cnt == R-1) begin cnt <= {CNT_W{1'b0}}; - out_q15 <= in_q15; - out_valid <= 1'b1; + o_q15 <= i_q15; + o_valid <= 1'b1; end else begin cnt <= cnt + 1'b1; end diff --git a/cores/signal/lpf_iir_q15_k/lpf_iir_q15_k.core b/cores/signal/lpf_iir_q15_k/lpf_iir_q15_k.core new file mode 100644 index 0000000..b134b5d --- /dev/null +++ b/cores/signal/lpf_iir_q15_k/lpf_iir_q15_k.core @@ -0,0 +1,24 @@ +CAPI=2: + +name: joppeb:signal:lpf_iir_q15_k:1.0 +description: First-order Q1.15 IIR low-pass filter + +filesets: + rtl: + files: + - lpf_iir_q15_k.v + file_type: verilogSource + +targets: + default: + filesets: + - rtl + toplevel: lpf_iir_q15_k + parameters: + - K + +parameters: + K: + datatype: int + description: Filter shift factor + paramtype: vlogparam diff --git a/rtl/core/lpf_iir_q15_k.v b/cores/signal/lpf_iir_q15_k/lpf_iir_q15_k.v similarity index 71% rename from rtl/core/lpf_iir_q15_k.v rename to cores/signal/lpf_iir_q15_k/lpf_iir_q15_k.v index 346124f..bfcaaa0 100644 --- a/rtl/core/lpf_iir_q15_k.v +++ b/cores/signal/lpf_iir_q15_k/lpf_iir_q15_k.v @@ -21,10 +21,10 @@ // larger K → lower cutoff // // inout: -// -- clk : input clock -// -- rst_n : active-low reset -// -- x_q15 : signed 16-bit Q1.15 input sample (e.g., 0..0x7FFF) -// -- y_q15 : signed 16-bit Q1.15 filtered output +// -- i_clk : input clock +// -- i_rst_n : active-low reset +// -- i_x_q15 : signed 16-bit Q1.15 input sample (e.g., 0..0x7FFF) +// -- o_y_q15 : signed 16-bit Q1.15 filtered output // // Notes: // - The arithmetic right shift implements division by 2^K. @@ -36,14 +36,14 @@ module lpf_iir_q15_k #( parameter integer K = 10 // try 8..12; bigger = more smoothing )( - input wire clk, - input wire rst_n, - input wire signed [15:0] x_q15, // Q1.15 input (e.g., 0..0x7FFF) - output reg signed [15:0] y_q15 // Q1.15 output + input wire i_clk, + input wire i_rst_n, + input wire signed [15:0] i_x_q15, // Q1.15 input (e.g., 0..0x7FFF) + output reg signed [15:0] o_y_q15 // Q1.15 output ); - wire signed [15:0] e_q15 = x_q15 - y_q15; + wire signed [15:0] e_q15 = i_x_q15 - o_y_q15; wire signed [15:0] delta_q15 = e_q15 >>> K; // arithmetic shift - wire signed [15:0] y_next = y_q15 + delta_q15; // clamp to [0, 0x7FFF] (handy if your signal is non-negative) + wire signed [15:0] y_next = o_y_q15 + delta_q15; // clamp to [0, 0x7FFF] (handy if your signal is non-negative) function signed [15:0] clamp01; input signed [15:0] v; @@ -57,8 +57,8 @@ module lpf_iir_q15_k #( end endfunction - always @(posedge clk or negedge rst_n) begin - if (!rst_n) y_q15 <= 16'sd0; - else y_q15 <= clamp01(y_next); + always @(posedge i_clk or negedge i_rst_n) begin + if (!i_rst_n) o_y_q15 <= 16'sd0; + else o_y_q15 <= clamp01(y_next); end endmodule diff --git a/cores/signal/nco_q15/nco_q15.core b/cores/signal/nco_q15/nco_q15.core new file mode 100644 index 0000000..6db61d5 --- /dev/null +++ b/cores/signal/nco_q15/nco_q15.core @@ -0,0 +1,40 @@ +CAPI=2: + +name: joppeb:signal:nco_q15:1.0 +description: A number controlled sine and cosine oscillator + +filesets: + rtl: + files: + - rtl/nco_q15.v + file_type: verilogSource + + tb: + files: + - tb/tb_nco_q15.v + file_type: verilogSource + +targets: + default: + filesets: + - rtl + toplevel: nco_q15 + parameters: + - CLK_HZ + - FS_HZ + sim: + default_tool: icarus + filesets: + - rtl + - tb + toplevel: tb_nco_q15 + +parameters: + CLK_HZ: + datatype: int + description: Frequency of the input clock + paramtype: vlogparam + FS_HZ: + datatype: int + description: Sample Frequency + paramtype: vlogparam \ No newline at end of file diff --git a/cores/signal/nco_q15/rtl/nco_q15.v b/cores/signal/nco_q15/rtl/nco_q15.v new file mode 100644 index 0000000..13c6bb4 --- /dev/null +++ b/cores/signal/nco_q15/rtl/nco_q15.v @@ -0,0 +1,163 @@ +`timescale 1ns/1ps + +// ============================================================================= +// Small number controlled oscillator +// Generates a sine and cosine and uses no multiplications, just some logic and +// a 64-entry LUT. It outputs Q15 data (but the LUT is 8 bits wide) +// params: +// -- CLK_HZ : input clock frequency in Hz +// -- FS_HZ : output sample frequency in Hz +// inout: +// -- i_clk : input clock +// -- i_rst_n : reset +// -- i_freq_hz : decimal number of desired generated frequency in Hz, 0-FS/2 +// -- o_sin_q15/o_cos_q15 : I and Q outputs +// -- o_clk_en : output valid strobe +// ============================================================================= +module nco_q15 #( + parameter integer CLK_HZ = 120_000_000, // input clock + parameter integer FS_HZ = 40_000 // sample rate +)( + input wire i_clk, // CLK_HZ domain + input wire i_rst_n, // async active-low reset + input wire [31:0] i_freq_hz, // desired output frequency (Hz), 0..FS_HZ/2 + + output reg signed [15:0] o_sin_q15, // Q1.15 sine + output reg signed [15:0] o_cos_q15, // Q1.15 cosine + output reg o_clk_en // 1-cycle strobe @ FS_HZ +); + localparam integer PHASE_FRAC_BITS = 6; + localparam integer QTR_ADDR_BITS = 6; + localparam integer PHASE_BITS = 2 + QTR_ADDR_BITS + PHASE_FRAC_BITS; + localparam integer DIV = CLK_HZ / FS_HZ; + localparam integer SHIFT = 32; + + // Fixed-point reciprocal (constant): RECIP = round( (2^PHASE_BITS * 2^SHIFT) / FS_HZ ) + localparam [63:0] RECIP = ( ((64'd1 << PHASE_BITS) << SHIFT) + (FS_HZ/2) ) / FS_HZ; + + // Sample-rate tick + function integer clog2; + input integer v; integer r; begin r=0; v=v-1; while (v>0) begin v=v>>1; r=r+1; end clog2=r; end + endfunction + + reg [clog2(DIV)-1:0] tick_cnt; + always @(posedge i_clk or negedge i_rst_n) begin + if (!i_rst_n) begin tick_cnt <= 0; o_clk_en <= 1'b0; end + else begin + o_clk_en <= 1'b0; + if (tick_cnt == DIV-1) begin tick_cnt <= 0; o_clk_en <= 1'b1; end + else tick_cnt <= tick_cnt + 1'b1; + end + end + + // 32-cycle shift-add multiply: prod = i_freq_hz * RECIP (no multiplications themself) + // Starts at o_clk_en, finishes in 32 cycles (<< available cycles per sample). + reg mul_busy; + reg [5:0] mul_i; // 0..31 + reg [31:0] f_reg; + reg [95:0] acc; // accumulator for product (32x64 -> 96b) + + wire [95:0] recip_shift = {{32{1'b0}}, RECIP} << mul_i; // shift constant by i + + always @(posedge i_clk or negedge i_rst_n) begin + if (!i_rst_n) begin + mul_busy <= 1'b0; mul_i <= 6'd0; f_reg <= 32'd0; acc <= 96'd0; + end else begin + if (o_clk_en && !mul_busy) begin + // kick off a new multiply this sample + mul_busy <= 1'b1; + mul_i <= 6'd0; + f_reg <= (i_freq_hz > (FS_HZ>>1)) ? (FS_HZ>>1) : i_freq_hz; // clamp to Nyquist + acc <= 96'd0; + end else if (mul_busy) begin + // add shifted RECIP if bit is set + if (f_reg[mul_i]) acc <= acc + recip_shift; + // next bit + if (mul_i == 6'd31) begin + mul_busy <= 1'b0; // done in 32 cycles + end + mul_i <= mul_i + 6'd1; + end + end + end + + // Rounding shift to get FTW; latch when multiply finishes. + reg [PHASE_BITS-1:0] ftw_q; + wire [95:0] acc_round = acc + (96'd1 << (SHIFT-1)); + wire [PHASE_BITS-1:0] ftw_next = acc_round[SHIFT +: PHASE_BITS]; // >> SHIFT + + always @(posedge i_clk or negedge i_rst_n) begin + if (!i_rst_n) ftw_q <= {PHASE_BITS{1'b0}}; + else if (!mul_busy) ftw_q <= ftw_next; // update once product ready + end + + // Phase accumulator (advance at FS_HZ) + reg [PHASE_BITS-1:0] phase; + always @(posedge i_clk or negedge i_rst_n) begin + if (!i_rst_n) phase <= {PHASE_BITS{1'b0}}; + else if (o_clk_en) phase <= phase + ftw_q; + end + + // Cosine phase = sine phase + 90° + wire [PHASE_BITS-1:0] phase_cos = phase + ({{(PHASE_BITS-2){1'b0}}, 2'b01} << (PHASE_BITS-2)); + + // Quadrant & LUT index + wire [1:0] q_sin = phase [PHASE_BITS-1 -: 2]; + wire [1:0] q_cos = phase_cos[PHASE_BITS-1 -: 2]; + + wire [QTR_ADDR_BITS-1:0] idx_sin_raw = phase [PHASE_BITS-3 -: QTR_ADDR_BITS]; + wire [QTR_ADDR_BITS-1:0] idx_cos_raw = phase_cos[PHASE_BITS-3 -: QTR_ADDR_BITS]; + + wire [QTR_ADDR_BITS-1:0] idx_sin = q_sin[0] ? ({QTR_ADDR_BITS{1'b1}} - idx_sin_raw) : idx_sin_raw; + wire [QTR_ADDR_BITS-1:0] idx_cos = q_cos[0] ? ({QTR_ADDR_BITS{1'b1}} - idx_cos_raw) : idx_cos_raw; + + // 64-entry quarter-wave LUT + wire [7:0] mag_sin_u8, mag_cos_u8; + sine_qtr_lut64 u_lut_s (.i_addr(idx_sin), .o_dout(mag_sin_u8)); + sine_qtr_lut64 u_lut_c (.i_addr(idx_cos), .o_dout(mag_cos_u8)); + + // Scale to Q1.15 and apply sign + wire signed [15:0] mag_sin_q15 = {1'b0, mag_sin_u8, 7'd0}; + wire signed [15:0] mag_cos_q15 = {1'b0, mag_cos_u8, 7'd0}; + wire sin_neg = (q_sin >= 2); + wire cos_neg = (q_cos >= 2); + + wire signed [15:0] sin_next = sin_neg ? -mag_sin_q15 : mag_sin_q15; + wire signed [15:0] cos_next = cos_neg ? -mag_cos_q15 : mag_cos_q15; + + always @(posedge i_clk or negedge i_rst_n) begin + if (!i_rst_n) begin + o_sin_q15 <= 16'sd0; o_cos_q15 <= 16'sd0; + end else if (o_clk_en) begin + o_sin_q15 <= sin_next; o_cos_q15 <= cos_next; + end + end + +endmodule + +module sine_qtr_lut64( + input wire [5:0] i_addr, + output reg [7:0] o_dout +); + always @* begin + case (i_addr) + 6'd0: o_dout = 8'd0; 6'd1: o_dout = 8'd6; 6'd2: o_dout = 8'd13; 6'd3: o_dout = 8'd19; + 6'd4: o_dout = 8'd25; 6'd5: o_dout = 8'd31; 6'd6: o_dout = 8'd37; 6'd7: o_dout = 8'd44; + 6'd8: o_dout = 8'd50; 6'd9: o_dout = 8'd56; 6'd10: o_dout = 8'd62; 6'd11: o_dout = 8'd68; + 6'd12: o_dout = 8'd74; 6'd13: o_dout = 8'd80; 6'd14: o_dout = 8'd86; 6'd15: o_dout = 8'd92; + 6'd16: o_dout = 8'd98; 6'd17: o_dout = 8'd103; 6'd18: o_dout = 8'd109; 6'd19: o_dout = 8'd115; + 6'd20: o_dout = 8'd120; 6'd21: o_dout = 8'd126; 6'd22: o_dout = 8'd131; 6'd23: o_dout = 8'd136; + 6'd24: o_dout = 8'd142; 6'd25: o_dout = 8'd147; 6'd26: o_dout = 8'd152; 6'd27: o_dout = 8'd157; + 6'd28: o_dout = 8'd162; 6'd29: o_dout = 8'd167; 6'd30: o_dout = 8'd171; 6'd31: o_dout = 8'd176; + 6'd32: o_dout = 8'd180; 6'd33: o_dout = 8'd185; 6'd34: o_dout = 8'd189; 6'd35: o_dout = 8'd193; + 6'd36: o_dout = 8'd197; 6'd37: o_dout = 8'd201; 6'd38: o_dout = 8'd205; 6'd39: o_dout = 8'd208; + 6'd40: o_dout = 8'd212; 6'd41: o_dout = 8'd215; 6'd42: o_dout = 8'd219; 6'd43: o_dout = 8'd222; + 6'd44: o_dout = 8'd225; 6'd45: o_dout = 8'd228; 6'd46: o_dout = 8'd231; 6'd47: o_dout = 8'd233; + 6'd48: o_dout = 8'd236; 6'd49: o_dout = 8'd238; 6'd50: o_dout = 8'd240; 6'd51: o_dout = 8'd242; + 6'd52: o_dout = 8'd244; 6'd53: o_dout = 8'd246; 6'd54: o_dout = 8'd247; 6'd55: o_dout = 8'd249; + 6'd56: o_dout = 8'd250; 6'd57: o_dout = 8'd251; 6'd58: o_dout = 8'd252; 6'd59: o_dout = 8'd253; + 6'd60: o_dout = 8'd254; 6'd61: o_dout = 8'd254; 6'd62: o_dout = 8'd255; 6'd63: o_dout = 8'd255; + default: o_dout=8'd0; + endcase + end +endmodule diff --git a/sim/tb/tb_nco_q15.v b/cores/signal/nco_q15/tb/tb_nco_q15.v similarity index 70% rename from sim/tb/tb_nco_q15.v rename to cores/signal/nco_q15/tb/tb_nco_q15.v index 0ca2e0a..5f81fcc 100644 --- a/sim/tb/tb_nco_q15.v +++ b/cores/signal/nco_q15/tb/tb_nco_q15.v @@ -9,35 +9,34 @@ module tb_nco_q15(); always #4.17 clk <= !clk; initial #40 resetn <= 1'b1; - // Default run - initial begin - $dumpfile("out.vcd"); - $dumpvars; - #5_000_000 - $finish; - end; - - reg [31:0] freq; wire [15:0] sin_q15; wire [15:0] cos_q15; wire out_en; nco_q15 #(.CLK_HZ(120_000_000), .FS_HZ(40_000)) nco ( - .clk (clk), - .rst_n (resetn), - .freq_hz(freq), - .sin_q15(sin_q15), - .cos_q15(cos_q15), - .clk_en (out_en) + .i_clk (clk), + .i_rst_n (resetn), + .i_freq_hz(freq), + .o_sin_q15(sin_q15), + .o_cos_q15(cos_q15), + .o_clk_en (out_en) ); initial begin + $dumpfile("out.vcd"); + $dumpvars; + freq = 32'h0; #100 freq = 32'd1000; #2_500_000 freq = 32'd2000; + #2_500_000 + freq = 32'd600; + #2_500_000 + + $finish; end; -endmodule \ No newline at end of file +endmodule diff --git a/rtl/util/rc_alpha_q15.vh b/cores/signal/sd_adc_q15/rtl/rc_alpha_q15.vh similarity index 100% rename from rtl/util/rc_alpha_q15.vh rename to cores/signal/sd_adc_q15/rtl/rc_alpha_q15.vh diff --git a/rtl/core/sigmadelta_rcmodel_q15.v b/cores/signal/sd_adc_q15/rtl/rcmodel_q15.v similarity index 64% rename from rtl/core/sigmadelta_rcmodel_q15.v rename to cores/signal/sd_adc_q15/rtl/rcmodel_q15.v index 7b737c8..505d4f5 100644 --- a/rtl/core/sigmadelta_rcmodel_q15.v +++ b/cores/signal/sd_adc_q15/rtl/rcmodel_q15.v @@ -9,26 +9,33 @@ // rounded to only use two bits (0b3b -> 0b00), the less // bits the better // inout: -// -- clk : input clock -// -- resetn : reset signal -// -- sd_sample : 1 bit sample output from sd sampler -// -- sample_q15 : output samples in q.15 +// -- i_clk : input clock +// -- i_rst_n : reset signal +// -- i_sd_sample : 1 bit sample output from sd sampler +// -- o_sample_q15 : output samples in q.15 // ============================================================================= -module sigmadelta_rcmodel_q15 #( +module rcmodel_q15 #( parameter integer alpha_q15 = 16'sh0b00 )( - input wire clk, - input wire resetn, - input wire sd_sample, - output wire [15:0] sample_q15 + input wire i_clk, + input wire i_rst_n, + input wire i_sd_sample, + output wire [15:0] o_sample_q15 ); reg signed [15:0] y_q15; - wire signed [15:0] sd_q15 = sd_sample ? 16'sh7fff : 16'sh0000; + wire signed [15:0] sd_q15 = i_sd_sample ? 16'sh7fff : 16'sh0000; wire signed [15:0] e_q15 = sd_q15 - y_q15; // wire signed [31:0] prod_q30 = $signed(e_q15) * $signed(alpha_q15); wire signed [31:0] prod_q30; // Use shift-add algorithm for multiplication - mul_const_shiftadd #(.C($signed(alpha_q15))) alpha_times_e ($signed(e_q15), prod_q30); + mul_const_shiftadd #( + .C($signed(alpha_q15)), + .IN_W(16), + .OUT_W(32) + ) alpha_times_e ( + .i_x(e_q15), + .o_y(prod_q30) + ); wire signed [15:0] y_next_q15 = y_q15 + (prod_q30>>>15); // clamp to [0, 0x7FFF] (keeps signal view tidy) @@ -38,11 +45,11 @@ module sigmadelta_rcmodel_q15 #( else clamp01_q15 = v; endfunction - always @(posedge clk or negedge resetn) begin - if (!resetn) y_q15 <= 16'sd0000; + always @(posedge i_clk or negedge i_rst_n) begin + if (!i_rst_n) y_q15 <= 16'sd0000; else y_q15 <= clamp01_q15(y_next_q15); end - assign sample_q15 = y_q15; + assign o_sample_q15 = y_q15; endmodule diff --git a/cores/signal/sd_adc_q15/rtl/sd_adc_q15.v b/cores/signal/sd_adc_q15/rtl/sd_adc_q15.v new file mode 100644 index 0000000..7130a25 --- /dev/null +++ b/cores/signal/sd_adc_q15/rtl/sd_adc_q15.v @@ -0,0 +1,57 @@ +module sd_adc_q15 #( + parameter integer R_OHM = 3300, + parameter integer C_PF = 220 +)( + input wire i_clk_15, + input wire i_rst_n, + + input wire i_adc_a, + input wire i_adc_b, + output wire o_adc, + + output wire signed [15:0] o_signal_q15, + output wire o_signal_valid +); + `include "rc_alpha_q15.vh" + + wire sd_signal; + wire signed [15:0] raw_sample_biased; + wire signed [15:0] raw_sample_q15; + wire signed [15:0] lpf_sample_q15; + + sd_sampler sd_sampler( + .i_clk(i_clk_15), + .i_a(i_adc_a), .i_b(i_adc_b), + .o_sample(sd_signal) + ); + assign o_adc = sd_signal; + + localparam integer alpha_q15_int = alpha_q15_from_rc(R_OHM, C_PF, 15000000); + localparam signed [15:0] alpha_q15 = alpha_q15_int[15:0]; + localparam signed [15:0] alpha_q15_top = alpha_q15 & 16'hff00; + rcmodel_q15 #( + .alpha_q15(alpha_q15_top) + ) rc_model ( + .i_clk(i_clk_15), .i_rst_n(i_rst_n), + .i_sd_sample(sd_signal), + .o_sample_q15(raw_sample_q15) + ); + + lpf_iir_q15_k #( + .K(10) + ) lpf ( + .i_clk(i_clk_15), .i_rst_n(i_rst_n), + .i_x_q15(raw_sample_q15), + .o_y_q15(lpf_sample_q15) + ); + + decimate_by_r_q15 #( + .R(375), // 15MHz/375 = 40KHz + .CNT_W(10) + ) decimate ( + .i_clk(i_clk_15), .i_rst_n(i_rst_n), + .i_valid(1'b1), .i_q15(lpf_sample_q15), + .o_valid(o_signal_valid), .o_q15(o_signal_q15) + ); + +endmodule diff --git a/cores/signal/sd_adc_q15/rtl/sd_sampler.v b/cores/signal/sd_adc_q15/rtl/sd_sampler.v new file mode 100644 index 0000000..e17fa19 --- /dev/null +++ b/cores/signal/sd_adc_q15/rtl/sd_sampler.v @@ -0,0 +1,18 @@ +module sd_sampler( + input wire i_clk, + input wire i_a, + input wire i_b, + output wire o_sample +); + + wire comp_out; + lvds_comparator comp ( + .a(i_a), .b(i_b), .o(comp_out) + ); + + reg registered_comp_out; + always @(posedge i_clk) + registered_comp_out <= comp_out; + assign o_sample = registered_comp_out; + +endmodule diff --git a/cores/signal/sd_adc_q15/sd_adc_q15.core b/cores/signal/sd_adc_q15/sd_adc_q15.core new file mode 100644 index 0000000..361973d --- /dev/null +++ b/cores/signal/sd_adc_q15/sd_adc_q15.core @@ -0,0 +1,57 @@ +CAPI=2: + +name: joppeb:signal:sd_adc_q15:1.0 +description: Sigma-delta ADC front-end with Q1.15 output + +filesets: + rtl_common: + depend: + - joppeb:primitive:lvds_comparator + - joppeb:signal:lpf_iir_q15_k + - joppeb:signal:decimate_by_r_q15 + - joppeb:util:mul_const + files: + - rtl/rc_alpha_q15.vh: + is_include_file: true + - rtl/rcmodel_q15.v + - rtl/sd_adc_q15.v + file_type: verilogSource + rtl_sampler: + files: + - rtl/sd_sampler.v + file_type: verilogSource + sim_sampler: + files: + - sim/sd_sampler.v + file_type: verilogSource + tb: + files: + - tb/tb_sd_adc_q15.v + file_type: verilogSource + +targets: + default: + filesets: + - rtl_common + - rtl_sampler + toplevel: sd_adc_q15 + parameters: + - R_OHM + - C_PF + sim: + default_tool: icarus + filesets: + - rtl_common + - sim_sampler + - tb + toplevel: tb_sd_adc_q15 + +parameters: + R_OHM: + datatype: int + description: RC filter resistor value in ohms + paramtype: vlogparam + C_PF: + datatype: int + description: RC filter capacitor value in pF + paramtype: vlogparam diff --git a/sim/overrides/sigmadelta_sampler.v b/cores/signal/sd_adc_q15/sim/sd_sampler.v similarity index 84% rename from sim/overrides/sigmadelta_sampler.v rename to cores/signal/sd_adc_q15/sim/sd_sampler.v index 5c56c4b..99f2d1a 100644 --- a/sim/overrides/sigmadelta_sampler.v +++ b/cores/signal/sd_adc_q15/sim/sd_sampler.v @@ -2,17 +2,17 @@ // ============================================================================= // Sigma-Delta sampler -// Simulates an RC circuit between O and B and a sine at A +// Simulates an RC circuit between o_sample and i_b and i_a sine at i_a // ============================================================================= -module sigmadelta_sampler( - input wire clk, - input wire a, - input wire b, - output wire o +module sd_sampler( + input wire i_clk, + input wire i_a, + input wire i_b, + output wire o_sample ); - // Sine source (A input / P) - parameter real F_HZ = 1.5e3; // input sine frequency (1 kHz) + // Sine source (i_a input / P) + parameter real F_HZ = 5000; // input sine frequency (1 kHz) parameter real AMP = 1.5; // sine amplitude (V) parameter real VCM = 1.65; // common-mode (V), centered in 0..3.3V @@ -25,7 +25,7 @@ module sigmadelta_sampler( parameter real VLOW = 0.0; // DAC 0 (V) parameter real VHIGH = 3.3; // DAC 1 (V) - // RC filter (B input / N) + // RC filter (i_b input / N) parameter real R_OHMS = 3300.0; // 3.3k parameter real C_FARADS = 220e-12; // 220 pF @@ -33,9 +33,9 @@ module sigmadelta_sampler( parameter integer TSTEP_NS = 10; // sim step in ns (choose << tau) // ===== Internal state (simulation only) ===== - real vp, vn; // comparator A/B inputs + real vp, vn; // comparator i_a/i_b inputs real v_rc; // RC node voltage (== vn) - real v_dac; // DAC output voltage from O + real v_dac; // DAC output voltage from o_sample real t_s; // time in seconds real dt_s; // step in seconds real tau_s; // R*C time constant in seconds @@ -45,10 +45,10 @@ module sigmadelta_sampler( reg sampler; initial sampler <= 1'b0; - always @(posedge clk) begin + always @(posedge i_clk) begin sampler <= out; end - assign o = sampler; + assign o_sample = sampler; // Helper task: update comparator with optional hysteresis @@ -96,7 +96,7 @@ module sigmadelta_sampler( v_rc = v_rc + (v_dac - v_rc) * (dt_s / tau_s); vn = v_rc; - // 3) Input sine on A + // 3) Input sine on i_a vp = VCM + AMP * $sin(two_pi * F_HZ * t_s); // 4) Comparator decision (with optional hysteresis) @@ -108,4 +108,4 @@ module sigmadelta_sampler( end -endmodule \ No newline at end of file +endmodule diff --git a/sim/tb/tb_sigmadelta.v b/cores/signal/sd_adc_q15/tb/tb_sd_adc_q15.v similarity index 70% rename from sim/tb/tb_sigmadelta.v rename to cores/signal/sd_adc_q15/tb/tb_sd_adc_q15.v index 4d09fd2..c5ce51f 100644 --- a/sim/tb/tb_sigmadelta.v +++ b/cores/signal/sd_adc_q15/tb/tb_sd_adc_q15.v @@ -1,6 +1,6 @@ `timescale 1ns/1ps -module tb_sigmadelta(); +module tb_sd_adc_q15(); // Clock and reset generation reg clk; reg resetn; @@ -23,14 +23,14 @@ module tb_sigmadelta(); wire signed [15:0] decimated_q15; wire decimated_valid; - sigmadelta_input #( + sd_adc_q15 #( .R_OHM(3300), .C_PF(220) ) dut( - .clk_15(clk), .resetn(resetn), - .adc_a(sd_a), .adc_b(sd_b), .adc_o(sd_o), - .signal_q15(decimated_q15), - .signal_valid(decimated_valid) + .i_clk_15(clk), .i_rst_n(resetn), + .i_adc_a(sd_a), .i_adc_b(sd_b), .o_adc(sd_o), + .o_signal_q15(decimated_q15), + .o_signal_valid(decimated_valid) ); endmodule diff --git a/cores/system/mcu/mcu.core b/cores/system/mcu/mcu.core new file mode 100644 index 0000000..4839bad --- /dev/null +++ b/cores/system/mcu/mcu.core @@ -0,0 +1,48 @@ +CAPI=2: + +name: joppeb:system:mcu:1.0 +description: basic RISC-V MCU system + +filesets: + rtl: + depend: + - "^award-winning:serv:servile:1.4.0" + - joppeb:util:clog2 + - joppeb:wb:jtag_wb_bridge + - joppeb:wb:wb_gpio_banks + - joppeb:wb:wb_timer + - joppeb:wb:wb_arbiter + - joppeb:wb:wb_mux + files: + - rtl/mcu.v + - rtl/mcu_peripherals.v + file_type: verilogSource + +targets: + default: + filesets: + - rtl + toplevel: mcu + parameters: + - memfile + - memsize + - sim + - jtag + +parameters: + memfile: + datatype: str + description: Memory initialization file passed to the internal RAM + paramtype: vlogparam + memsize: + datatype: int + description: Internal RAM size in bytes + paramtype: vlogparam + sim: + datatype: int + description: Enable simulation-friendly RAM initialization behavior + paramtype: vlogparam + jtag: + datatype: int + description: Enable the JTAG Wishbone bridge and arbiter path + paramtype: vlogparam diff --git a/rtl/core/mcu.v b/cores/system/mcu/rtl/mcu.v similarity index 99% rename from rtl/core/mcu.v rename to cores/system/mcu/rtl/mcu.v index f7860a5..16f094f 100644 --- a/rtl/core/mcu.v +++ b/cores/system/mcu/rtl/mcu.v @@ -1,5 +1,5 @@ `timescale 1ns/1ps -`include "../util/clog2.vh" +`include "clog2.vh" module mcu #( parameter memfile = "", diff --git a/rtl/core/mcu_peripherals.v b/cores/system/mcu/rtl/mcu_peripherals.v similarity index 93% rename from rtl/core/mcu_peripherals.v rename to cores/system/mcu/rtl/mcu_peripherals.v index 771445e..ec3d61b 100644 --- a/rtl/core/mcu_peripherals.v +++ b/cores/system/mcu/rtl/mcu_peripherals.v @@ -44,7 +44,9 @@ module mcu_peripherals ( wire [31:0] gpio_wbs_dat_r; wire gpio_wbs_ack; + wire [31:0] timer_wbs_adr = wbs_adr[1*32 +: 32]; wire [31:0] timer_wbs_dat_w = wbs_dat_w[1*32 +: 32]; + wire [3:0] timer_wbs_sel = wbs_sel[1*4 +: 4]; wire timer_wbs_we = wbs_we[1]; wire timer_wbs_cyc = wbs_cyc[1]; wire timer_wbs_stb = wbs_stb[1]; @@ -97,7 +99,8 @@ module mcu_peripherals ( .i_wb_dat(gpio_wbs_dat_w), .i_wb_adr(gpio_wbs_adr), .i_wb_we(gpio_wbs_we), - .i_wb_stb(gpio_wbs_stb & gpio_wbs_cyc), + .i_wb_stb(gpio_wbs_stb), + .i_wb_cyc(gpio_wbs_cyc), .i_wb_sel(gpio_wbs_sel), .o_wb_rdt(gpio_wbs_dat_r), .o_wb_ack(gpio_wbs_ack), @@ -112,8 +115,10 @@ module mcu_peripherals ( .i_clk(i_clk), .i_rst(i_rst), .o_irq(o_timer_irq), + .i_wb_adr(timer_wbs_adr), .i_wb_dat(timer_wbs_dat_w), .o_wb_dat(timer_wbs_dat_r), + .i_wb_sel(timer_wbs_sel), .i_wb_we(timer_wbs_we), .i_wb_cyc(timer_wbs_cyc), .i_wb_stb(timer_wbs_stb), diff --git a/boards/mimas_v1/constraints.ucf b/cores/system/test/mimas.ucf similarity index 100% rename from boards/mimas_v1/constraints.ucf rename to cores/system/test/mimas.ucf diff --git a/cores/system/test/options.tcl b/cores/system/test/options.tcl new file mode 100644 index 0000000..dcd3c00 --- /dev/null +++ b/cores/system/test/options.tcl @@ -0,0 +1 @@ +project set "Create Binary Configuration File" TRUE -process "Generate Programming File" \ No newline at end of file diff --git a/rtl/toplevel/top_generic.v b/cores/system/test/rtl/toplevel.v similarity index 81% rename from rtl/toplevel/top_generic.v rename to cores/system/test/rtl/toplevel.v index cec58d2..49830a5 100644 --- a/rtl/toplevel/top_generic.v +++ b/cores/system/test/rtl/toplevel.v @@ -1,7 +1,8 @@ `timescale 1ns/1ps -module top_generic #( - parameter sim = 0 +module toplevel #( + parameter sim = 0, + parameter memfile = "sweep.hex" )( input wire aclk, input wire aresetn, @@ -11,18 +12,24 @@ module top_generic #( output wire[5:0] r2r, output wire[7:0] LED + ); `include "conv.vh" // Clocking wire clk_100; - wire clk_15; assign clk_100 = aclk; - clk_gen clocking( + wire clk_15; + clkgen #( + .CLK_IN_HZ(100000000), + .CLKFX_DIVIDE(20), + .CLKFX_MULTIPLY(3) + ) clk_gen_15 ( .clk_in(clk_100), - .clk_out_15(clk_15) + .clk_out(clk_15) ); + // Reset conditioning for button input: // - asynchronous assert when button is pressed (aresetn=0) // - synchronous, debounced deassert in clk_15 domain @@ -51,7 +58,7 @@ module top_generic #( wire test; mcu #( - .memfile("../sw/sweep/sweep.hex"), + .memfile(memfile), .sim(sim), .jtag(1) ) mcu ( @@ -74,12 +81,12 @@ module top_generic #( .CLK_HZ(15_000_000), .FS_HZ(80_000) ) nco ( - .clk (clk_15), - .rst_n (sys_resetn), - .freq_hz(GPIO_A), - .sin_q15(sin_q15), - .cos_q15(), - .clk_en (clk_en) + .i_clk (clk_15), + .i_rst_n (sys_resetn), + .i_freq_hz(GPIO_A), + .o_sin_q15(sin_q15), + .o_cos_q15(), + .o_clk_en (clk_en) ); reg [5:0] dac_code; @@ -91,4 +98,6 @@ module top_generic #( assign LED = GPIO_B[7:0]; assign led_green = GPIO_C[0]; assign led_red = GPIO_C[1]; + + endmodule diff --git a/sw/.gitignore b/cores/system/test/sw/.gitignore similarity index 100% rename from sw/.gitignore rename to cores/system/test/sw/.gitignore diff --git a/sw/sweep/Makefile b/cores/system/test/sw/sweep/Makefile similarity index 79% rename from sw/sweep/Makefile rename to cores/system/test/sw/sweep/Makefile index a44b794..5e1cd7d 100644 --- a/sw/sweep/Makefile +++ b/cores/system/test/sw/sweep/Makefile @@ -15,12 +15,9 @@ CFLAGS := $(ARCH_FLAGS) -Os -ffreestanding -fno-builtin -Wall -Wextra ASFLAGS := $(ARCH_FLAGS) LDFLAGS := $(ARCH_FLAGS) -nostdlib -nostartfiles -Wl,-Bstatic,-Tlink.ld,--gc-sections,-Map,$(TARGET).map -HEX_TO_COE := ../../scripts/hex_to_coe.py -HEX_TO_MIF := ../../scripts/hex_to_mif.py - .PHONY: all clean disasm size -all: $(TARGET).elf $(TARGET).bin $(TARGET).hex $(TARGET).coe $(TARGET).mif $(TARGET).elf.asm +all: $(TARGET).elf $(TARGET).bin $(TARGET).hex $(TARGET).elf.asm $(TARGET).elf: $(OBJS) link.ld $(CC) $(LDFLAGS) -o $@ $(OBJS) @@ -37,12 +34,6 @@ $(TARGET).bin: $(TARGET).elf $(TARGET).hex: $(TARGET).bin hexdump -v -e '1/4 "%08x\n"' $< > $@ -$(TARGET).coe: $(TARGET).hex - $(HEX_TO_COE) $< $@ - -$(TARGET).mif: $(TARGET).hex - $(HEX_TO_MIF) $< $@ - $(TARGET).elf.asm: $(TARGET).elf $(OBJDUMP) -d -S $< > $@ diff --git a/sw/sweep/link.ld b/cores/system/test/sw/sweep/link.ld similarity index 100% rename from sw/sweep/link.ld rename to cores/system/test/sw/sweep/link.ld diff --git a/sw/sweep/start.s b/cores/system/test/sw/sweep/start.s similarity index 100% rename from sw/sweep/start.s rename to cores/system/test/sw/sweep/start.s diff --git a/sw/sweep/sweep.c b/cores/system/test/sw/sweep/sweep.c similarity index 66% rename from sw/sweep/sweep.c rename to cores/system/test/sw/sweep/sweep.c index 27de2da..447ba27 100644 --- a/sw/sweep/sweep.c +++ b/cores/system/test/sw/sweep/sweep.c @@ -6,7 +6,9 @@ static volatile uint32_t * const LEDS = (volatile uint32_t *)(GPIO_BASE+4) static volatile uint32_t * const LEDGR = (volatile uint32_t *)(GPIO_BASE+8); #define TIMER_BASE 0x40010000u -static volatile uint32_t * const TIMER = (volatile uint32_t *)(TIMER_BASE+0); +static volatile uint32_t * const TIMER_CNT = (volatile uint32_t *)(TIMER_BASE+0); +static volatile uint32_t * const TIMER_LD = (volatile uint32_t *)(TIMER_BASE+4); +static volatile uint32_t * const TIMER_ACK = (volatile uint32_t *)(TIMER_BASE+8); #define MSTATUS_MIE (1u << 3) #define MIE_MTIE (1u << 7) @@ -25,21 +27,21 @@ static inline void irq_init() { } void timer_isr(){ - static int set = 0; - *TIMER = 1840000*2; + *TIMER_ACK = 1; *LEDGR = ~(*LEDGR); } void main(){ irq_init(); - *LEDGR = 3; - *TIMER = 1840000*2; + *LEDGR = 1; + *TIMER_LD = 2 * 15000000/1000; for(;;){ - for(int i=1000; i<10000; i++){ + for(int i=1000; i<10000; i+=10){ *R_FREQ = i; - for(int j=0; j<80; j++) asm volatile("nop"); + *LEDS = i>>4; + // for(int j=0; j<80; j++) asm volatile("nop"); } } } \ No newline at end of file diff --git a/cores/system/test/tb/tb_toplevel.v b/cores/system/test/tb/tb_toplevel.v new file mode 100644 index 0000000..0be568b --- /dev/null +++ b/cores/system/test/tb/tb_toplevel.v @@ -0,0 +1,37 @@ +`timescale 1ns/1ps + +module tb_toplevel; + reg aclk; + reg aresetn; + wire led_green; + wire led_red; + wire [5:0] r2r; + wire [7:0] LED; + + toplevel #( + .sim(1) + ) dut ( + .aclk(aclk), + .aresetn(aresetn), + .led_green(led_green), + .led_red(led_red), + .r2r(r2r), + .LED(LED) + ); + + initial aclk = 1'b0; + always #33.33 aclk = ~aclk; + + initial begin + $dumpfile("toplevel.vcd"); + $dumpvars(1, tb_toplevel); + + aresetn = 1'b0; + #100; + aresetn = 1'b1; + + #10_000_000; + + $finish; + end +endmodule diff --git a/cores/system/test/test.core b/cores/system/test/test.core new file mode 100644 index 0000000..31c1f11 --- /dev/null +++ b/cores/system/test/test.core @@ -0,0 +1,64 @@ +CAPI=2: + +name: joppeb:system:test:1.0 +description: Example top-level + +filesets: + rtl: + depend: + - joppeb:primitive:clkgen + - joppeb:system:mcu + - joppeb:signal:nco_q15 + - joppeb:util:conv + files: + - rtl/toplevel.v + file_type: verilogSource + tb: + files: + - tb/tb_toplevel.v + file_type: verilogSource + + sw: + files: + - sw/sweep/sweep.hex : {copyto : sweep.hex} + file_type: user + + mimas: + files: + - mimas.ucf : {file_type : UCF} + - options.tcl : {file_type : tclSource} + +targets: + default: + filesets: + - rtl + toplevel: toplevel + sim: + default_tool: icarus + filesets: + - rtl + - sw + - tb + toplevel: tb_toplevel + + mimas: + filesets: + - rtl + - mimas + - sw + toplevel: toplevel + parameters: + - FPGA_SPARTAN6=true + default_tool: ise + tools: + ise: + family: Spartan6 + device: xc6slx9 + package: tqg144 + speed: -2 + +parameters: + FPGA_SPARTAN6: + datatype: bool + description: Select Spartan-6 family specific implementations + paramtype: vlogdefine diff --git a/cores/util/cdc/cdc.core b/cores/util/cdc/cdc.core new file mode 100644 index 0000000..adbeb2e --- /dev/null +++ b/cores/util/cdc/cdc.core @@ -0,0 +1,16 @@ +CAPI=2: + +name: joppeb:util:cdc:1.0 +description: Clock-domain crossing helpers + +filesets: + rtl: + files: + - rtl/cdc_strobe_data.v + - rtl/cdc_req_resp.v + file_type: verilogSource + +targets: + default: + filesets: + - rtl diff --git a/rtl/core/cdc_req_resp.v b/cores/util/cdc/rtl/cdc_req_resp.v similarity index 99% rename from rtl/core/cdc_req_resp.v rename to cores/util/cdc/rtl/cdc_req_resp.v index ebfd2c2..0a7d826 100644 --- a/rtl/core/cdc_req_resp.v +++ b/cores/util/cdc/rtl/cdc_req_resp.v @@ -67,4 +67,4 @@ module cdc_req_resp #( .d_data(a_resp_data) ); -endmodule \ No newline at end of file +endmodule diff --git a/rtl/core/cdc_strobe_data.v b/cores/util/cdc/rtl/cdc_strobe_data.v similarity index 100% rename from rtl/core/cdc_strobe_data.v rename to cores/util/cdc/rtl/cdc_strobe_data.v diff --git a/cores/util/clog2/clog2.core b/cores/util/clog2/clog2.core new file mode 100644 index 0000000..3f6f0c2 --- /dev/null +++ b/cores/util/clog2/clog2.core @@ -0,0 +1,16 @@ +CAPI=2: + +name: joppeb:util:clog2:1.0 +description: Verilog-2001 compatible ceil(log2(x)) macro header + +filesets: + include: + files: + - clog2.vh: + is_include_file: true + file_type: verilogSource + +targets: + default: + filesets: + - include diff --git a/rtl/util/clog2.vh b/cores/util/clog2/clog2.vh similarity index 97% rename from rtl/util/clog2.vh rename to cores/util/clog2/clog2.vh index 0aad108..a273f14 100644 --- a/rtl/util/clog2.vh +++ b/cores/util/clog2/clog2.vh @@ -2,6 +2,7 @@ `define CLOG2_VH // Verilog-2001 compatible ceil(log2(x)) macro (matches $clog2 semantics). +`ifndef CLOG2 `define CLOG2(x) \ (((x) <= 1) ? 0 : \ ((x) <= 2) ? 1 : \ @@ -37,3 +38,4 @@ ((x) <= 2147483648) ? 31 : 32) `endif +`endif diff --git a/cores/util/conv/conv.core b/cores/util/conv/conv.core new file mode 100644 index 0000000..fcbaf68 --- /dev/null +++ b/cores/util/conv/conv.core @@ -0,0 +1,16 @@ +CAPI=2: + +name: joppeb:util:conv:1.0 +description: Verilog conversion helper header + +filesets: + include: + files: + - conv.vh: + is_include_file: true + file_type: verilogSource + +targets: + default: + filesets: + - include diff --git a/rtl/util/conv.vh b/cores/util/conv/conv.vh similarity index 100% rename from rtl/util/conv.vh rename to cores/util/conv/conv.vh diff --git a/cores/util/mul_const/mul_const.core b/cores/util/mul_const/mul_const.core new file mode 100644 index 0000000..4602beb --- /dev/null +++ b/cores/util/mul_const/mul_const.core @@ -0,0 +1,15 @@ +CAPI=2: + +name: joppeb:util:mul_const:1.0 +description: Constant multiplier helpers implemented with shift-add logic + +filesets: + rtl: + files: + - rtl/mul_const.v + file_type: verilogSource + +targets: + default: + filesets: + - rtl diff --git a/cores/util/mul_const/rtl/mul_const.v b/cores/util/mul_const/rtl/mul_const.v new file mode 100644 index 0000000..481e9b0 --- /dev/null +++ b/cores/util/mul_const/rtl/mul_const.v @@ -0,0 +1,31 @@ +`timescale 1ns/1ps + +module mul_const_shiftadd #( + parameter integer C = 0, + parameter integer IN_W = 16, + parameter integer OUT_W = 32 +)( + input wire signed [IN_W-1:0] i_x, + output reg signed [OUT_W-1:0] o_y +); + integer k; + integer abs_c; + reg signed [OUT_W-1:0] acc; + reg signed [OUT_W-1:0] x_ext; + + always @* begin + abs_c = (C < 0) ? -C : C; + acc = {OUT_W{1'b0}}; + x_ext = {{(OUT_W-IN_W){i_x[IN_W-1]}}, i_x}; + + for (k = 0; k < 32; k = k + 1) begin + if (abs_c[k]) + acc = acc + (x_ext <<< k); + end + + if (C < 0) + o_y = -acc; + else + o_y = acc; + end +endmodule diff --git a/cores/wb/formal_checker/formal/formal_wb_master_checker.v b/cores/wb/formal_checker/formal/formal_wb_master_checker.v new file mode 100644 index 0000000..86ad833 --- /dev/null +++ b/cores/wb/formal_checker/formal/formal_wb_master_checker.v @@ -0,0 +1,205 @@ +// formal_wb_master_checker.v +// +// Wishbone Classic master-side protocol checker (plain Verilog). +// Use when your DUT is a *master* and the bus/slave is the environment. + +module formal_wb_master_checker #( + parameter OPT_USE_ERR = 0, + parameter OPT_USE_RTY = 0, + + // If 1: require responses only when STB=1 (stricter than spec permission). + // If 0: allow "ghost" responses with STB=0; we only COUNT termination when STB=1. + parameter OPT_STRICT_RESP_WITH_STB = 0, + + // If 1: require ACK/ERR/RTY to be single-cycle pulses. + // If 0: allow them to be held. + parameter OPT_PULSE_RESP = 1, + + // If 1: after a synchronous reset has been asserted for one clock, + // require the master to hold CYC/STB low. + parameter OPT_STRICT_RESET = 1, + + // Optional widths + parameter AW = 32, + parameter DW = 32, + parameter SW = 4 +) ( + input wire i_clk, + input wire i_rst, + input wire i_wb_rst, + + // Master -> bus + input wire i_wb_cyc, + input wire i_wb_stb, + input wire i_wb_we, + input wire [AW-1:0] i_wb_adr, + input wire [DW-1:0] i_wb_dat, + input wire [SW-1:0] i_wb_sel, + + // Bus/slave -> master + input wire o_wb_ack, + input wire o_wb_err, + input wire o_wb_rty, + input wire [DW-1:0] o_wb_rdt +); + +`ifdef FORMAL + // ----------------------------- + // Reset combine + // ----------------------------- + wire rst_any; + assign rst_any = i_rst | i_wb_rst; + + // ----------------------------- + // Formal infrastructure + // ----------------------------- + reg f_past_valid; + initial f_past_valid = 1'b0; + always @(posedge i_clk) + f_past_valid <= 1'b1; + + wire f_resp_any; + assign f_resp_any = o_wb_ack + | (OPT_USE_ERR ? o_wb_err : 1'b0) + | (OPT_USE_RTY ? o_wb_rty : 1'b0); + + // A "real" termination in Classic requires STB high (handshake qualifies the transfer) + wire f_terminate; + assign f_terminate = i_wb_cyc && i_wb_stb && f_resp_any; + + // ----------------------------- + // Track exactly one outstanding request (Classic) + // ----------------------------- + reg f_pending; + initial f_pending = 1'b0; + + always @(posedge i_clk or posedge rst_any) begin + if (rst_any) begin + f_pending <= 1'b0; + end else if (!i_wb_cyc) begin + // Dropping CYC ends the bus cycle and clears any outstanding request + f_pending <= 1'b0; + end else begin + // Start pending when STB is asserted and none is pending + if (!f_pending && i_wb_stb) + f_pending <= 1'b1; + + // Clear pending only on a real termination (STB && response) + if (f_terminate) + f_pending <= 1'b0; + end + end + + // ----------------------------- + // Reset rules (Wishbone synchronous reset semantics) + // ----------------------------- + always @(posedge i_clk) if (f_past_valid) begin + if (rst_any) begin + // R00: Monitor pending state must be cleared during reset + R00: assert(f_pending == 1'b0); + + if (OPT_STRICT_RESET && $past(rst_any)) begin + // R01: After reset was asserted on the prior clock, master must be idle + R01: assert(!i_wb_cyc); + // R02: After reset was asserted on the prior clock, master must not strobe + R02: assert(!i_wb_stb); + end + + if ($past(rst_any)) begin + // A00: After reset was asserted on the prior clock, environment should not respond + A00: assume(!o_wb_ack); + if (OPT_USE_ERR) A01: assume(!o_wb_err); + if (OPT_USE_RTY) A02: assume(!o_wb_rty); + end + end + end + + // ----------------------------- + // Master-side RULES (ASSERTIONS) + // ----------------------------- + always @(posedge i_clk) if (f_past_valid && !rst_any) begin + // R10: STB must imply CYC (no strobe outside of a cycle) + if (i_wb_stb) begin + R10: assert(i_wb_cyc); + end + + // R11: While a request is pending and NOT terminated, master must keep CYC asserted + if ($past(f_pending) && !$past(f_terminate)) begin + R11: assert(i_wb_cyc); + end + + // R12: While a request is pending and NOT terminated, master must keep STB asserted + if ($past(f_pending) && !$past(f_terminate)) begin + R12: assert(i_wb_stb); + end + + // R13: Address stable while pending and not terminated + if ($past(f_pending) && !$past(f_terminate)) begin + R13: assert(i_wb_adr == $past(i_wb_adr)); + end + + // R14: WE stable while pending and not terminated + if ($past(f_pending) && !$past(f_terminate)) begin + R14: assert(i_wb_we == $past(i_wb_we)); + end + + // R15: SEL stable while pending and not terminated + if ($past(f_pending) && !$past(f_terminate)) begin + R15: assert(i_wb_sel == $past(i_wb_sel)); + end + + // R16: Write data stable while pending and not terminated + if ($past(f_pending) && !$past(f_terminate)) begin + R16: assert(i_wb_dat == $past(i_wb_dat)); + end + end + + // ----------------------------- + // Environment SLAVE assumptions + // ----------------------------- + always @(posedge i_clk) if (f_past_valid && !rst_any) begin + // A10: Any response must occur only during an active cycle + if (f_resp_any) begin + A10: assume(i_wb_cyc); + end + + // A11: Optional strict profile: response only when STB=1 + if (OPT_STRICT_RESP_WITH_STB && f_resp_any) begin + A11: assume(i_wb_stb); + end + + // A12-A14: Mutual exclusion between ACK/ERR/RTY (recommended) + if (o_wb_ack) begin + if (OPT_USE_ERR) A12s1: assume(!o_wb_err); + if (OPT_USE_RTY) A12s2: assume(!o_wb_rty); + end + if (OPT_USE_ERR && o_wb_err) begin + A13s1: assume(!o_wb_ack); + if (OPT_USE_RTY) A13s2: assume(!o_wb_rty); + end + if (OPT_USE_RTY && o_wb_rty) begin + A14s1: assume(!o_wb_ack); + if (OPT_USE_ERR) A14s2: assume(!o_wb_err); + end + + // A15-A17: Optional pulse-only responses + if (OPT_PULSE_RESP) begin + if ($past(o_wb_ack)) begin + A15: assume(!o_wb_ack); + end + if (OPT_USE_ERR && $past(o_wb_err)) begin + A16: assume(!o_wb_err); + end + if (OPT_USE_RTY && $past(o_wb_rty)) begin + A17: assume(!o_wb_rty); + end + end + end + + // ----------------------------- + // Coverage: explore protocol space ("state diagram" witnesses) + // ----------------------------- + // TODO + +`endif +endmodule diff --git a/cores/wb/formal_checker/formal/formal_wb_slave_checker.v b/cores/wb/formal_checker/formal/formal_wb_slave_checker.v new file mode 100644 index 0000000..b277482 --- /dev/null +++ b/cores/wb/formal_checker/formal/formal_wb_slave_checker.v @@ -0,0 +1,222 @@ +// formal_wb_slave_checker.v +// +// Wishbone Classic slave-side protocol checker (plain Verilog). +// Use when your DUT is a *slave* and the bus/master is the environment. + +module formal_wb_slave_checker #( + parameter OPT_USE_ERR = 0, + parameter OPT_USE_RTY = 0, + + // If 1: require slave to only assert responses when STB=1 (stricter profile). + // If 0: allow "ghost" responses with STB=0; termination still only counts when STB=1. + parameter OPT_STRICT_RESP_WITH_STB = 0, + + // If 1: require termination signals to be pulses (1 cycle). + // If 0: allow them to be held. + parameter OPT_PULSE_RESP = 1, + + // If 1: after a synchronous reset has been asserted for one clock, + // require the master to hold CYC/STB low. + parameter OPT_STRICT_RESET = 1, + + // If 1: assert read data stable while ACK is held (useful if you allow ACK-hold). + parameter OPT_ASSERT_RDATA_STABLE_DURING_ACK = 1, + + // Optional widths + parameter AW = 32, + parameter DW = 32, + parameter SW = 4 +) ( + input wire i_clk, + input wire i_rst, + input wire i_wb_rst, + + // Master -> slave + input wire i_wb_cyc, + input wire i_wb_stb, + input wire i_wb_we, + input wire [AW-1:0] i_wb_adr, + input wire [DW-1:0] i_wb_dat, + input wire [SW-1:0] i_wb_sel, + + // Slave -> master + input wire o_wb_ack, + input wire o_wb_err, + input wire o_wb_rty, + input wire [DW-1:0] o_wb_rdt +); + +`ifdef FORMAL + // ----------------------------- + // Reset combine + // ----------------------------- + wire rst_any; + assign rst_any = i_rst | i_wb_rst; + + // ----------------------------- + // Formal infrastructure + // ----------------------------- + reg f_past_valid; + initial f_past_valid = 1'b0; + always @(posedge i_clk) + f_past_valid <= 1'b1; + + wire f_resp_any; + assign f_resp_any = o_wb_ack + | (OPT_USE_ERR ? o_wb_err : 1'b0) + | (OPT_USE_RTY ? o_wb_rty : 1'b0); + + // Real termination only counts when STB=1 + wire f_terminate; + assign f_terminate = i_wb_cyc && i_wb_stb && f_resp_any; + + // ----------------------------- + // Outstanding request tracking (Classic) + // ----------------------------- + reg f_pending; + initial f_pending = 1'b0; + + always @(posedge i_clk or posedge rst_any) begin + if (rst_any) begin + f_pending <= 1'b0; + end else if (!i_wb_cyc) begin + f_pending <= 1'b0; + end else begin + if (!f_pending && i_wb_stb) + f_pending <= 1'b1; + + if (f_terminate) + f_pending <= 1'b0; + end + end + + // ----------------------------- + // Reset rules (Wishbone synchronous reset semantics) + // ----------------------------- + always @(posedge i_clk) if (f_past_valid) begin + if (rst_any) begin + // R00: Monitor pending state must be cleared during reset + R00: assert(f_pending == 1'b0); + + if (OPT_STRICT_RESET && $past(rst_any)) begin + // A00: After reset was asserted on the prior clock, assume master is idle + A00: assume(!i_wb_cyc); + // A01: After reset was asserted on the prior clock, assume master is not strobing + A01: assume(!i_wb_stb); + end + + if ($past(rst_any)) begin + // R01: After reset was asserted on the prior clock, slave must not respond + R01: assert(!o_wb_ack); + if (OPT_USE_ERR) R02: assert(!o_wb_err); + if (OPT_USE_RTY) R03: assert(!o_wb_rty); + end + end + end + + // ----------------------------- + // Master/environment assumptions (Classic rules) + // ----------------------------- + always @(posedge i_clk) if (f_past_valid && !rst_any) begin + // A10: STB must imply CYC + if (i_wb_stb) begin + A10: assume(i_wb_cyc); + end + + // A11: While pending and not terminated, master holds CYC asserted + if ($past(f_pending) && !$past(f_terminate)) begin + A11: assume(i_wb_cyc); + end + + // A12: While pending and not terminated, master holds STB asserted + if ($past(f_pending) && !$past(f_terminate)) begin + A12: assume(i_wb_stb); + end + + // A13: Address stable while pending and not terminated + if ($past(f_pending) && !$past(f_terminate)) begin + A13: assume(i_wb_adr == $past(i_wb_adr)); + end + + // A14: WE stable while pending and not terminated + if ($past(f_pending) && !$past(f_terminate)) begin + A14: assume(i_wb_we == $past(i_wb_we)); + end + + // A15: SEL stable while pending and not terminated + if ($past(f_pending) && !$past(f_terminate)) begin + A15: assume(i_wb_sel == $past(i_wb_sel)); + end + + // A16: Write data stable while pending and not terminated + if ($past(f_pending) && !$past(f_terminate)) begin + A16: assume(i_wb_dat == $past(i_wb_dat)); + end + end + + // ----------------------------- + // Slave/DUT assertions (response sanity) + // ----------------------------- + always @(posedge i_clk) if (f_past_valid && !rst_any) begin + // R10: Any response must occur only during an active cycle + if (f_resp_any) begin + R10: assert(i_wb_cyc); + end + + // R11: Optional strict profile: response only when STB=1 + if (OPT_STRICT_RESP_WITH_STB && f_resp_any) begin + R11: assert(i_wb_stb); + end + + // R12-R14: Mutual exclusion of termination signals (recommended) + if (o_wb_ack) begin + if (OPT_USE_ERR) R12s1: assert(!o_wb_err); + if (OPT_USE_RTY) R12s2: assert(!o_wb_rty); + end + if (OPT_USE_ERR && o_wb_err) begin + R13s1: assert(!o_wb_ack); + if (OPT_USE_RTY) R13s2: assert(!o_wb_rty); + end + if (OPT_USE_RTY && o_wb_rty) begin + R14s1: assert(!o_wb_ack); + if (OPT_USE_ERR) R14s2: assert(!o_wb_err); + end + + // R15-R17: Optional pulse-only responses + if (OPT_PULSE_RESP) begin + if ($past(o_wb_ack)) begin + R15: assert(!o_wb_ack); + end + if (OPT_USE_ERR && $past(o_wb_err)) begin + R16: assert(!o_wb_err); + end + if (OPT_USE_RTY && $past(o_wb_rty)) begin + R17: assert(!o_wb_rty); + end + end + + // R18: A real termination (STB && response) should only happen when a request is pending. + if (i_wb_stb && f_resp_any) begin + R18: assert(f_pending || $past(f_pending)); + end + + // R19: Optional read-data stability while ACK is held (only relevant if ACK can be held) + if (OPT_ASSERT_RDATA_STABLE_DURING_ACK) begin + if (o_wb_ack && !i_wb_we && $past(o_wb_ack)) begin + R19: assert(o_wb_rdt == $past(o_wb_rdt)); + end + end + + // R20: If no cycle, no responses (strong sanity rule) + if (!i_wb_cyc) begin + R20: assert(!f_resp_any); + end + end + + // ----------------------------- + // Coverage: exercise the slave (useful witness traces) + // ----------------------------- + // TODO + +`endif +endmodule diff --git a/cores/wb/formal_checker/formal_checker.core b/cores/wb/formal_checker/formal_checker.core new file mode 100644 index 0000000..3da7e5d --- /dev/null +++ b/cores/wb/formal_checker/formal_checker.core @@ -0,0 +1,16 @@ +CAPI=2: + +name: joppeb:wb:formal_checker:1.0 +description: Reusable formal Wishbone protocol checkers + +filesets: + formal_rtl: + files: + - formal/formal_wb_slave_checker.v + - formal/formal_wb_master_checker.v + file_type: verilogSource + +targets: + default: + filesets: + - formal_rtl diff --git a/cores/wb/jtag_wb_bridge/formal/formal_jtag_wb_bridge.v b/cores/wb/jtag_wb_bridge/formal/formal_jtag_wb_bridge.v new file mode 100644 index 0000000..e43ea7b --- /dev/null +++ b/cores/wb/jtag_wb_bridge/formal/formal_jtag_wb_bridge.v @@ -0,0 +1,63 @@ +`timescale 1ns/1ps + +module formal_jtag_wb_bridge; + (* gclk *) reg i_clk; + (* anyseq *) reg i_rst; + (* anyseq *) reg [31:0] i_wb_rdt; + (* anyseq *) reg i_wb_ack; + reg f_past_valid; + + wire [31:0] o_wb_adr; + wire [31:0] o_wb_dat; + wire [3:0] o_wb_sel; + wire o_wb_we; + wire o_wb_cyc; + wire o_wb_stb; + wire o_cmd_reset; + + // This bridge has no dedicated Wishbone reset output. + wire f_wb_rst = 1'b0; + + jtag_wb_bridge #( + .chain(1), + .byte_aligned(0) + ) dut ( + .i_clk(i_clk), + .i_rst(i_rst), + .o_wb_adr(o_wb_adr), + .o_wb_dat(o_wb_dat), + .o_wb_sel(o_wb_sel), + .o_wb_we(o_wb_we), + .o_wb_cyc(o_wb_cyc), + .o_wb_stb(o_wb_stb), + .i_wb_rdt(i_wb_rdt), + .i_wb_ack(i_wb_ack), + .o_cmd_reset(o_cmd_reset) + ); + + formal_wb_master_checker wb_checker ( + .i_clk(i_clk), + .i_rst(i_rst), + .i_wb_rst(f_wb_rst), + .i_wb_adr(o_wb_adr), + .i_wb_dat(o_wb_dat), + .i_wb_sel(o_wb_sel), + .i_wb_we(o_wb_we), + .i_wb_stb(o_wb_stb), + .i_wb_cyc(o_wb_cyc), + .o_wb_rdt(i_wb_rdt), + .o_wb_ack(i_wb_ack) + ); + + initial f_past_valid = 1'b0; + + always @(posedge i_clk) begin + f_past_valid <= 1'b1; + + // A1: Start in reset so the bridge state is initialized + if (!f_past_valid) + assume(i_rst); + end + + wire unused = &{1'b0, o_cmd_reset}; +endmodule diff --git a/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge.sby b/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge.sby new file mode 100644 index 0000000..75c2d00 --- /dev/null +++ b/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge.sby @@ -0,0 +1,24 @@ +[tasks] +prove +cover +bmc + +[options] +bmc: mode bmc +bmc: depth 16 +cover: mode cover +cover: depth 16 +prove: mode prove + +[engines] +bmc: smtbmc yices +cover: smtbmc yices +prove: abc pdr + +[script] +{{"-formal"|gen_reads}} +prep -top {{top_level}} +clk2fflogic + +[files] +{{files}} diff --git a/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge_prove/config.sby b/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge_prove/config.sby new file mode 100644 index 0000000..29b2876 --- /dev/null +++ b/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge_prove/config.sby @@ -0,0 +1,13 @@ +[options] +mode prove + +[engines] +abc pdr + +[script] +{{"-formal"|gen_reads}} +prep -top {{top_level}} +clk2fflogic + +[files] +{{files}} diff --git a/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge_prove/logfile.txt b/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge_prove/logfile.txt new file mode 100644 index 0000000..2c0f76b --- /dev/null +++ b/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge_prove/logfile.txt @@ -0,0 +1,2 @@ +SBY 17:52:48 [/data/joppe/projects/fusesoc_test/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge_prove] Removing directory '/data/joppe/projects/fusesoc_test/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge_prove'. +SBY 17:52:48 [/data/joppe/projects/fusesoc_test/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge_prove] Copy '/data/joppe/projects/fusesoc_test/cores/wb/jtag_wb_bridge/formal/{{files}}' to '/data/joppe/projects/fusesoc_test/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge_prove/src/{{files}}'. diff --git a/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge_prove/status.path b/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge_prove/status.path new file mode 100644 index 0000000..9b60661 --- /dev/null +++ b/cores/wb/jtag_wb_bridge/formal/jtag_wb_bridge_prove/status.path @@ -0,0 +1 @@ +../jtag_wb_bridge/status.sqlite diff --git a/cores/wb/jtag_wb_bridge/formal/stub_cdc_req_resp.v b/cores/wb/jtag_wb_bridge/formal/stub_cdc_req_resp.v new file mode 100644 index 0000000..2ffae74 --- /dev/null +++ b/cores/wb/jtag_wb_bridge/formal/stub_cdc_req_resp.v @@ -0,0 +1,63 @@ +`timescale 1ns/1ps + +module cdc_req_resp #( + parameter integer REQ_W = 32, + parameter integer RESP_W = 32, + parameter integer STABLE_SAMPLES = 2 +)( + input wire a_clk, + input wire a_rst, + input wire a_req_pulse, + input wire [REQ_W-1:0] a_req_data, + output wire a_req_busy, + output wire a_req_accepted, + output wire a_resp_pulse, + output wire [RESP_W-1:0] a_resp_data, + input wire b_clk, + input wire b_rst, + output reg b_req_pulse, + output reg [REQ_W-1:0] b_req_data, + input wire b_resp_pulse, + input wire [RESP_W-1:0] b_resp_data, + output wire b_resp_busy, + output wire b_resp_accepted +); + (* anyseq *) reg f_req_pulse; + (* anyseq *) reg [REQ_W-1:0] f_req_data; + reg f_past_valid; + + assign a_req_busy = 1'b0; + assign a_req_accepted = 1'b0; + assign a_resp_pulse = 1'b0; + assign a_resp_data = {RESP_W{1'b0}}; + assign b_resp_busy = 1'b0; + assign b_resp_accepted = 1'b0; + + initial f_past_valid = 1'b0; + + always @(posedge b_clk) begin + f_past_valid <= 1'b1; + + b_req_pulse <= f_req_pulse; + b_req_data <= f_req_data; + + // A1: no abstract request while system reset is asserted + if (b_rst) + assume(!f_req_pulse); + + // A2: abstract requests are single-cycle pulses + if (f_past_valid && $past(f_req_pulse)) + assume(!f_req_pulse); + end + + wire unused = &{ + 1'b0, + a_clk, + a_rst, + a_req_pulse, + a_req_data, + b_resp_pulse, + b_resp_data, + STABLE_SAMPLES[0] + }; +endmodule diff --git a/cores/wb/jtag_wb_bridge/formal/stub_jtag_if.v b/cores/wb/jtag_wb_bridge/formal/stub_jtag_if.v new file mode 100644 index 0000000..ee2f9a6 --- /dev/null +++ b/cores/wb/jtag_wb_bridge/formal/stub_jtag_if.v @@ -0,0 +1,28 @@ +`timescale 1ns/1ps + +module jtag_if #( + parameter chain = 1 +)( + input wire i_tdo, + output wire o_tck, + output wire o_tdi, + output wire o_drck, + output wire o_capture, + output wire o_shift, + output wire o_update, + output wire o_runtest, + output wire o_reset, + output wire o_sel +); + assign o_tck = 1'b0; + assign o_tdi = 1'b0; + assign o_drck = 1'b0; + assign o_capture = 1'b0; + assign o_shift = 1'b0; + assign o_update = 1'b0; + assign o_runtest = 1'b0; + assign o_reset = 1'b0; + assign o_sel = 1'b0; + + wire unused = &{1'b0, i_tdo, chain[0]}; +endmodule diff --git a/cores/wb/jtag_wb_bridge/jtag_wb_bridge.core b/cores/wb/jtag_wb_bridge/jtag_wb_bridge.core new file mode 100644 index 0000000..b0a9006 --- /dev/null +++ b/cores/wb/jtag_wb_bridge/jtag_wb_bridge.core @@ -0,0 +1,64 @@ +CAPI=2: + +name: joppeb:wb:jtag_wb_bridge:1.0 +description: Generic JTAG boundary scan to Wishbone classic bridge + +filesets: + rtl: + depend: + - joppeb:primitive:jtag_if + - joppeb:util:cdc + files: + - rtl/jtag_wb_bridge.v + file_type: verilogSource + formal_rtl: + depend: + - joppeb:wb:formal_checker + files: + - formal/formal_jtag_wb_bridge.v + file_type: verilogSource + formal_abstract_rtl: + depend: + - joppeb:wb:formal_checker + files: + - rtl/jtag_wb_bridge.v + - formal/stub_jtag_if.v + - formal/stub_cdc_req_resp.v + - formal/formal_jtag_wb_bridge.v + file_type: verilogSource + formal_cfg: + files: + - formal/jtag_wb_bridge.sby + file_type: sbyConfigTemplate + +targets: + default: + filesets: + - rtl + toplevel: jtag_wb_bridge + parameters: + - chain + - byte_aligned + formal: + default_tool: symbiyosys + filesets: + - rtl + - formal_rtl + - formal_cfg + toplevel: formal_jtag_wb_bridge + formal_abstract: + default_tool: symbiyosys + filesets: + - formal_abstract_rtl + - formal_cfg + toplevel: formal_jtag_wb_bridge + +parameters: + chain: + datatype: int + description: User chain + paramtype: vlogparam + byte_aligned: + datatype: int + description: use addr[1:0] for byte lane on 32-bit WB when 0, always use lane 0 when 1 + paramtype: vlogparam diff --git a/rtl/wb/jtag_wb_bridge.v b/cores/wb/jtag_wb_bridge/rtl/jtag_wb_bridge.v similarity index 99% rename from rtl/wb/jtag_wb_bridge.v rename to cores/wb/jtag_wb_bridge/rtl/jtag_wb_bridge.v index bfb9e9e..9cbe2bb 100644 --- a/rtl/wb/jtag_wb_bridge.v +++ b/cores/wb/jtag_wb_bridge/rtl/jtag_wb_bridge.v @@ -505,8 +505,8 @@ module jtag_wb_bridge #( // Mark active command complete act_valid <= 1'b0; - // If there is a queued command, promote and start it - if (q_valid) begin + // If there is a queued command and the WB port is idle, promote it now. + if (q_valid && !wb_busy) begin act_valid <= 1'b1; act_opcode <= q_opcode; act_addr <= q_addr; diff --git a/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/.gitignore b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/.gitignore new file mode 100644 index 0000000..e2ff95c --- /dev/null +++ b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/.gitignore @@ -0,0 +1,6 @@ +__pycache__/ +*.d +*.o +*.a +*.so +prog \ No newline at end of file diff --git a/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/Makefile b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/Makefile new file mode 100644 index 0000000..7e47956 --- /dev/null +++ b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/Makefile @@ -0,0 +1,43 @@ +TOOLCHAIN_PREFIX ?= + +CXX := $(TOOLCHAIN_PREFIX)g++ +AR := $(TOOLCHAIN_PREFIX)ar + +TARGET := prog +STATIC_LIB := libjtag_wb_bridge.a +SHARED_LIB := libjtag_wb_bridge.so + +ADEPT_LIBDIR := /opt/packages/digilent.adept.runtime_2.27.9-x86_64/lib64 + +CPPFLAGS := -MMD -MP +CXXFLAGS := -O2 -Wall -Wextra -std=c++17 -fPIC +LDFLAGS := -L$(ADEPT_LIBDIR) -Wl,--disable-new-dtags -Wl,-rpath,$(ADEPT_LIBDIR) +LIBS := -ldjtg -ldmgr -ldpcomm -ldabs -ldftd2xx + +LIB_SRCS := difilent_jtag.cpp jtag_wb_bridge_client.cpp jtag_wb_bridge_c.cpp +APP_SRCS := prog.cpp argparse.cpp + +LIB_OBJS := $(LIB_SRCS:.cpp=.o) +APP_OBJS := $(APP_SRCS:.cpp=.o) +DEPS := $(LIB_OBJS:.o=.d) $(APP_OBJS:.o=.d) + +.PHONY: all clean + +all: $(STATIC_LIB) $(SHARED_LIB) $(TARGET) + +$(STATIC_LIB): $(LIB_OBJS) + $(AR) rcs $@ $(LIB_OBJS) + +$(SHARED_LIB): $(LIB_OBJS) + $(CXX) -shared $(LDFLAGS) -o $@ $(LIB_OBJS) $(LIBS) + +$(TARGET): $(APP_OBJS) $(STATIC_LIB) + $(CXX) $(LDFLAGS) -o $@ $(APP_OBJS) -L. $(STATIC_LIB) $(LIBS) + +%.o: %.cpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< + +clean: + rm -f $(TARGET) $(STATIC_LIB) $(SHARED_LIB) $(LIB_OBJS) $(APP_OBJS) $(DEPS) + +-include $(DEPS) diff --git a/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/__init__.py b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tools/argparse.cpp b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/argparse.cpp similarity index 100% rename from tools/argparse.cpp rename to cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/argparse.cpp diff --git a/tools/argparse.hpp b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/argparse.hpp similarity index 100% rename from tools/argparse.hpp rename to cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/argparse.hpp diff --git a/tools/digilent_jtag.cpp b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/difilent_jtag.cpp similarity index 100% rename from tools/digilent_jtag.cpp rename to cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/difilent_jtag.cpp diff --git a/tools/digilent_jtag.hpp b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/digilent_jtag.hpp similarity index 100% rename from tools/digilent_jtag.hpp rename to cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/digilent_jtag.hpp diff --git a/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_bridge.py b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_bridge.py new file mode 100644 index 0000000..90fc03a --- /dev/null +++ b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_bridge.py @@ -0,0 +1,146 @@ +import ctypes +import os +from pathlib import Path + + +def _load_library(path=None): + if path is None: + env_path = os.environ.get("JTAG_BRIDGE_LIB") + if env_path: + path = env_path + else: + path = Path(__file__).with_name("libjtag_wb_bridge.so") + return ctypes.CDLL(str(path)) + + +class JtagBridgeError(RuntimeError): + pass + + +class JtagBridge: + def __init__(self, library_path=None): + self._handle = None + self._lib = _load_library(library_path) + self._configure() + self._handle = self._lib.jtag_bridge_create() + if not self._handle: + raise JtagBridgeError("failed to allocate bridge handle") + + def _configure(self): + self._lib.jtag_bridge_create.restype = ctypes.c_void_p + self._lib.jtag_bridge_destroy.argtypes = [ctypes.c_void_p] + self._lib.jtag_bridge_open.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] + self._lib.jtag_bridge_open.restype = ctypes.c_int + self._lib.jtag_bridge_open_selector.argtypes = [ + ctypes.c_void_p, + ctypes.c_char_p, + ctypes.c_int, + ctypes.c_int, + ] + self._lib.jtag_bridge_open_selector.restype = ctypes.c_int + self._lib.jtag_bridge_close.argtypes = [ctypes.c_void_p] + self._lib.jtag_bridge_set_speed.argtypes = [ + ctypes.c_void_p, + ctypes.c_uint32, + ctypes.POINTER(ctypes.c_uint32), + ] + self._lib.jtag_bridge_set_speed.restype = ctypes.c_int + self._lib.jtag_bridge_set_chain.argtypes = [ctypes.c_void_p, ctypes.c_int] + self._lib.jtag_bridge_set_chain.restype = ctypes.c_int + self._lib.jtag_bridge_clear_flags.argtypes = [ctypes.c_void_p] + self._lib.jtag_bridge_clear_flags.restype = ctypes.c_int + self._lib.jtag_bridge_ping.argtypes = [ctypes.c_void_p] + self._lib.jtag_bridge_ping.restype = ctypes.c_int + self._lib.jtag_bridge_set_reset.argtypes = [ctypes.c_void_p, ctypes.c_int] + self._lib.jtag_bridge_set_reset.restype = ctypes.c_int + self._lib.jtag_bridge_write8.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.c_uint8] + self._lib.jtag_bridge_write8.restype = ctypes.c_int + self._lib.jtag_bridge_read8.argtypes = [ + ctypes.c_void_p, + ctypes.c_uint32, + ctypes.POINTER(ctypes.c_uint8), + ] + self._lib.jtag_bridge_read8.restype = ctypes.c_int + self._lib.jtag_bridge_write32.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.c_uint32] + self._lib.jtag_bridge_write32.restype = ctypes.c_int + self._lib.jtag_bridge_read32.argtypes = [ + ctypes.c_void_p, + ctypes.c_uint32, + ctypes.POINTER(ctypes.c_uint32), + ] + self._lib.jtag_bridge_read32.restype = ctypes.c_int + self._lib.jtag_bridge_last_error.argtypes = [ctypes.c_void_p] + self._lib.jtag_bridge_last_error.restype = ctypes.c_char_p + + def close(self): + if self._handle: + self._lib.jtag_bridge_close(self._handle) + + def destroy(self): + if self._handle: + self._lib.jtag_bridge_destroy(self._handle) + self._handle = None + + def __del__(self): + self.destroy() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc, tb): + self.destroy() + return False + + def _check(self, ok): + if not ok: + message = self._lib.jtag_bridge_last_error(self._handle) + if not message: + raise JtagBridgeError("operation failed") + decoded = message.decode("utf-8", errors="replace") + if not decoded: + decoded = "operation failed" + raise JtagBridgeError(decoded) + + def open(self, port=0, chain=1): + self._check(self._lib.jtag_bridge_open(self._handle, port, chain)) + + def open_selector(self, selector, port=0, chain=1): + self._check( + self._lib.jtag_bridge_open_selector( + self._handle, selector.encode("utf-8"), port, chain + ) + ) + + def set_speed(self, requested_hz): + actual = ctypes.c_uint32() + self._check(self._lib.jtag_bridge_set_speed(self._handle, requested_hz, ctypes.byref(actual))) + return actual.value + + def set_chain(self, chain): + self._check(self._lib.jtag_bridge_set_chain(self._handle, chain)) + + def clear_flags(self): + self._check(self._lib.jtag_bridge_clear_flags(self._handle)) + + def ping(self): + self._check(self._lib.jtag_bridge_ping(self._handle)) + return True + + def set_reset(self, enabled): + self._check(self._lib.jtag_bridge_set_reset(self._handle, int(bool(enabled)))) + + def write8(self, addr, value): + self._check(self._lib.jtag_bridge_write8(self._handle, addr, value)) + + def read8(self, addr): + value = ctypes.c_uint8() + self._check(self._lib.jtag_bridge_read8(self._handle, addr, ctypes.byref(value))) + return value.value + + def write32(self, addr, value): + self._check(self._lib.jtag_bridge_write32(self._handle, addr, value)) + + def read32(self, addr): + value = ctypes.c_uint32() + self._check(self._lib.jtag_bridge_read32(self._handle, addr, ctypes.byref(value))) + return value.value diff --git a/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_wb_bridge_c.cpp b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_wb_bridge_c.cpp new file mode 100644 index 0000000..fd1a1ff --- /dev/null +++ b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_wb_bridge_c.cpp @@ -0,0 +1,113 @@ +#include "jtag_wb_bridge_c.h" + +#include "jtag_wb_bridge_client.hpp" + +#include + +struct JtagBridgeHandle { + JtagWishboneBridge bridge; +}; + +namespace { + +template +int callBridge(JtagBridgeHandle* handle, Fn&& fn) { + if (!handle) { + return 0; + } + return fn(handle->bridge) ? 1 : 0; +} + +} // namespace + +extern "C" { + +JtagBridgeHandle* jtag_bridge_create(void) { + return new (std::nothrow) JtagBridgeHandle(); +} + +void jtag_bridge_destroy(JtagBridgeHandle* handle) { + delete handle; +} + +int jtag_bridge_open(JtagBridgeHandle* handle, int port, int chain) { + return callBridge(handle, [port, chain](JtagWishboneBridge& bridge) { + return bridge.open(port, chain); + }); +} + +int jtag_bridge_open_selector(JtagBridgeHandle* handle, const char* selector, int port, int chain) { + if (!handle || !selector) { + return 0; + } + return handle->bridge.open(selector, port, chain) ? 1 : 0; +} + +void jtag_bridge_close(JtagBridgeHandle* handle) { + if (handle) { + handle->bridge.close(); + } +} + +int jtag_bridge_set_speed(JtagBridgeHandle* handle, uint32_t requested_hz, uint32_t* actual_hz) { + return callBridge(handle, [requested_hz, actual_hz](JtagWishboneBridge& bridge) { + return bridge.setSpeed(requested_hz, actual_hz); + }); +} + +int jtag_bridge_set_chain(JtagBridgeHandle* handle, int chain) { + return callBridge(handle, [chain](JtagWishboneBridge& bridge) { + return bridge.setChain(chain); + }); +} + +int jtag_bridge_clear_flags(JtagBridgeHandle* handle) { + return callBridge(handle, [](JtagWishboneBridge& bridge) { + return bridge.clearFlags(); + }); +} + +int jtag_bridge_ping(JtagBridgeHandle* handle) { + return callBridge(handle, [](JtagWishboneBridge& bridge) { + return bridge.ping(); + }); +} + +int jtag_bridge_set_reset(JtagBridgeHandle* handle, int enabled) { + return callBridge(handle, [enabled](JtagWishboneBridge& bridge) { + return bridge.setReset(enabled != 0); + }); +} + +int jtag_bridge_write8(JtagBridgeHandle* handle, uint32_t addr, uint8_t value) { + return callBridge(handle, [addr, value](JtagWishboneBridge& bridge) { + return bridge.write8(addr, value); + }); +} + +int jtag_bridge_read8(JtagBridgeHandle* handle, uint32_t addr, uint8_t* value) { + return callBridge(handle, [addr, value](JtagWishboneBridge& bridge) { + return bridge.read8(addr, value); + }); +} + +int jtag_bridge_write32(JtagBridgeHandle* handle, uint32_t addr, uint32_t value) { + return callBridge(handle, [addr, value](JtagWishboneBridge& bridge) { + return bridge.write32(addr, value); + }); +} + +int jtag_bridge_read32(JtagBridgeHandle* handle, uint32_t addr, uint32_t* value) { + return callBridge(handle, [addr, value](JtagWishboneBridge& bridge) { + return bridge.read32(addr, value); + }); +} + +const char* jtag_bridge_last_error(const JtagBridgeHandle* handle) { + if (!handle) { + return "invalid bridge handle"; + } + return handle->bridge.lastError().c_str(); +} + +} // extern "C" diff --git a/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_wb_bridge_c.h b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_wb_bridge_c.h new file mode 100644 index 0000000..e4f89d7 --- /dev/null +++ b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_wb_bridge_c.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct JtagBridgeHandle JtagBridgeHandle; + +JtagBridgeHandle* jtag_bridge_create(void); +void jtag_bridge_destroy(JtagBridgeHandle* handle); + +int jtag_bridge_open(JtagBridgeHandle* handle, int port, int chain); +int jtag_bridge_open_selector(JtagBridgeHandle* handle, const char* selector, int port, int chain); +void jtag_bridge_close(JtagBridgeHandle* handle); + +int jtag_bridge_set_speed(JtagBridgeHandle* handle, uint32_t requested_hz, uint32_t* actual_hz); +int jtag_bridge_set_chain(JtagBridgeHandle* handle, int chain); + +int jtag_bridge_clear_flags(JtagBridgeHandle* handle); +int jtag_bridge_ping(JtagBridgeHandle* handle); +int jtag_bridge_set_reset(JtagBridgeHandle* handle, int enabled); + +int jtag_bridge_write8(JtagBridgeHandle* handle, uint32_t addr, uint8_t value); +int jtag_bridge_read8(JtagBridgeHandle* handle, uint32_t addr, uint8_t* value); +int jtag_bridge_write32(JtagBridgeHandle* handle, uint32_t addr, uint32_t value); +int jtag_bridge_read32(JtagBridgeHandle* handle, uint32_t addr, uint32_t* value); + +const char* jtag_bridge_last_error(const JtagBridgeHandle* handle); + +#ifdef __cplusplus +} +#endif diff --git a/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_wb_bridge_client.cpp b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_wb_bridge_client.cpp new file mode 100644 index 0000000..5a3616e --- /dev/null +++ b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_wb_bridge_client.cpp @@ -0,0 +1,186 @@ +#include "jtag_wb_bridge_client.hpp" + +#include + +namespace { + +constexpr uint8_t kOpNop = 0x00; +constexpr uint8_t kOpResetOn = 0x10; +constexpr uint8_t kOpResetOff = 0x11; +constexpr uint8_t kOpWrite8 = 0x20; +constexpr uint8_t kOpRead8 = 0x21; +constexpr uint8_t kOpWrite32 = 0x22; +constexpr uint8_t kOpRead32 = 0x23; +constexpr uint8_t kOpPing = 0x30; +constexpr uint8_t kOpClearFlags = 0x40; + +constexpr int kPacketBytes = 9; +constexpr int kPacketBits = 72; +constexpr int kMaxPollAttempts = 32; + +void makeCommand(uint8_t out[kPacketBytes], uint8_t opcode, uint32_t addr, uint32_t data) { + out[0] = static_cast(data); + out[1] = static_cast(data >> 8); + out[2] = static_cast(data >> 16); + out[3] = static_cast(data >> 24); + out[4] = static_cast(addr); + out[5] = static_cast(addr >> 8); + out[6] = static_cast(addr >> 16); + out[7] = static_cast(addr >> 24); + out[8] = opcode; +} + +uint32_t getResponseData32(const uint8_t rx[kPacketBytes]) { + return static_cast(rx[2]) | + (static_cast(rx[3]) << 8) | + (static_cast(rx[4]) << 16) | + (static_cast(rx[5]) << 24); +} + +uint8_t getLastOpcode(const uint8_t rx[kPacketBytes]) { + return rx[0]; +} + +} // namespace + +bool JtagWishboneBridge::open(int port, int chain) { + if (!jtag_.open(port)) { + return setError(jtag_.lastError()); + } + if (!jtag_.setChain(chain)) { + const std::string msg = jtag_.lastError(); + jtag_.close(); + return setError(msg); + } + last_error_.clear(); + return true; +} + +bool JtagWishboneBridge::open(const std::string& selector, int port, int chain) { + if (!jtag_.open(selector, port)) { + return setError(jtag_.lastError()); + } + if (!jtag_.setChain(chain)) { + const std::string msg = jtag_.lastError(); + jtag_.close(); + return setError(msg); + } + last_error_.clear(); + return true; +} + +void JtagWishboneBridge::close() { + jtag_.close(); + last_error_.clear(); +} + +bool JtagWishboneBridge::isOpen() const { + return jtag_.isOpen(); +} + +bool JtagWishboneBridge::setSpeed(uint32_t requested_hz, uint32_t* actual_hz) { + if (!jtag_.setSpeed(requested_hz, actual_hz)) { + return setError(jtag_.lastError()); + } + last_error_.clear(); + return true; +} + +bool JtagWishboneBridge::setChain(int chain) { + if (!jtag_.setChain(chain)) { + return setError(jtag_.lastError()); + } + last_error_.clear(); + return true; +} + +bool JtagWishboneBridge::clearFlags() { + return executeCommand(kOpClearFlags, 0, 0, nullptr); +} + +bool JtagWishboneBridge::ping() { + uint32_t response = 0; + uint8_t ping_value; + if (!executeCommand(kOpPing, 0, 0, &response)) { + return false; + } + ping_value = static_cast(response & 0xffu); + if (ping_value != 0xa5) { + char msg[96]; + std::snprintf(msg, sizeof(msg), "ping mismatch: expected 0xa5, got 0x%02x", ping_value); + return setError(msg); + } + last_error_.clear(); + return true; +} + +bool JtagWishboneBridge::setReset(bool enabled) { + return executeCommand(enabled ? kOpResetOn : kOpResetOff, 0, 0, nullptr); +} + +bool JtagWishboneBridge::write8(uint32_t addr, uint8_t value) { + return executeCommand(kOpWrite8, addr, value, nullptr); +} + +bool JtagWishboneBridge::read8(uint32_t addr, uint8_t* value) { + uint32_t response = 0; + if (!value) { + return setError("read8: value pointer is null"); + } + if (!executeCommand(kOpRead8, addr, 0, &response)) { + return false; + } + *value = static_cast(response & 0xffu); + return true; +} + +bool JtagWishboneBridge::write32(uint32_t addr, uint32_t value) { + return executeCommand(kOpWrite32, addr, value, nullptr); +} + +bool JtagWishboneBridge::read32(uint32_t addr, uint32_t* value) { + if (!value) { + return setError("read32: value pointer is null"); + } + return executeCommand(kOpRead32, addr, 0, value); +} + +const std::string& JtagWishboneBridge::lastError() const { + return last_error_; +} + +bool JtagWishboneBridge::executeCommand(uint8_t opcode, uint32_t addr, uint32_t data, uint32_t* response_data) { + if (!jtag_.isOpen()) { + return setError("executeCommand: device not open"); + } + + uint8_t tx[kPacketBytes] = {0}; + uint8_t rx[kPacketBytes] = {0}; + makeCommand(tx, opcode, addr, data); + if (!jtag_.shiftData(tx, rx, kPacketBits)) { + return setError(jtag_.lastError()); + } + + for (int i = 0; i < kMaxPollAttempts; ++i) { + makeCommand(tx, kOpNop, 0, 0); + if (!jtag_.shiftData(tx, rx, kPacketBits)) { + return setError(jtag_.lastError()); + } + if (getLastOpcode(rx) == opcode) { + if (response_data) { + *response_data = getResponseData32(rx); + } + last_error_.clear(); + return true; + } + } + + char msg[96]; + std::snprintf(msg, sizeof(msg), "command 0x%02x timed out after %d polls", opcode, kMaxPollAttempts); + return setError(msg); +} + +bool JtagWishboneBridge::setError(const std::string& msg) { + last_error_ = msg; + return false; +} diff --git a/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_wb_bridge_client.hpp b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_wb_bridge_client.hpp new file mode 100644 index 0000000..2bf3968 --- /dev/null +++ b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/jtag_wb_bridge_client.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include "digilent_jtag.hpp" + +#include +#include + +class JtagWishboneBridge { +public: + JtagWishboneBridge() = default; + ~JtagWishboneBridge() = default; + + JtagWishboneBridge(const JtagWishboneBridge&) = delete; + JtagWishboneBridge& operator=(const JtagWishboneBridge&) = delete; + + bool open(int port = 0, int chain = 1); + bool open(const std::string& selector, int port = 0, int chain = 1); + void close(); + + bool isOpen() const; + + bool setSpeed(uint32_t requested_hz, uint32_t* actual_hz = nullptr); + bool setChain(int chain); + + bool clearFlags(); + bool ping(); + bool setReset(bool enabled); + + bool write8(uint32_t addr, uint8_t value); + bool read8(uint32_t addr, uint8_t* value); + bool write32(uint32_t addr, uint32_t value); + bool read32(uint32_t addr, uint32_t* value); + + const std::string& lastError() const; + +private: + bool executeCommand(uint8_t opcode, uint32_t addr, uint32_t data, uint32_t* response_data); + bool setError(const std::string& msg); + + DigilentJtag jtag_; + std::string last_error_; +}; diff --git a/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/prog.cpp b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/prog.cpp new file mode 100644 index 0000000..24a9184 --- /dev/null +++ b/cores/wb/jtag_wb_bridge/tool/libjtag_wb_bridge/prog.cpp @@ -0,0 +1,99 @@ +#include "argparse.hpp" +#include "jtag_wb_bridge_client.hpp" + +#include +#include + +int main(int argc, char** argv) { + ArgParser parser(argc > 0 ? argv[0] : "test"); + parser.addString("file", "", "File to write", true, "f"); + parser.addFlag("verify", "Verify", "v"); + + std::string parse_error; + if (!parser.parse(argc, argv, &parse_error)) { + if (parse_error == "help") { + std::printf("%s", parser.helpText().c_str()); + return 0; + } + std::printf("Argument error: %s\n\n", parse_error.c_str()); + std::printf("%s", parser.helpText().c_str()); + return -1; + } + + JtagWishboneBridge bridge; + if (!bridge.open()) { + std::printf("Could not open programmer: %s\n", bridge.lastError().c_str()); + return -1; + } + + if (!bridge.clearFlags()) { + std::printf("Could not clear flags: %s\n", bridge.lastError().c_str()); + return -1; + } + + if (!bridge.ping()) { + std::printf("PING command failed: %s\n", bridge.lastError().c_str()); + return -1; + } + + const std::string file = parser.getString("file"); + FILE* f = std::fopen(file.c_str(), "rb"); + if (!f) { + std::printf("Could not open file\n"); + return -1; + } + + if (!bridge.setReset(true)) { + std::printf("Could not assert reset: %s\n", bridge.lastError().c_str()); + std::fclose(f); + return -1; + } + + int nr = 0; + uint32_t addr = 0; + do { + uint32_t buf[32]; + nr = static_cast(std::fread(buf, sizeof(uint32_t), 32, f)); + for (int i = 0; i < nr; ++i) { + if (!bridge.write32(addr + static_cast(i * 4), buf[i])) { + std::printf("Write failed at %04x: %s\n", + addr + static_cast(i * 4), + bridge.lastError().c_str()); + std::fclose(f); + return -1; + } + std::printf("."); + } + std::printf("\n"); + + if (parser.getFlag("verify")) { + for (int i = 0; i < nr; ++i) { + uint32_t value = 0; + if (!bridge.read32(addr + static_cast(i * 4), &value)) { + std::printf("Read failed at %04x: %s\n", + addr + static_cast(i * 4), + bridge.lastError().c_str()); + std::fclose(f); + return -1; + } + if (value != buf[i]) { + std::printf(" -- Verify failed at %04x : %08x != %08x\n", + addr + static_cast(i * 4), + value, + buf[i]); + } + } + } + + addr += static_cast(nr * 4); + } while (nr > 0); + + if (!bridge.setReset(false)) { + std::printf("Could not deassert reset: %s\n", bridge.lastError().c_str()); + std::fclose(f); + return -1; + } + + std::fclose(f); + return 0; +} diff --git a/cores/wb/jtag_wb_bridge/tool/test.py b/cores/wb/jtag_wb_bridge/tool/test.py new file mode 100644 index 0000000..30d9a9d --- /dev/null +++ b/cores/wb/jtag_wb_bridge/tool/test.py @@ -0,0 +1,8 @@ +from libjtag_wb_bridge.jtag_bridge import JtagBridge + +with JtagBridge() as bridge: + bridge.open(port=0, chain=1) + bridge.clear_flags() + bridge.ping() + + bridge.write8(0x0, 0xAA) \ No newline at end of file diff --git a/rtl/core/arbiter.v b/cores/wb/wb_arbiter/rtl/arbiter.v similarity index 98% rename from rtl/core/arbiter.v rename to cores/wb/wb_arbiter/rtl/arbiter.v index 17c2e74..07ada9a 100644 --- a/rtl/core/arbiter.v +++ b/cores/wb/wb_arbiter/rtl/arbiter.v @@ -25,7 +25,7 @@ * Author: Berin Martini // berin.martini@gmail.com */ `ifndef _arbiter_ `define _arbiter_ - `include "../util/clog2.vh" + `include "clog2.vh" module arbiter #(parameter @@ -135,4 +135,4 @@ module arbiter endmodule -`endif // `ifndef _arbiter_ \ No newline at end of file +`endif // `ifndef _arbiter_ diff --git a/rtl/wb/wb_arbiter.v b/cores/wb/wb_arbiter/rtl/wb_arbiter.v similarity index 99% rename from rtl/wb/wb_arbiter.v rename to cores/wb/wb_arbiter/rtl/wb_arbiter.v index cf61abe..899a641 100644 --- a/rtl/wb/wb_arbiter.v +++ b/cores/wb/wb_arbiter/rtl/wb_arbiter.v @@ -21,7 +21,7 @@ Wishbone arbiter, burst-compatible Simple round-robin arbiter for multiple Wishbone masters */ -`include "../util/clog2.vh" +`include "clog2.vh" module wb_arbiter #(parameter dw = 32, diff --git a/cores/wb/wb_arbiter/wb_arbiter.core b/cores/wb/wb_arbiter/wb_arbiter.core new file mode 100644 index 0000000..df864f8 --- /dev/null +++ b/cores/wb/wb_arbiter/wb_arbiter.core @@ -0,0 +1,42 @@ +CAPI=2: + +name: joppeb:wb:wb_arbiter:1.0 +description: Wishbone round-robin arbiter + +filesets: + rtl: + depend: + - joppeb:util:clog2 + files: + - rtl/arbiter.v + - rtl/wb_arbiter.v + file_type: verilogSource + +targets: + default: + filesets: + - rtl + toplevel: wb_arbiter + parameters: + - dw + - aw + - num_hosts + - num_masters + +parameters: + dw: + datatype: int + description: Wishbone data width + paramtype: vlogparam + aw: + datatype: int + description: Wishbone address width + paramtype: vlogparam + num_hosts: + datatype: int + description: Deprecated alias for num_masters + paramtype: vlogparam + num_masters: + datatype: int + description: Number of wishbone masters + paramtype: vlogparam diff --git a/cores/wb/wb_gpio/formal/formal_wb_gpio.v b/cores/wb/wb_gpio/formal/formal_wb_gpio.v new file mode 100644 index 0000000..035e6b8 --- /dev/null +++ b/cores/wb/wb_gpio/formal/formal_wb_gpio.v @@ -0,0 +1,67 @@ +`timescale 1ns/1ps + +module formal_wb_gpio; + (* gclk *) reg i_wb_clk; + (* anyseq *) reg i_wb_rst; + (* anyseq *) reg [31:0] i_wb_adr; + (* anyseq *) reg [31:0] i_wb_dat; + (* anyseq *) reg [3:0] i_wb_sel; + (* anyseq *) reg i_wb_we; + (* anyseq *) reg i_wb_stb; + (* anyseq *) reg i_wb_cyc; + (* anyseq *) reg [31:0] i_gpio; + wire [31:0] o_wb_rdt; + wire o_wb_ack; + wire [31:0] o_gpio; + reg f_past_valid; + + wb_gpio dut ( + .i_clk(i_wb_clk), + .i_rst(i_wb_rst), + .i_wb_adr(i_wb_adr), + .i_wb_dat(i_wb_dat), + .i_wb_sel(i_wb_sel), + .i_wb_we(i_wb_we), + .i_wb_stb(i_wb_stb), + .i_wb_cyc(i_wb_cyc), + .i_gpio(i_gpio), + .o_wb_rdt(o_wb_rdt), + .o_wb_ack(o_wb_ack), + .o_gpio(o_gpio) + ); + + formal_wb_slave_checker wb_checker ( + .i_clk(i_wb_clk), + .i_rst(i_wb_rst), + .i_wb_rst(i_wb_rst), + .i_wb_adr(i_wb_adr), + .i_wb_dat(i_wb_dat), + .i_wb_sel(i_wb_sel), + .i_wb_we(i_wb_we), + .i_wb_stb(i_wb_stb), + .i_wb_cyc(i_wb_cyc), + .o_wb_rdt(o_wb_rdt), + .o_wb_ack(o_wb_ack) + ); + + initial f_past_valid = 1'b0; + + always @(posedge i_wb_clk) begin + f_past_valid <= 1'b1; + + // R1: reads return the sampled GPIO input on the following cycle + if(f_past_valid && + !i_wb_rst && $past(!i_wb_rst) && + o_wb_ack && + $past(i_wb_sel)==4'hf && i_wb_sel==4'hf && + $past(i_wb_cyc & i_wb_stb & !i_wb_we) && + (i_wb_cyc & i_wb_stb & !i_wb_we)) + assert(o_wb_rdt == $past(i_gpio)); + + // R2: reset clears the output register and read data register + if (f_past_valid && $past(i_wb_rst)) begin + assert(o_gpio == 32'h00000000); + assert(o_wb_rdt == 32'h00000000); + end + end +endmodule diff --git a/cores/wb/wb_gpio/formal/wb_gpio.sby b/cores/wb/wb_gpio/formal/wb_gpio.sby new file mode 100644 index 0000000..a5088be --- /dev/null +++ b/cores/wb/wb_gpio/formal/wb_gpio.sby @@ -0,0 +1,23 @@ +[tasks] +prove +cover +bmc + +[options] +bmc: mode bmc +bmc: depth 50 +cover: mode cover +cover: depth 50 +prove: mode prove + +[engines] +bmc: smtbmc yices +cover: smtbmc yices +prove: abc pdr + +[script] +{{"-formal"|gen_reads}} +prep -top {{top_level}} + +[files] +{{files}} \ No newline at end of file diff --git a/cores/wb/wb_gpio/rtl/wb_gpio.v b/cores/wb/wb_gpio/rtl/wb_gpio.v new file mode 100644 index 0000000..bb59b8a --- /dev/null +++ b/cores/wb/wb_gpio/rtl/wb_gpio.v @@ -0,0 +1,53 @@ +module wb_gpio ( + input wire i_clk, + input wire i_rst, + + input wire [31:0] i_wb_adr, + input wire [31:0] i_wb_dat, + output reg [31:0] o_wb_rdt, + input wire [3:0] i_wb_sel, + input wire i_wb_we, + input wire i_wb_cyc, + input wire i_wb_stb, + output wire o_wb_ack, + + input wire [31:0] i_gpio, + output wire [31:0] o_gpio +); + + // Registers + reg [31:0] gpo; + wire [31:0] gpi; + assign o_gpio = gpo; + assign gpi = i_gpio; + + reg wb_ack = 0; + assign o_wb_ack = wb_ack & i_wb_cyc & i_wb_stb; + + always @(posedge i_clk) begin + if(i_rst) begin + gpo <= 0; + wb_ack <= 0; + o_wb_rdt <= 0; + end else begin + // Ack generation + wb_ack <= i_wb_cyc & i_wb_stb & !wb_ack; + + // Read cycle + if(i_wb_cyc && i_wb_stb && !i_wb_we) begin + if(i_wb_sel[0]) o_wb_rdt[7:0] <= gpi[7:0]; + if(i_wb_sel[1]) o_wb_rdt[15:8] <= gpi[15:8]; + if(i_wb_sel[2]) o_wb_rdt[23:16] <= gpi[23:16]; + if(i_wb_sel[3]) o_wb_rdt[31:24] <= gpi[31:24]; + end + // write cycle + if(i_wb_cyc && i_wb_stb && i_wb_we) begin + if(i_wb_sel[0]) gpo[7:0] <= i_wb_dat[7:0]; + if(i_wb_sel[1]) gpo[15:8] <= i_wb_dat[15:8]; + if(i_wb_sel[2]) gpo[23:16] <= i_wb_dat[23:16]; + if(i_wb_sel[3]) gpo[31:24] <= i_wb_dat[31:24]; + end + end + end + +endmodule diff --git a/cores/wb/wb_gpio/wb_gpio.core b/cores/wb/wb_gpio/wb_gpio.core new file mode 100644 index 0000000..fa3cc43 --- /dev/null +++ b/cores/wb/wb_gpio/wb_gpio.core @@ -0,0 +1,35 @@ +CAPI=2: + +name: joppeb:wb:wb_gpio:1.0 +description: Wishbone GPIO peripheral + +filesets: + rtl: + files: + - rtl/wb_gpio.v + file_type: verilogSource + + formal_rtl: + depend: + - joppeb:wb:formal_checker + files: + - formal/formal_wb_gpio.v + file_type: verilogSource + formal_cfg: + files: + - formal/wb_gpio.sby + file_type: sbyConfigTemplate + +targets: + default: + filesets: + - rtl + toplevel: wb_gpio + + formal: + default_tool: symbiyosys + filesets: + - rtl + - formal_rtl + - formal_cfg + toplevel: formal_wb_gpio diff --git a/cores/wb/wb_gpio_banks/formal/formal_wb_gpio_banks.v b/cores/wb/wb_gpio_banks/formal/formal_wb_gpio_banks.v new file mode 100644 index 0000000..658c7d1 --- /dev/null +++ b/cores/wb/wb_gpio_banks/formal/formal_wb_gpio_banks.v @@ -0,0 +1,50 @@ +`timescale 1ns/1ps + +module formal_wb_gpio_banks #( + parameter integer num_banks = 2, +); + (* gclk *) reg i_clk; + (* anyseq *) reg i_rst; + (* anyseq *) reg [31:0] i_wb_adr; + (* anyseq *) reg [31:0] i_wb_dat; + (* anyseq *) reg [3:0] i_wb_sel; + (* anyseq *) reg i_wb_we; + (* anyseq *) reg i_wb_stb; + (* anyseq *) reg [num_banks*32-1:0] i_gpio; + wire [31:0] o_wb_rdt; + wire o_wb_ack; + wire [num_banks*32-1:0] o_gpio; + wire i_wb_cyc; + + assign i_wb_cyc = i_wb_stb || o_wb_ack; + + wb_gpio_banks #( + .num_banks(num_banks) + ) dut ( + .i_clk(i_clk), + .i_rst(i_rst), + .i_wb_adr(i_wb_adr), + .i_wb_dat(i_wb_dat), + .i_wb_sel(i_wb_sel), + .i_wb_we(i_wb_we), + .i_wb_stb(i_wb_stb), + .i_gpio(i_gpio), + .o_wb_rdt(o_wb_rdt), + .o_wb_ack(o_wb_ack), + .o_gpio(o_gpio) + ); + + formal_wb_slave_checker wb_checker ( + .i_clk(i_clk), + .i_rst(i_rst), + .i_wb_rst(i_rst), + .i_wb_adr(i_wb_adr), + .i_wb_dat(i_wb_dat), + .i_wb_sel(i_wb_sel), + .i_wb_we(i_wb_we), + .i_wb_stb(i_wb_stb), + .i_wb_cyc(i_wb_cyc), + .o_wb_rdt(o_wb_rdt), + .o_wb_ack(o_wb_ack) + ); +endmodule diff --git a/cores/wb/wb_gpio_banks/formal/wb_gpio_banks.sby b/cores/wb/wb_gpio_banks/formal/wb_gpio_banks.sby new file mode 100644 index 0000000..e5382b5 --- /dev/null +++ b/cores/wb/wb_gpio_banks/formal/wb_gpio_banks.sby @@ -0,0 +1,25 @@ +[tasks] +prove +cover +bmc + +[options] +bmc: mode bmc +bmc: depth 50 +cover: mode cover +cover: depth 50 +prove: mode prove + +[engines] +bmc: smtbmc yices +cover: smtbmc yices +prove: abc pdr + +[script] +read -formal clog2.vh +{{"-formal"|gen_reads}} +prep -top {{top_level}} + +[files] +src/joppeb_util_clog2_1.0/clog2.vh +{{files}} diff --git a/cores/wb/wb_gpio_banks/rtl/wb_gpio_banks.v b/cores/wb/wb_gpio_banks/rtl/wb_gpio_banks.v new file mode 100644 index 0000000..04476ec --- /dev/null +++ b/cores/wb/wb_gpio_banks/rtl/wb_gpio_banks.v @@ -0,0 +1,61 @@ +`include "clog2.vh" + +module wb_gpio_banks #( + parameter num_banks = 4 +)( + input wire i_clk, + input wire i_rst, + + input wire [31:0] i_wb_adr, + input wire [31:0] i_wb_dat, + output reg [31:0] o_wb_rdt, + input wire [3:0] i_wb_sel, + input wire i_wb_we, + input wire i_wb_cyc, + input wire i_wb_stb, + output wire o_wb_ack, + + input wire [num_banks*32-1:0] i_gpio, + output wire [num_banks*32-1:0] o_gpio +); + localparam sw = `CLOG2(num_banks); + wire [num_banks-1:0] bank_sel; + + wire [num_banks-1:0] bank_ack; + wire [num_banks*32-1:0] bank_rdt; + + genvar gi; + generate + for(gi=0; gi0; + + if(!irq_fired && prev_counter_running && !counter_running) + irq_fired <= 1'b1; + if(counter>0 && counter_started) + counter <= counter - 1; + + if(counter == 0 && preload>0 && counter_started) + counter <= preload; + + if(counter == 0 && preload == 0) + counter_started <= 1'b0; + + // Ack generation + wb_ack <= i_wb_cyc & i_wb_stb & !wb_ack; + + // Read cycle + if(i_wb_cyc && i_wb_stb && !i_wb_we) begin + if(i_wb_adr[3:0] == 4'b0000) begin + if(i_wb_sel[0]) o_wb_dat[7:0] <= counter[7:0]; + if(i_wb_sel[1]) o_wb_dat[15:8] <= counter[15:8]; + if(i_wb_sel[2]) o_wb_dat[23:16] <= counter[23:16]; + if(i_wb_sel[3]) o_wb_dat[31:24] <= counter[31:24]; + end else if(i_wb_adr[3:0] == 4'b0100) begin + if(i_wb_sel[0]) o_wb_dat[7:0] <= preload[7:0]; + if(i_wb_sel[1]) o_wb_dat[15:8] <= preload[15:8]; + if(i_wb_sel[2]) o_wb_dat[23:16] <= preload[23:16]; + if(i_wb_sel[3]) o_wb_dat[31:24] <= preload[31:24]; + end + end + + // write cycle + if(i_wb_cyc && i_wb_stb && i_wb_we) begin + if(i_wb_adr[3:0] == 4'b0000) begin + if(i_wb_sel[0]) counter[7:0] <= i_wb_dat[7:0]; + if(i_wb_sel[1]) counter[15:8] <= i_wb_dat[15:8]; + if(i_wb_sel[2]) counter[23:16] <= i_wb_dat[23:16]; + if(i_wb_sel[3]) counter[31:24] <= i_wb_dat[31:24]; + counter_started <= 1'b1; + end else if(i_wb_adr[3:0] == 4'b0100) begin + if(i_wb_sel[0]) preload[7:0] <= i_wb_dat[7:0]; + if(i_wb_sel[1]) preload[15:8] <= i_wb_dat[15:8]; + if(i_wb_sel[2]) preload[23:16] <= i_wb_dat[23:16]; + if(i_wb_sel[3]) preload[31:24] <= i_wb_dat[31:24]; + counter_started <= 1'b1; + end else if(i_wb_adr[3:0] == 4'b1000) begin + // Any write to BASE+8 will ack the IRQ + irq_fired <= 1'b0; + end + end + + end + end + +`ifdef FORMAL + // Formal verification + reg f_past_valid = 1'b0; + wire cnt_write = i_wb_cyc && i_wb_stb && i_wb_we && (i_wb_adr[3:0] == 4'h0); + wire pld_write = i_wb_cyc && i_wb_stb && i_wb_we && (i_wb_adr[3:0] == 4'h4); + wire ack_write = i_wb_cyc && i_wb_stb && i_wb_we && (i_wb_adr[3:0] == 4'h8); + reg [31:0] past_counter; + + always @(posedge i_clk) begin + f_past_valid <= 1'b1; + past_counter <= counter; + + // R1: Reset clears all timer state on the following cycle. + // Check counter, preload, wb_ack, o_wb_dat, irq_fired, + // counter_started, counter_running, and prev_counter_running. + if(f_past_valid && $past(i_rst)) begin + R1s1: assert(counter==0); + R1s2: assert(preload==0); + R1s3: assert(!wb_ack); + R1s4: assert(o_wb_dat==0); + R1s5: assert(!irq_fired); + R1s6: assert(!counter_started); + R1s7: assert(!counter_running); + end + + // R2: irq_fired is sticky until reset or a write to BASE+8 clears it. + // -> if last cycle was irq and last cycle was not reset and not ack write then now still irq + if(f_past_valid && $past(!i_rst) && $past(irq_fired) && $past(!ack_write)) + R2: assert(irq_fired); + + // R3: A write to BASE+8 clears irq_fired on the following cycle. + // -> if last cycle was ack write and irq was high it must be low now + if(f_past_valid && $past(!i_rst) && $past(irq_fired) && $past(ack_write)) + R3: assert(!irq_fired); + + // R4: While the timer is running and no counter write overrides it, + // counter decrements by exactly one each cycle. + if(f_past_valid && $past(!i_rst) && $past(counter>1) && $past(counter_started) && $past(!cnt_write)) + R4: assert(counter == $past(counter)-1); + + // R5: When counter reaches zero with preload > 0 and the timer is started, + // the counter reloads from preload. + if(f_past_valid && $past(!i_rst) && $past(counter==0) && $past(preload>0) && $past(counter_started) && $past(!cnt_write)) + R5: assert(counter == $past(preload)); + + // R6: When counter == 0 and preload == 0, the timer stops + // (counter_started deasserts unless a write rearms it). + if(f_past_valid && $past(!i_rst) && $past(counter==0) && $past(preload==0) && $past(!cnt_write) && $past(!pld_write)) begin + R6s1: assert(counter==0); + R6s2: assert(counter_started==0); + end + + // R7: A write to BASE+0 or BASE+4 arms the timer + // (counter_started asserts on the following cycle). + if(f_past_valid && $past(!i_rst) && ($past(cnt_write) || $past(pld_write))) + R7: assert(counter_started==1); + + // R8: o_irq always reflects irq_fired. + R8: assert(o_irq == irq_fired); + + // R9: Interrupt only fired after counter was 0 two clock cycles ago + if(f_past_valid && $past(!i_rst) && $past(!irq_fired) && irq_fired) + R9: assert($past(past_counter) == 0); + + // C1: Cover a counter write that starts the timer. + C1s1: cover(f_past_valid && !i_rst && cnt_write); + if(f_past_valid && $past(!i_rst) && $past(cnt_write)) + C1s2: cover(counter_started); + + // C2: Cover a preload write. + C2: cover(f_past_valid && !i_rst && pld_write); + + // C3: Cover the counter decrementing at least once. + C3: cover(f_past_valid && $past(!i_rst) && $past(counter)==counter-1 && $past(!cnt_write) && $past(!pld_write)); + + // C4: Cover the counter reloading from preload. + C4: cover(f_past_valid && $past(!i_rst) && $past(counter==0) && $past(preload>0) && counter>0 && $past(!cnt_write) && $past(!pld_write)); + + // C5: Cover irq_fired asserting when the timer expires. + C5: cover(f_past_valid && $past(!i_rst) && $past(!irq_fired) && irq_fired && $past(counter==0)); + + // C6: Cover irq_fired being cleared by a write to BASE+8. + C6: cover(f_past_valid && $past(!i_rst) && $past(irq_fired) && !irq_fired && $past(ack_write)); + + end +`endif + +endmodule diff --git a/cores/wb/wb_timer/tb/tb_wb_timer.v b/cores/wb/wb_timer/tb/tb_wb_timer.v new file mode 100644 index 0000000..0c38307 --- /dev/null +++ b/cores/wb/wb_timer/tb/tb_wb_timer.v @@ -0,0 +1,143 @@ +`timescale 1ns/1ps + +module tb_wb_timer; + localparam ADDR_COUNTER = 32'h0000_0000; + localparam ADDR_PRELOAD = 32'h0000_0004; + localparam ADDR_ACK = 32'h0000_0008; + + reg i_clk; + reg i_rst; + reg [31:0] i_wb_adr; + reg [31:0] i_wb_dat; + reg [3:0] i_wb_sel; + reg i_wb_we; + reg i_wb_stb; + reg i_wb_cyc; + wire [31:0] o_wb_dat; + wire o_wb_ack; + wire o_irq; + + reg [31:0] read_data; + integer cycle; + + wb_countdown_timer dut ( + .i_clk(i_clk), + .i_rst(i_rst), + .o_irq(o_irq), + .i_wb_adr(i_wb_adr), + .i_wb_dat(i_wb_dat), + .o_wb_dat(o_wb_dat), + .i_wb_sel(i_wb_sel), + .i_wb_we(i_wb_we), + .i_wb_cyc(i_wb_cyc), + .i_wb_stb(i_wb_stb), + .o_wb_ack(o_wb_ack) + ); + + initial i_clk = 1'b0; + always #5 i_clk = ~i_clk; + + task automatic wb_write; + input [31:0] addr; + input [31:0] data; + input [3:0] sel; + begin + @(negedge i_clk); + i_wb_adr <= addr; + i_wb_dat <= data; + i_wb_sel <= sel; + i_wb_we <= 1'b1; + i_wb_stb <= 1'b1; + i_wb_cyc <= 1'b1; + + while (!o_wb_ack) + @(posedge i_clk); + + @(negedge i_clk); + i_wb_we <= 1'b0; + i_wb_stb <= 1'b0; + i_wb_cyc <= 1'b0; + i_wb_sel <= 4'b0000; + i_wb_dat <= 32'h0000_0000; + end + endtask + + task automatic wb_read; + input [31:0] addr; + output [31:0] data; + begin + @(negedge i_clk); + i_wb_adr <= addr; + i_wb_dat <= 32'h0000_0000; + i_wb_sel <= 4'b1111; + i_wb_we <= 1'b0; + i_wb_stb <= 1'b1; + i_wb_cyc <= 1'b1; + + while (!o_wb_ack) + @(posedge i_clk); + + #1; + data = o_wb_dat; + + @(negedge i_clk); + i_wb_stb <= 1'b0; + i_wb_cyc <= 1'b0; + i_wb_sel <= 4'b0000; + end + endtask + + initial begin + $dumpfile("wb_timer.vcd"); + $dumpvars(0, tb_wb_timer); + + i_rst = 1'b1; + i_wb_adr = 32'h0000_0000; + i_wb_dat = 32'h0000_0000; + i_wb_sel = 4'b0000; + i_wb_we = 1'b0; + i_wb_stb = 1'b0; + i_wb_cyc = 1'b0; + + repeat (2) @(posedge i_clk); + i_rst = 1'b0; + + wb_write(ADDR_COUNTER, 5, 4'b1111); + wb_write(ADDR_PRELOAD, 0, 4'b1111); + + for (cycle = 0; cycle < 40; cycle = cycle + 1) begin + @(posedge i_clk); + if(o_irq) + wb_write(ADDR_ACK, 32'h0000_ffff, 4'b1111); + end + + for (cycle = 0; cycle < 8; cycle = cycle + 1) + @(posedge i_clk); + + wb_write(ADDR_PRELOAD, 8, 4'b1111); + + for (cycle = 0; cycle < 21; cycle = cycle + 1) begin + @(posedge i_clk); + if(o_irq) + wb_write(ADDR_ACK, 32'h0000_ffff, 4'b1111); + end + + wb_write(ADDR_PRELOAD, 6, 4'b1111); + + for (cycle = 0; cycle < 21; cycle = cycle + 1) begin + @(posedge i_clk); + if(o_irq) + wb_write(ADDR_ACK, 32'h0000_ffff, 4'b1111); + end + + wb_write(ADDR_PRELOAD, 0, 4'b1111); + + for (cycle = 0; cycle < 10; cycle = cycle + 1) begin + @(posedge i_clk); + if(o_irq) + wb_write(ADDR_ACK, 32'h0000_ffff, 4'b1111); + end + + $finish; + end +endmodule diff --git a/cores/wb/wb_timer/wb_timer.core b/cores/wb/wb_timer/wb_timer.core new file mode 100644 index 0000000..677cc6b --- /dev/null +++ b/cores/wb/wb_timer/wb_timer.core @@ -0,0 +1,51 @@ +CAPI=2: + +name: joppeb:wb:wb_timer:1.0 +description: Wishbone countdown timer peripheral + +filesets: + rtl: + files: + - rtl/wb_timer.v + file_type: verilogSource + tb: + files: + - tb/tb_wb_timer.v + file_type: verilogSource + formal_rtl: + depend: + - joppeb:wb:formal_checker + files: + - formal/formal_wb_timer.v + file_type: verilogSource + formal_cfg: + files: + - formal/wb_timer.sby + file_type: sbyConfigTemplate + +targets: + default: + filesets: + - rtl + toplevel: wb_countdown_timer + sim: + default_tool: icarus + filesets: + - rtl + - tb + toplevel: tb_wb_timer + formal: + default_tool: symbiyosys + filesets: + - rtl + - formal_rtl + - formal_cfg + toplevel: formal_wb_timer + parameters: + - FORMAL=true + +parameters: + FORMAL: + datatype: bool + description: Enable in-module formal-only logic + paramtype: vlogdefine diff --git a/fusesoc.conf b/fusesoc.conf new file mode 100644 index 0000000..ac3f322 --- /dev/null +++ b/fusesoc.conf @@ -0,0 +1,17 @@ +[library.base] +location = /data/joppe/projects/fusesoc_test/cores +sync-uri = ./cores +sync-type = local +auto-sync = true + +[library.serv] +location = ./fusesoc_libraries/serv +sync-uri = git@github.com:Jojojoppe/serv.git +sync-type = local +auto-sync = true + +[library.fusesoc-cores] +location = ./fusesoc_libraries/fusesoc-cores +sync-uri = https://github.com/fusesoc/fusesoc-cores +sync-type = git +auto-sync = true diff --git a/fusesoc_libraries/fusesoc-cores b/fusesoc_libraries/fusesoc-cores new file mode 160000 index 0000000..815f64b --- /dev/null +++ b/fusesoc_libraries/fusesoc-cores @@ -0,0 +1 @@ +Subproject commit 815f64ba335db54a7904eed862c970dc66ac7018 diff --git a/fusesoc_libraries/serv b/fusesoc_libraries/serv new file mode 160000 index 0000000..74a7f73 --- /dev/null +++ b/fusesoc_libraries/serv @@ -0,0 +1 @@ +Subproject commit 74a7f73d3198f17bebf5754cb94e72dc30b0103e diff --git a/project.cfg b/project.cfg deleted file mode 100644 index 6857882..0000000 --- a/project.cfg +++ /dev/null @@ -1,220 +0,0 @@ -[project] -name = modem -version = 0.1 -out_dir = out -build_dir = build - -[target.ip] -toolchain = ISE_IP -ise_settings = /opt/Xilinx/14.7/ISE_DS/settings64.sh -family = spartan6 -device = xc6slx9 -package = tqg144 -speedgrade = -2 -files_def = boards/mimas_v1/ip/clk_gen.xco - -[target.tools] -toolchain = make -output_files = tools/test -buildroot = tools -files_makefile = tools/Makefile -files_other = tools/digilent_jtag.cpp - tools/digilent_jtag.hpp - tools/argparse.cpp - tools/argparse.hpp - tools/test.cpp - -# Testbenches -# ----------- - -[target.tb_wb_timer] -toolchain = iverilog -runtime = all -toplevel = tb_wb_timer -files_verilog = sim/tb/tb_wb_timer.v - rtl/wb/wb_timer.v - -[target.tb_cdc_strobe_data] -toolchain = iverilog -runtime = all -toplevel = tb_cdc_strobe_data -files_verilog = sim/tb/tb_cdc_strobe_data.v - rtl/core/cdc_strobe_data.v - -[target.tb_jtag_wb_bridge] -toolchain = iverilog -runtime = all -toplevel = tb_jtag_wb_bridge -files_verilog = sim/tb/tb_jtag_wb_bridge.v - rtl/wb/jtag_wb_bridge.v - rtl/core/cdc_req_resp.v - rtl/core/cdc_strobe_data.v - -[target.synth_sim] -toolchain = iverilog -runtime = all -toplevel = tb_top_generic -ivl_opts = -Irtl/util -files_verilog = rtl/toplevel/top_generic.v - rtl/util/conv.vh - rtl/core/nco_q15.v - rtl/core/sigmadelta_sampler.v - rtl/core/sigmadelta_rcmodel_q15.v - rtl/core/sigmadelta_input_q15.v - rtl/core/mul_const.v - rtl/core/lpf_iir_q15_k.v - rtl/core/decimate_by_r_q15.v - rtl/core/mcu_peripherals.v - rtl/core/mcu.v - rtl/core/cdc_strobe_data.v - rtl/core/cdc_req_resp.v - rtl/core/mem_jtag_writable.v - # Arch - rtl/core/lvds_comparator.v - sim/overrides/clk_gen.v - rtl/core/jtag_if.v - # SERV - rtl/serv/serv_aligner.v - rtl/serv/serv_alu.v - rtl/serv/serv_bufreg.v - rtl/serv/serv_bufreg2.v - rtl/serv/serv_compdec.v - rtl/serv/serv_csr.v - rtl/serv/serv_ctrl.v - rtl/serv/serv_debug.v - rtl/serv/serv_decode.v - rtl/serv/serv_immdec.v - rtl/serv/serv_mem_if.v - rtl/serv/serv_rf_if.v - rtl/serv/serv_rf_ram_if.v - rtl/serv/serv_rf_ram.v - rtl/serv/serv_state.v - rtl/serv/serv_rf_top.v - rtl/serv/serv_synth_wrapper.v - rtl/serv/serv_top.v - # QERV - # rtl/qerv/serv_rf_top.v - # rtl/qerv/serv_synth_wrapper.v - # rtl/qerv/serv_top.v - # rtl/qerv/qerv_immdec.v - # Servile - rtl/serv/servile_arbiter.v - rtl/serv/servile_mux.v - rtl/serv/servile_rf_mem_if.v - rtl/serv/servile.v - # rtl/qerv/servile_arbiter.v - # rtl/qerv/servile_mux.v - # rtl/qerv/servile_rf_mem_if.v - # rtl/qerv/servile.v - # WB - rtl/wb/wb_gpio.v - rtl/wb/wb_gpio_banks.v - rtl/wb/wb_mux.v - rtl/wb/jtag_wb_bridge.v - rtl/wb/wb_timer.v - - sim/tb/tb_top_generic.v - -files_con = boards/mimas_v1/constraints.ucf -files_other = rtl/util/rc_alpha_q15.vh - rtl/util/clog2.vh - rtl/util/conv.vh - sw/sweep/sweep.hex - - -# Synth targets -# ------------- - -[target.synth] -toolchain = ISE -ise_settings = /opt/Xilinx/14.7/ISE_DS/settings64.sh -family = spartan6 -device = xc6slx9 -package = tqg144 -speedgrade = -2 -toplevel = top_generic -xst_opts = -vlgincdir rtl/util -keep_hierarchy yes -files_verilog = rtl/toplevel/top_generic.v - rtl/util/conv.vh - rtl/core/nco_q15.v - rtl/core/sigmadelta_sampler.v - rtl/core/sigmadelta_rcmodel_q15.v - rtl/core/sigmadelta_input_q15.v - rtl/core/mul_const.v - rtl/core/lpf_iir_q15_k.v - rtl/core/decimate_by_r_q15.v - rtl/core/mcu_peripherals.v - rtl/core/cdc_strobe_data.v - rtl/core/cdc_req_resp.v - rtl/core/mcu.v - rtl/core/arbiter.v - rtl/core/mem_jtag_writable.v - # Arch - rtl/arch/spartan-6/lvds_comparator.v - rtl/arch/spartan-6/clk_gen.v - rtl/arch/spartan-6/jtag_if.v - # SERV - rtl/serv/serv_aligner.v - rtl/serv/serv_alu.v - rtl/serv/serv_bufreg.v - rtl/serv/serv_bufreg2.v - rtl/serv/serv_compdec.v - rtl/serv/serv_csr.v - rtl/serv/serv_ctrl.v - rtl/serv/serv_debug.v - rtl/serv/serv_decode.v - rtl/serv/serv_immdec.v - rtl/serv/serv_mem_if.v - rtl/serv/serv_rf_if.v - rtl/serv/serv_rf_ram_if.v - rtl/serv/serv_rf_ram.v - rtl/serv/serv_state.v - rtl/serv/serv_rf_top.v - rtl/serv/serv_synth_wrapper.v - rtl/serv/serv_top.v - rtl/serv/serving_ram.v - # QERV - # rtl/qerv/serv_rf_top.v - # rtl/qerv/serv_synth_wrapper.v - # rtl/qerv/serv_top.v - # rtl/qerv/qerv_immdec.v - # Servile - rtl/serv/servile_arbiter.v - rtl/serv/servile_mux.v - rtl/serv/servile_rf_mem_if.v - rtl/serv/servile.v - # rtl/qerv/servile_arbiter.v - # rtl/qerv/servile_mux.v - # rtl/qerv/servile_rf_mem_if.v - # rtl/qerv/servile.v - # WB - rtl/wb/wb_gpio.v - rtl/wb/wb_gpio_banks.v - rtl/wb/wb_mux.v - rtl/wb/wb_arbiter.v - rtl/wb/jtag_wb_bridge.v - rtl/wb/wb_timer.v - -files_con = boards/mimas_v1/constraints.ucf -files_other = rtl/util/rc_alpha_q15.vh - rtl/util/clog2.vh - sw/sweep/sweep.hex - -[target.jtag] -toolchain = ISE -ise_settings = /opt/Xilinx/14.7/ISE_DS/settings64.sh -family = spartan6 -device = xc6slx9 -package = tqg144 -speedgrade = -2 -toplevel = top_jtag -xst_opts = -vlgincdir rtl/util -keep_hierarchy yes -files_other = -files_con = boards/mimas_v1/constraints.ucf -files_verilog = rtl/arch/spartan-6/jtag_if.v - rtl/arch/spartan-6/clk_gen.v - rtl/core/cdc_strobe_data.v - rtl/core/cdc_req_resp.v - rtl/wb/jtag_wb_bridge.v - rtl/wb/wb_gpio.v - rtl/toplevel/top_jtag.v diff --git a/rtl/arch/gw1/lvds_comparator.v b/rtl/arch/gw1/lvds_comparator.v deleted file mode 100644 index 8424b20..0000000 --- a/rtl/arch/gw1/lvds_comparator.v +++ /dev/null @@ -1,17 +0,0 @@ -`timescale 1ns/1ps - -// ============================================================================= -// LVDS comparator -// Instantiating a GW1 TLVDS_IBUF -// ============================================================================= -module lvds_comparator( - input wire a, - input wire b, - output wire o -); - TLVDS_IBUF lvds_buf ( - .O(o), - .I(a), - .IB(b) - ); -endmodule \ No newline at end of file diff --git a/rtl/arch/spartan-6/clk_gen.v b/rtl/arch/spartan-6/clk_gen.v deleted file mode 100755 index 5eee15d..0000000 --- a/rtl/arch/spartan-6/clk_gen.v +++ /dev/null @@ -1,148 +0,0 @@ -// file: clk_gen.v -// -// (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved. -// -// This file contains confidential and proprietary information -// of Xilinx, Inc. and is protected under U.S. and -// international copyright and other intellectual property -// laws. -// -// DISCLAIMER -// This disclaimer is not a license and does not grant any -// rights to the materials distributed herewith. Except as -// otherwise provided in a valid license issued to you by -// Xilinx, and to the maximum extent permitted by applicable -// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND -// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES -// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING -// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- -// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and -// (2) Xilinx shall not be liable (whether in contract or tort, -// including negligence, or under any other theory of -// liability) for any loss or damage of any kind or nature -// related to, arising under or in connection with these -// materials, including for any direct, or any indirect, -// special, incidental, or consequential loss or damage -// (including loss of data, profits, goodwill, or any type of -// loss or damage suffered as a result of any action brought -// by a third party) even if such damage or loss was -// reasonably foreseeable or Xilinx had been advised of the -// possibility of the same. -// -// CRITICAL APPLICATIONS -// Xilinx products are not designed or intended to be fail- -// safe, or for use in any application requiring fail-safe -// performance, such as life-support or safety devices or -// systems, Class III medical devices, nuclear facilities, -// applications related to the deployment of airbags, or any -// other applications that could lead to death, personal -// injury, or severe property or environmental damage -// (individually and collectively, "Critical -// Applications"). Customer assumes the sole risk and -// liability of any use of Xilinx products in Critical -// Applications, subject only to applicable laws and -// regulations governing limitations on product liability. -// -// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS -// PART OF THIS FILE AT ALL TIMES. -// -//---------------------------------------------------------------------------- -// User entered comments -//---------------------------------------------------------------------------- -// None -// -//---------------------------------------------------------------------------- -// "Output Output Phase Duty Pk-to-Pk Phase" -// "Clock Freq (MHz) (degrees) Cycle (%) Jitter (ps) Error (ps)" -//---------------------------------------------------------------------------- -// CLK_OUT1____15.000______0.000______50.0_____1533.333____150.000 -// -//---------------------------------------------------------------------------- -// "Input Clock Freq (MHz) Input Jitter (UI)" -//---------------------------------------------------------------------------- -// __primary_________100.000____________0.010 - -`timescale 1ps/1ps - -(* CORE_GENERATION_INFO = "clk_gen,clk_wiz_v3_6,{component_name=clk_gen,use_phase_alignment=true,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,feedback_source=FDBK_AUTO,primtype_sel=DCM_SP,num_out_clk=1,clkin1_period=10.0,clkin2_period=10.0,use_power_down=false,use_reset=false,use_locked=false,use_inclk_stopped=false,use_status=false,use_freeze=false,use_clk_valid=false,feedback_type=SINGLE,clock_mgr_type=AUTO,manual_override=false}" *) -module clk_gen - (// Clock in ports - input wire clk_in, - // Clock out ports - output wire clk_out_15 - ); - - // Input buffering - //------------------------------------ - // BUFG clkin1_buf - // (.O (clkin1), - // .I (clk_in)); - - wire clkin1; - assign clkin1 = clk_in; - - // Clocking primitive - //------------------------------------ - - // Instantiation of the DCM primitive - // * Unused inputs are tied off - // * Unused outputs are labeled unused - wire psdone_unused; - wire locked_int; - wire [7:0] status_int; - wire clkfb; - wire clk0; - wire clkfx; - - DCM_SP - #(.CLKDV_DIVIDE (2.000), - .CLKFX_DIVIDE (20), - .CLKFX_MULTIPLY (3), - .CLKIN_DIVIDE_BY_2 ("FALSE"), - .CLKIN_PERIOD (10.0), - .CLKOUT_PHASE_SHIFT ("NONE"), - .CLK_FEEDBACK ("1X"), - .DESKEW_ADJUST ("SYSTEM_SYNCHRONOUS"), - .PHASE_SHIFT (0), - .STARTUP_WAIT ("FALSE")) - dcm_sp_inst - // Input clock - (.CLKIN (clkin1), - .CLKFB (clkfb), - // Output clocks - .CLK0 (clk0), - .CLK90 (), - .CLK180 (), - .CLK270 (), - .CLK2X (), - .CLK2X180 (), - .CLKFX (clkfx), - .CLKFX180 (), - .CLKDV (), - // Ports for dynamic phase shift - .PSCLK (1'b0), - .PSEN (1'b0), - .PSINCDEC (1'b0), - .PSDONE (), - // Other control and status signals - .LOCKED (locked_int), - .STATUS (status_int), - .RST (1'b0), - // Unused pin- tie low - .DSSEN (1'b0)); - - - // Output buffering - //----------------------------------- - BUFG clkf_buf - (.O (clkfb), - .I (clk0)); - - BUFG clkout1_buf - (.O (clk_out_15), - .I (clkfx)); - - - - -endmodule diff --git a/rtl/arch/spartan-6/lvds_comparator.v b/rtl/arch/spartan-6/lvds_comparator.v deleted file mode 100644 index 844b544..0000000 --- a/rtl/arch/spartan-6/lvds_comparator.v +++ /dev/null @@ -1,20 +0,0 @@ -`timescale 1ns/1ps - -// ============================================================================= -// LVDS comparator -// Instantiating a spartan-6 IBUFDS -// ============================================================================= -module lvds_comparator( - input wire a, - input wire b, - output wire o -); - IBUFDS #( - .DIFF_TERM("FALSE"), - .IOSTANDARD("LVDS33") - ) lvds_buf ( - .O(o), - .I(a), - .IB(b) - ); -endmodule \ No newline at end of file diff --git a/rtl/core/clk_gen.v b/rtl/core/clk_gen.v deleted file mode 100644 index 5b647d7..0000000 --- a/rtl/core/clk_gen.v +++ /dev/null @@ -1,12 +0,0 @@ -`timescale 1ns/1ps - -// ============================================================================= -// Clock generator/PLL -// Simple pass through -// ============================================================================= -module clk_gen( - input wire clk_in, - output wire clk_out_15 -); - assign clk_out_15 = clk_in; -endmodule diff --git a/rtl/core/lvds_comparator.v b/rtl/core/lvds_comparator.v deleted file mode 100644 index e60285f..0000000 --- a/rtl/core/lvds_comparator.v +++ /dev/null @@ -1,13 +0,0 @@ -`timescale 1ns/1ps - -// ============================================================================= -// LVDS comparator -// Simple pass-though model -// ============================================================================= -module lvds_comparator( - input wire a, - input wire b, - output wire o -); - assign o = a; -endmodule \ No newline at end of file diff --git a/rtl/core/mem_jtag_writable.v b/rtl/core/mem_jtag_writable.v deleted file mode 100644 index 2ef2ce5..0000000 --- a/rtl/core/mem_jtag_writable.v +++ /dev/null @@ -1,91 +0,0 @@ -`timescale 1ns/1ps - -module memory_jtag #( - parameter memfile = "", - parameter depth = 256, - parameter sim = 1'b0, - parameter aw = `CLOG2(depth) - )( - input wire i_clk, - input wire i_rst, - input wire [aw-1:0] i_waddr, - input wire [7:0] i_wdata, - input wire i_wen, - input wire [aw-1:0] i_raddr, - output reg [7:0] o_rdata, - output wire o_core_reset -); - // The actual memory - reg [7:0] mem [0:depth-1]; - wire [aw-1:0] mem_adr; - assign mem_adr = (i_wen==1'b1) ? i_waddr : - i_raddr; - - // Second port wishbone - wire [31:0] wb_adr; - wire [31:0] wb_dat; - reg [31:0] wb_rdt; - wire [3:0] wb_sel; - wire wb_cyc; - wire wb_we; - wire wb_stb; - reg wb_ack; - reg wb_req_d; - wire cmd_reset; - // Driven by JTAG - jtag_wb_bridge #( - .chain(1), - .byte_aligned(1) - ) jtag_wb ( - .i_clk(i_clk), - .i_rst(i_rst), - - .o_wb_adr(wb_adr), - .o_wb_dat(wb_dat), - .o_wb_sel(wb_sel), - .o_wb_we(wb_we), - .o_wb_cyc(wb_cyc), - .o_wb_stb(wb_stb), - .i_wb_rdt(wb_rdt), - .i_wb_ack(wb_ack), - .o_cmd_reset(cmd_reset) - ); - - assign o_core_reset = cmd_reset; - - // Read/Write - always @(posedge i_clk) begin - if (i_rst) begin - wb_req_d <= 1'b0; - wb_ack <= 1'b0; - wb_rdt <= 32'h00000000; - o_rdata <= 32'h00000000; - end else begin - if (i_wen) - mem[mem_adr] <= i_wdata; - o_rdata <= mem[mem_adr]; - - wb_req_d <= wb_stb && wb_cyc; - wb_ack <= wb_req_d; - if (wb_we && wb_stb && wb_cyc) - mem[wb_adr[aw-1:0]] <= wb_dat[7:0]; - wb_rdt <= {24'h000000, mem[wb_adr[aw-1:0]]}; - end - end - - // Preload memory - integer i; - initial begin - if(sim==1'b1) begin - for (i = 0; i < depth; i = i + 1) - mem[i] = 8'h00; - end - if(|memfile) begin - $display("Preloading %m from %s", memfile); - $readmemh(memfile, mem); - end - end - - - -endmodule diff --git a/rtl/core/mul_const.v b/rtl/core/mul_const.v deleted file mode 100644 index 06dc8ce..0000000 --- a/rtl/core/mul_const.v +++ /dev/null @@ -1,71 +0,0 @@ -`timescale 1ns/1ps - -// ============================================================================= -// Multiply a value by a constant -// Use a shift-add algorithm instead of a multiplier -// parameters: -// -- W : data width -// -- C : constant -// inout: -// -- x : input of width W -// -- y : output of widht 2W -// ============================================================================= -module mul_const_shiftadd#( - parameter integer W = 16, - parameter integer C = 16'sh7fff -)( - input wire signed [W-1:0] x, - output wire signed [2*W-1:0] y -); - // Sign and magnitude of constant - localparam integer C_NEG = (C < 0) ? 1 : 0; - localparam integer C_ABS = (C < 0) ? -C : C; - - // MSB index of |C| (0-based). Keeps network minimal. - function integer msb_index; - input integer v; - integer i; - begin - msb_index = -1; - for (i = 0; i < 32; i = i + 1) - if (v >> i) msb_index = i; - end - endfunction - - localparam integer I_MAX = (C_ABS == 0) ? 0 : msb_index(C_ABS); - - // Width big enough for the largest partial product: W bits shifted by I_MAX - localparam integer PPW = W + I_MAX + 1; - - // Pre-extend x to PPW so shifts don’t truncate high/sign bits - wire signed [PPW-1:0] x_ext = {{(PPW-W){x[W-1]}}, x}; - - // Partial products (only where C’s bit is 1) - wire signed [PPW-1:0] part [0:I_MAX]; - genvar i; - generate - for (i = 0; i <= I_MAX; i = i + 1) begin : GEN_PARTS - assign part[i] = C_ABS[i] ? (x_ext <<< i) : {PPW{1'b0}}; - end - endgenerate - - // Adder chain (you can replace with a balanced tree for speed) - wire signed [PPW-1:0] sum [0:I_MAX]; - generate - if (I_MAX == 0) begin - assign sum[0] = part[0]; - end else begin - assign sum[0] = part[0]; - for (i = 1; i <= I_MAX; i = i + 1) begin : GEN_SUM - assign sum[i] = sum[i-1] + part[i]; - end - end - endgenerate - - // Apply sign of C - wire signed [PPW-1:0] mag = (I_MAX == 0) ? part[0] : sum[I_MAX]; - wire signed [PPW-1:0] prod = C_NEG ? -mag : mag; - - // Stretch/extend to 2W result width - assign y = {{((2*W)-PPW){prod[PPW-1]}}, prod}; -endmodule \ No newline at end of file diff --git a/rtl/core/nco_q15.v b/rtl/core/nco_q15.v deleted file mode 100644 index df60955..0000000 --- a/rtl/core/nco_q15.v +++ /dev/null @@ -1,163 +0,0 @@ -`timescale 1ns/1ps - -// ============================================================================= -// Small number controlled oscillator -// Generates a sine and cosine and uses no multiplications, just some logic and -// a 64-entry LUT. It outputs Q15 data (but the LUT is 8 bits wide) -// params: -// -- CLK_HZ : input clock frequency in Hz -// -- FS_HZ : output sample frequency in Hz -// inout: -// -- clk : input clock -// -- rst_n : reset -// -- freq_hz : decimal number of desired generated frequency in Hz, 0-FS/2 -// -- sin_q15/cos_q15 : I and Q outputs -// -- clk_en : output valid strobe -// ============================================================================= -module nco_q15 #( - parameter integer CLK_HZ = 120_000_000, // input clock - parameter integer FS_HZ = 40_000 // sample rate -)( - input wire clk, // CLK_HZ domain - input wire rst_n, // async active-low reset - input wire [31:0] freq_hz, // desired output frequency (Hz), 0..FS_HZ/2 - - output reg signed [15:0] sin_q15, // Q1.15 sine - output reg signed [15:0] cos_q15, // Q1.15 cosine - output reg clk_en // 1-cycle strobe @ FS_HZ -); - localparam integer PHASE_FRAC_BITS = 6; - localparam integer QTR_ADDR_BITS = 6; - localparam integer PHASE_BITS = 2 + QTR_ADDR_BITS + PHASE_FRAC_BITS; - localparam integer DIV = CLK_HZ / FS_HZ; - localparam integer SHIFT = 32; - - // Fixed-point reciprocal (constant): RECIP = round( (2^PHASE_BITS * 2^SHIFT) / FS_HZ ) - localparam [63:0] RECIP = ( ((64'd1 << PHASE_BITS) << SHIFT) + (FS_HZ/2) ) / FS_HZ; - - // Sample-rate tick - function integer clog2; - input integer v; integer r; begin r=0; v=v-1; while (v>0) begin v=v>>1; r=r+1; end clog2=r; end - endfunction - - reg [clog2(DIV)-1:0] tick_cnt; - always @(posedge clk or negedge rst_n) begin - if (!rst_n) begin tick_cnt <= 0; clk_en <= 1'b0; end - else begin - clk_en <= 1'b0; - if (tick_cnt == DIV-1) begin tick_cnt <= 0; clk_en <= 1'b1; end - else tick_cnt <= tick_cnt + 1'b1; - end - end - - // 32-cycle shift–add multiply: prod = freq_hz * RECIP (no multiplications themself) - // Starts at clk_en, finishes in 32 cycles (<< available cycles per sample). - reg mul_busy; - reg [5:0] mul_i; // 0..31 - reg [31:0] f_reg; - reg [95:0] acc; // accumulator for product (32x64 -> 96b) - - wire [95:0] recip_shift = {{32{1'b0}}, RECIP} << mul_i; // shift constant by i - - always @(posedge clk or negedge rst_n) begin - if (!rst_n) begin - mul_busy <= 1'b0; mul_i <= 6'd0; f_reg <= 32'd0; acc <= 96'd0; - end else begin - if (clk_en && !mul_busy) begin - // kick off a new multiply this sample - mul_busy <= 1'b1; - mul_i <= 6'd0; - f_reg <= (freq_hz > (FS_HZ>>1)) ? (FS_HZ>>1) : freq_hz; // clamp to Nyquist - acc <= 96'd0; - end else if (mul_busy) begin - // add shifted RECIP if bit is set - if (f_reg[mul_i]) acc <= acc + recip_shift; - // next bit - if (mul_i == 6'd31) begin - mul_busy <= 1'b0; // done in 32 cycles - end - mul_i <= mul_i + 6'd1; - end - end - end - - // Rounding shift to get FTW; latch when multiply finishes. - reg [PHASE_BITS-1:0] ftw_q; - wire [95:0] acc_round = acc + (96'd1 << (SHIFT-1)); - wire [PHASE_BITS-1:0] ftw_next = acc_round[SHIFT +: PHASE_BITS]; // >> SHIFT - - always @(posedge clk or negedge rst_n) begin - if (!rst_n) ftw_q <= {PHASE_BITS{1'b0}}; - else if (!mul_busy) ftw_q <= ftw_next; // update once product ready - end - - // Phase accumulator (advance at FS_HZ) - reg [PHASE_BITS-1:0] phase; - always @(posedge clk or negedge rst_n) begin - if (!rst_n) phase <= {PHASE_BITS{1'b0}}; - else if (clk_en) phase <= phase + ftw_q; - end - - // Cosine phase = sine phase + 90° - wire [PHASE_BITS-1:0] phase_cos = phase + ({{(PHASE_BITS-2){1'b0}}, 2'b01} << (PHASE_BITS-2)); - - // Quadrant & LUT index - wire [1:0] q_sin = phase [PHASE_BITS-1 -: 2]; - wire [1:0] q_cos = phase_cos[PHASE_BITS-1 -: 2]; - - wire [QTR_ADDR_BITS-1:0] idx_sin_raw = phase [PHASE_BITS-3 -: QTR_ADDR_BITS]; - wire [QTR_ADDR_BITS-1:0] idx_cos_raw = phase_cos[PHASE_BITS-3 -: QTR_ADDR_BITS]; - - wire [QTR_ADDR_BITS-1:0] idx_sin = q_sin[0] ? ({QTR_ADDR_BITS{1'b1}} - idx_sin_raw) : idx_sin_raw; - wire [QTR_ADDR_BITS-1:0] idx_cos = q_cos[0] ? ({QTR_ADDR_BITS{1'b1}} - idx_cos_raw) : idx_cos_raw; - - // 64-entry quarter-wave LUT - wire [7:0] mag_sin_u8, mag_cos_u8; - sine_qtr_lut64 u_lut_s (.addr(idx_sin), .dout(mag_sin_u8)); - sine_qtr_lut64 u_lut_c (.addr(idx_cos), .dout(mag_cos_u8)); - - // Scale to Q1.15 and apply sign - wire signed [15:0] mag_sin_q15 = {1'b0, mag_sin_u8, 7'd0}; - wire signed [15:0] mag_cos_q15 = {1'b0, mag_cos_u8, 7'd0}; - wire sin_neg = (q_sin >= 2); - wire cos_neg = (q_cos >= 2); - - wire signed [15:0] sin_next = sin_neg ? -mag_sin_q15 : mag_sin_q15; - wire signed [15:0] cos_next = cos_neg ? -mag_cos_q15 : mag_cos_q15; - - always @(posedge clk or negedge rst_n) begin - if (!rst_n) begin - sin_q15 <= 16'sd0; cos_q15 <= 16'sd0; - end else if (clk_en) begin - sin_q15 <= sin_next; cos_q15 <= cos_next; - end - end - -endmodule - -module sine_qtr_lut64( - input wire [5:0] addr, - output reg [7:0] dout -); - always @* begin - case (addr) - 6'd0: dout = 8'd0; 6'd1: dout = 8'd6; 6'd2: dout = 8'd13; 6'd3: dout = 8'd19; - 6'd4: dout = 8'd25; 6'd5: dout = 8'd31; 6'd6: dout = 8'd37; 6'd7: dout = 8'd44; - 6'd8: dout = 8'd50; 6'd9: dout = 8'd56; 6'd10: dout = 8'd62; 6'd11: dout = 8'd68; - 6'd12: dout = 8'd74; 6'd13: dout = 8'd80; 6'd14: dout = 8'd86; 6'd15: dout = 8'd92; - 6'd16: dout = 8'd98; 6'd17: dout = 8'd103; 6'd18: dout = 8'd109; 6'd19: dout = 8'd115; - 6'd20: dout = 8'd120; 6'd21: dout = 8'd126; 6'd22: dout = 8'd131; 6'd23: dout = 8'd136; - 6'd24: dout = 8'd142; 6'd25: dout = 8'd147; 6'd26: dout = 8'd152; 6'd27: dout = 8'd157; - 6'd28: dout = 8'd162; 6'd29: dout = 8'd167; 6'd30: dout = 8'd171; 6'd31: dout = 8'd176; - 6'd32: dout = 8'd180; 6'd33: dout = 8'd185; 6'd34: dout = 8'd189; 6'd35: dout = 8'd193; - 6'd36: dout = 8'd197; 6'd37: dout = 8'd201; 6'd38: dout = 8'd205; 6'd39: dout = 8'd208; - 6'd40: dout = 8'd212; 6'd41: dout = 8'd215; 6'd42: dout = 8'd219; 6'd43: dout = 8'd222; - 6'd44: dout = 8'd225; 6'd45: dout = 8'd228; 6'd46: dout = 8'd231; 6'd47: dout = 8'd233; - 6'd48: dout = 8'd236; 6'd49: dout = 8'd238; 6'd50: dout = 8'd240; 6'd51: dout = 8'd242; - 6'd52: dout = 8'd244; 6'd53: dout = 8'd246; 6'd54: dout = 8'd247; 6'd55: dout = 8'd249; - 6'd56: dout = 8'd250; 6'd57: dout = 8'd251; 6'd58: dout = 8'd252; 6'd59: dout = 8'd253; - 6'd60: dout = 8'd254; 6'd61: dout = 8'd254; 6'd62: dout = 8'd255; 6'd63: dout = 8'd255; - default: dout=8'd0; - endcase - end -endmodule \ No newline at end of file diff --git a/rtl/core/sigmadelta_input_q15.v b/rtl/core/sigmadelta_input_q15.v deleted file mode 100644 index f6e8c37..0000000 --- a/rtl/core/sigmadelta_input_q15.v +++ /dev/null @@ -1,58 +0,0 @@ -`timescale 1ns/1ps - -module sigmadelta_input #( - parameter integer R_OHM = 3300, - parameter integer C_PF = 220 -)( - input wire clk_15, - input wire resetn, - - input wire adc_a, - input wire adc_b, - output wire adc_o, - - output wire signed [15:0] signal_q15, - output wire signal_valid -); - `include "rc_alpha_q15.vh" - - wire sd_signal; - wire signed [15:0] raw_sample_q15; - wire signed [15:0] lpf_sample_q15; - - sigmadelta_sampler sd_sampler( - .clk(clk_15), - .a(adc_a), .b(adc_b), - .o(sd_signal) - ); - assign adc_o = sd_signal; - - localparam integer alpha_q15_int = alpha_q15_from_rc(R_OHM, C_PF, 15000000); - localparam signed [15:0] alpha_q15 = alpha_q15_int[15:0]; - localparam signed [15:0] alpha_q15_top = alpha_q15 & 16'hff00; - sigmadelta_rcmodel_q15 #( - .alpha_q15(alpha_q15_top) - ) rc_model ( - .clk(clk_15), .resetn(resetn), - .sd_sample(sd_signal), - .sample_q15(raw_sample_q15) - ); - - lpf_iir_q15_k #( - .K(10) - ) lpf ( - .clk(clk_15), .rst_n(resetn), - .x_q15(raw_sample_q15), - .y_q15(lpf_sample_q15) - ); - - decimate_by_r_q15 #( - .R(375), // 15MHz/375 = 40KHz - .CNT_W(10) - ) decimate ( - .clk(clk_15), .rst_n(resetn), - .in_valid(1'b1), .in_q15(lpf_sample_q15), - .out_valid(signal_valid), .out_q15(signal_q15) - ); - -endmodule diff --git a/rtl/core/sigmadelta_sampler.v b/rtl/core/sigmadelta_sampler.v deleted file mode 100644 index 0c0c4c1..0000000 --- a/rtl/core/sigmadelta_sampler.v +++ /dev/null @@ -1,23 +0,0 @@ -`timescale 1ns/1ps - -// ============================================================================= -// Sigma-Delta sampler -// Samples A>B at clk -// ============================================================================= -module sigmadelta_sampler( - input wire clk, - input wire a, - input wire b, - output wire o -); - - wire comp_out; - lvds_comparator comp ( - .a(a), .b(b), .o(comp_out) - ); - - reg registered_comp_out; - always @(posedge clk) registered_comp_out <= comp_out; - assign o = registered_comp_out; - -endmodule \ No newline at end of file diff --git a/rtl/qerv/LICENSE b/rtl/qerv/LICENSE deleted file mode 100644 index 8572ea0..0000000 --- a/rtl/qerv/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -ISC License - -Copyright 2019, Olof Kindgren - -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/rtl/qerv/qerv_immdec.v b/rtl/qerv/qerv_immdec.v deleted file mode 100644 index 7405775..0000000 --- a/rtl/qerv/qerv_immdec.v +++ /dev/null @@ -1,152 +0,0 @@ -// SPDX-License-Identifier: ISC -`default_nettype none -module qerv_immdec - ( - input wire i_clk, - //State - input wire i_cnt_en, - input wire i_cnt_done, - //Control - input wire [3:0] i_immdec_en, - input wire i_csr_imm_en, - input wire [3:0] i_ctrl, - output wire [4:0] o_rd_addr, - output wire [4:0] o_rs1_addr, - output wire [4:0] o_rs2_addr, - //Data - output wire [3:0] o_csr_imm, - output wire [3:0] o_imm, - //External - input wire i_wb_en, - input wire [31:7] i_wb_rdt); - - reg [4:0] rd_addr; - reg [4:0] rs1_addr; - reg [4:0] rs2_addr; - - reg i31; - reg i30; - reg i29; - reg i28; - reg i27; - reg i26; - reg i25; - reg i24; - reg i23; - reg i22; - reg i21; - reg i20; - reg i19; - reg i18; - reg i17; - reg i16; - reg i15; - reg i14; - reg i13; - reg i12; - reg i11; - reg i10; - reg i9; - reg i8; - reg i7; - - reg i7_2; - reg i20_2; - - wire signbit = i31 & !i_csr_imm_en; - - assign o_csr_imm[3] = i18; - assign o_csr_imm[2] = i17; - assign o_csr_imm[1] = i16; - assign o_csr_imm[0] = i15; - - assign o_rd_addr = rd_addr; - assign o_rs1_addr = rs1_addr; - assign o_rs2_addr = rs2_addr; - always @(posedge i_clk) begin - if (i_wb_en) begin - //Common - i31 <= i_wb_rdt[31]; - - //Bit lane 3 - i19 <= i_wb_rdt[19]; - i15 <= i_wb_rdt[15]; - i20 <= i_wb_rdt[20]; - i7 <= i_wb_rdt[7]; - i27 <= i_wb_rdt[27]; - i23 <= i_wb_rdt[23]; - i10 <= i_wb_rdt[10]; - - //Bit lane 2 - i22 <= i_wb_rdt[22]; - i9 <= i_wb_rdt[ 9]; - i26 <= i_wb_rdt[26]; - i30 <= i_wb_rdt[30]; - i14 <= i_wb_rdt[14]; - i18 <= i_wb_rdt[18]; - - //Bit lane 1 - i21 <= i_wb_rdt[21]; - i8 <= i_wb_rdt[ 8]; - i25 <= i_wb_rdt[25]; - i29 <= i_wb_rdt[29]; - i13 <= i_wb_rdt[13]; - i17 <= i_wb_rdt[17]; - - //Bit lane 0 - i11 <= i_wb_rdt[11]; - i7_2 <= i_wb_rdt[7 ]; - i20_2 <= i_wb_rdt[20]; - i24 <= i_wb_rdt[24]; - i28 <= i_wb_rdt[28]; - i12 <= i_wb_rdt[12]; - i16 <= i_wb_rdt[16]; - - rd_addr <= i_wb_rdt[11:7]; - rs1_addr <= i_wb_rdt[19:15]; - rs2_addr <= i_wb_rdt[24:20]; - end - if (i_cnt_en) begin - //Bit lane 3 - i10 <= i27; - i23 <= i27; - i27 <= i_ctrl[2] ? i7 : i_ctrl[1] ? signbit : i20; - i7 <= signbit; - i20 <= i15; - i15 <= i19; - i19 <= i_ctrl[3] ? signbit : i23; - - //Bit lane 2 - i22 <= i26; - i9 <= i26; - i26 <= i30; - i30 <= (i_ctrl[1] | i_ctrl[2]) ? signbit : i14; - i14 <= i18; - i18 <= i_ctrl[3] ? signbit : i22; - - //Bit lane 1 - i21 <= i25; - i8 <= i25; - i25 <= i29; - i29 <= (i_ctrl[1] | i_ctrl[2]) ? signbit : i13; - i13 <= i17; - i17 <= i_ctrl[3] ? signbit : i21; - - //Bit lane 0 - i7_2 <= i11; - i11 <= i28; - i20_2 <= i24; - i24 <= i28; - i28 <= (i_ctrl[1] | i_ctrl[2]) ? signbit : i12; - i12 <= i16; - i16 <= i_ctrl[3] ? signbit : i20_2; - - end - end - - assign o_imm[3] = (i_cnt_done ? signbit : (i_ctrl[0] ? i10 : i23)); - assign o_imm[2] = i_ctrl[0] ? i9 : i22; - assign o_imm[1] = i_ctrl[0] ? i8 : i21; - assign o_imm[0] = i_ctrl[0] ? i7_2 : i20_2; - -endmodule \ No newline at end of file diff --git a/rtl/qerv/serv_rf_top.v b/rtl/qerv/serv_rf_top.v deleted file mode 100644 index 169698e..0000000 --- a/rtl/qerv/serv_rf_top.v +++ /dev/null @@ -1,222 +0,0 @@ -`default_nettype none -`include "../util/clog2.vh" - -module qerv_rf_top - #(parameter RESET_PC = 32'd0, - /* COMPRESSED=1: Enable the compressed decoder and allowed misaligned jump of pc - COMPRESSED=0: Disable the compressed decoder and does not allow the misaligned jump of pc - */ - parameter [0:0] COMPRESSED = 0, - /* - ALIGN = 1: Fetch the aligned instruction by making two bus transactions if the misaligned address - is given to the instruction bus. - */ - parameter [0:0] ALIGN = COMPRESSED, - /* Multiplication and Division Unit - This parameter enables the interface for connecting SERV and MDU - */ - parameter [0:0] MDU = 0, - /* Register signals before or after the decoder - 0 : Register after the decoder. Faster but uses more resources - 1 : (default) Register before the decoder. Slower but uses less resources - */ - parameter PRE_REGISTER = 1, - /* Amount of reset applied to design - "NONE" : No reset at all. Relies on a POR to set correct initialization - values and that core isn't reset during runtime - "MINI" : Standard setting. Resets the minimal amount of FFs needed to - restart execution from the instruction at RESET_PC - */ - parameter RESET_STRATEGY = "MINI", - parameter [0:0] DEBUG = 1'b0, - parameter WITH_CSR = 1, - parameter W = 1, - parameter RF_WIDTH = W * 2, - parameter RF_L2D = `CLOG2((32+(WITH_CSR*4))*32/RF_WIDTH)) - ( - input wire clk, - input wire i_rst, - input wire i_timer_irq, -`ifdef RISCV_FORMAL - output wire rvfi_valid, - output wire [63:0] rvfi_order, - output wire [31:0] rvfi_insn, - output wire rvfi_trap, - output wire rvfi_halt, - output wire rvfi_intr, - output wire [1:0] rvfi_mode, - output wire [1:0] rvfi_ixl, - output wire [4:0] rvfi_rs1_addr, - output wire [4:0] rvfi_rs2_addr, - output wire [31:0] rvfi_rs1_rdata, - output wire [31:0] rvfi_rs2_rdata, - output wire [4:0] rvfi_rd_addr, - output wire [31:0] rvfi_rd_wdata, - output wire [31:0] rvfi_pc_rdata, - output wire [31:0] rvfi_pc_wdata, - output wire [31:0] rvfi_mem_addr, - output wire [3:0] rvfi_mem_rmask, - output wire [3:0] rvfi_mem_wmask, - output wire [31:0] rvfi_mem_rdata, - output wire [31:0] rvfi_mem_wdata, -`endif - output wire [31:0] o_ibus_adr, - output wire o_ibus_cyc, - input wire [31:0] i_ibus_rdt, - input wire i_ibus_ack, - output wire [31:0] o_dbus_adr, - output wire [31:0] o_dbus_dat, - output wire [3:0] o_dbus_sel, - output wire o_dbus_we , - output wire o_dbus_cyc, - input wire [31:0] i_dbus_rdt, - input wire i_dbus_ack, - - // Extension - output wire [31:0] o_ext_rs1, - output wire [31:0] o_ext_rs2, - output wire [ 2:0] o_ext_funct3, - input wire [31:0] i_ext_rd, - input wire i_ext_ready, - // MDU - output wire o_mdu_valid); - - localparam CSR_REGS = WITH_CSR*4; - - wire rf_wreq; - wire rf_rreq; - wire [4+WITH_CSR:0] wreg0; - wire [4+WITH_CSR:0] wreg1; - wire wen0; - wire wen1; - wire [W-1:0] wdata0; - wire [W-1:0] wdata1; - wire [4+WITH_CSR:0] rreg0; - wire [4+WITH_CSR:0] rreg1; - wire rf_ready; - wire [W-1:0] rdata0; - wire [W-1:0] rdata1; - - wire [RF_L2D-1:0] waddr; - wire [RF_WIDTH-1:0] wdata; - wire wen; - wire [RF_L2D-1:0] raddr; - wire ren; - wire [RF_WIDTH-1:0] rdata; - - serv_rf_ram_if - #(.width (RF_WIDTH), - .reset_strategy (RESET_STRATEGY), - .csr_regs (CSR_REGS), - .W(W)) - rf_ram_if - (.i_clk (clk), - .i_rst (i_rst), - .i_wreq (rf_wreq), - .i_rreq (rf_rreq), - .o_ready (rf_ready), - .i_wreg0 (wreg0), - .i_wreg1 (wreg1), - .i_wen0 (wen0), - .i_wen1 (wen1), - .i_wdata0 (wdata0), - .i_wdata1 (wdata1), - .i_rreg0 (rreg0), - .i_rreg1 (rreg1), - .o_rdata0 (rdata0), - .o_rdata1 (rdata1), - .o_waddr (waddr), - .o_wdata (wdata), - .o_wen (wen), - .o_raddr (raddr), - .o_ren (ren), - .i_rdata (rdata)); - - serv_rf_ram - #(.width (RF_WIDTH), - .csr_regs (CSR_REGS)) - rf_ram - (.i_clk (clk), - .i_waddr (waddr), - .i_wdata (wdata), - .i_wen (wen), - .i_raddr (raddr), - .i_ren (ren), - .o_rdata (rdata)); - - qerv_top - #(.RESET_PC (RESET_PC), - .PRE_REGISTER (PRE_REGISTER), - .RESET_STRATEGY (RESET_STRATEGY), - .WITH_CSR (WITH_CSR), - .DEBUG (DEBUG), - .MDU(MDU), - .COMPRESSED(COMPRESSED), - .ALIGN(ALIGN), - .W(W)) - cpu - ( - .clk (clk), - .i_rst (i_rst), - .i_timer_irq (i_timer_irq), -`ifdef RISCV_FORMAL - .rvfi_valid (rvfi_valid ), - .rvfi_order (rvfi_order ), - .rvfi_insn (rvfi_insn ), - .rvfi_trap (rvfi_trap ), - .rvfi_halt (rvfi_halt ), - .rvfi_intr (rvfi_intr ), - .rvfi_mode (rvfi_mode ), - .rvfi_ixl (rvfi_ixl ), - .rvfi_rs1_addr (rvfi_rs1_addr ), - .rvfi_rs2_addr (rvfi_rs2_addr ), - .rvfi_rs1_rdata (rvfi_rs1_rdata), - .rvfi_rs2_rdata (rvfi_rs2_rdata), - .rvfi_rd_addr (rvfi_rd_addr ), - .rvfi_rd_wdata (rvfi_rd_wdata ), - .rvfi_pc_rdata (rvfi_pc_rdata ), - .rvfi_pc_wdata (rvfi_pc_wdata ), - .rvfi_mem_addr (rvfi_mem_addr ), - .rvfi_mem_rmask (rvfi_mem_rmask), - .rvfi_mem_wmask (rvfi_mem_wmask), - .rvfi_mem_rdata (rvfi_mem_rdata), - .rvfi_mem_wdata (rvfi_mem_wdata), -`endif - .o_rf_rreq (rf_rreq), - .o_rf_wreq (rf_wreq), - .i_rf_ready (rf_ready), - .o_wreg0 (wreg0), - .o_wreg1 (wreg1), - .o_wen0 (wen0), - .o_wen1 (wen1), - .o_wdata0 (wdata0), - .o_wdata1 (wdata1), - .o_rreg0 (rreg0), - .o_rreg1 (rreg1), - .i_rdata0 (rdata0), - .i_rdata1 (rdata1), - - .o_ibus_adr (o_ibus_adr), - .o_ibus_cyc (o_ibus_cyc), - .i_ibus_rdt (i_ibus_rdt), - .i_ibus_ack (i_ibus_ack), - - .o_dbus_adr (o_dbus_adr), - .o_dbus_dat (o_dbus_dat), - .o_dbus_sel (o_dbus_sel), - .o_dbus_we (o_dbus_we), - .o_dbus_cyc (o_dbus_cyc), - .i_dbus_rdt (i_dbus_rdt), - .i_dbus_ack (i_dbus_ack), - - //Extension - .o_ext_funct3 (o_ext_funct3), - .i_ext_ready (i_ext_ready), - .i_ext_rd (i_ext_rd), - .o_ext_rs1 (o_ext_rs1), - .o_ext_rs2 (o_ext_rs2), - //MDU - .o_mdu_valid (o_mdu_valid)); - -endmodule -`default_nettype wire \ No newline at end of file diff --git a/rtl/qerv/serv_synth_wrapper.v b/rtl/qerv/serv_synth_wrapper.v deleted file mode 100644 index 1790961..0000000 --- a/rtl/qerv/serv_synth_wrapper.v +++ /dev/null @@ -1,136 +0,0 @@ -`default_nettype none -`include "../util/clog2.vh" - -module serv_synth_wrapper - #( - /* Register signals before or after the decoder - 0 : Register after the decoder. Faster but uses more resources - 1 : (default) Register before the decoder. Slower but uses less resources - */ - parameter PRE_REGISTER = 1, - /* Amount of reset applied to design - "NONE" : No reset at all. Relies on a POR to set correct initialization - values and that core isn't reset during runtime - "MINI" : Standard setting. Resets the minimal amount of FFs needed to - restart execution from the instruction at RESET_PC - */ - parameter RESET_STRATEGY = "MINI", - parameter WITH_CSR = 1, - parameter RF_WIDTH = 8, - parameter RF_L2D = `CLOG2((32+(WITH_CSR*4))*32/RF_WIDTH)) - ( - input wire clk, - input wire i_rst, - input wire i_timer_irq, - output wire [31:0] o_ibus_adr, - output wire o_ibus_cyc, - input wire [31:0] i_ibus_rdt, - input wire i_ibus_ack, - output wire [31:0] o_dbus_adr, - output wire [31:0] o_dbus_dat, - output wire [3:0] o_dbus_sel, - output wire o_dbus_we , - output wire o_dbus_cyc, - input wire [31:0] i_dbus_rdt, - input wire i_dbus_ack, - - output wire [RF_L2D-1:0] o_waddr, - output wire [RF_WIDTH-1:0] o_wdata, - output wire o_wen, - output wire [RF_L2D-1:0] o_raddr, - input wire [RF_WIDTH-1:0] i_rdata); - - localparam CSR_REGS = WITH_CSR*4; - localparam W = 4; - - wire rf_wreq; - wire rf_rreq; - wire [4+WITH_CSR:0] wreg0; - wire [4+WITH_CSR:0] wreg1; - wire wen0; - wire wen1; - wire [W-1:0] wdata0; - wire [W-1:0] wdata1; - wire [4+WITH_CSR:0] rreg0; - wire [4+WITH_CSR:0] rreg1; - wire rf_ready; - wire [W-1:0] rdata0; - wire [W-1:0] rdata1; - - serv_rf_ram_if - #(.width (RF_WIDTH), - .reset_strategy (RESET_STRATEGY), - .W (W), - .csr_regs (CSR_REGS)) - rf_ram_if - (.i_clk (clk), - .i_rst (i_rst), - .i_wreq (rf_wreq), - .i_rreq (rf_rreq), - .o_ready (rf_ready), - .i_wreg0 (wreg0), - .i_wreg1 (wreg1), - .i_wen0 (wen0), - .i_wen1 (wen1), - .i_wdata0 (wdata0), - .i_wdata1 (wdata1), - .i_rreg0 (rreg0), - .i_rreg1 (rreg1), - .o_rdata0 (rdata0), - .o_rdata1 (rdata1), - .o_waddr (o_waddr), - .o_wdata (o_wdata), - .o_wen (o_wen), - .o_raddr (o_raddr), - .i_rdata (i_rdata)); - - qerv_top - #(.RESET_PC (32'd0), - .PRE_REGISTER (PRE_REGISTER), - .RESET_STRATEGY (RESET_STRATEGY), - .WITH_CSR (WITH_CSR), - .W (W), - .MDU(1'b0)) - cpu - ( - .clk (clk), - .i_rst (i_rst), - .i_timer_irq (i_timer_irq), - .o_rf_rreq (rf_rreq), - .o_rf_wreq (rf_wreq), - .i_rf_ready (rf_ready), - .o_wreg0 (wreg0), - .o_wreg1 (wreg1), - .o_wen0 (wen0), - .o_wen1 (wen1), - .o_wdata0 (wdata0), - .o_wdata1 (wdata1), - .o_rreg0 (rreg0), - .o_rreg1 (rreg1), - .i_rdata0 (rdata0), - .i_rdata1 (rdata1), - - .o_ibus_adr (o_ibus_adr), - .o_ibus_cyc (o_ibus_cyc), - .i_ibus_rdt (i_ibus_rdt), - .i_ibus_ack (i_ibus_ack), - - .o_dbus_adr (o_dbus_adr), - .o_dbus_dat (o_dbus_dat), - .o_dbus_sel (o_dbus_sel), - .o_dbus_we (o_dbus_we), - .o_dbus_cyc (o_dbus_cyc), - .i_dbus_rdt (i_dbus_rdt), - .i_dbus_ack (i_dbus_ack), - - //Extension - .o_ext_funct3 (), - .i_ext_ready (1'b0), - .i_ext_rd (32'd0), - .o_ext_rs1 (), - .o_ext_rs2 (), - //MDU - .o_mdu_valid ()); - -endmodule -`default_nettype wire \ No newline at end of file diff --git a/rtl/qerv/serv_top.v b/rtl/qerv/serv_top.v deleted file mode 100644 index e6f0cab..0000000 --- a/rtl/qerv/serv_top.v +++ /dev/null @@ -1,694 +0,0 @@ -`default_nettype none - -module qerv_top - #(parameter WITH_CSR = 1, - parameter W = 1, - parameter B = W-1, - parameter PRE_REGISTER = 1, - parameter RESET_STRATEGY = "MINI", - parameter RESET_PC = 32'd0, - parameter [0:0] DEBUG = 1'b0, - parameter [0:0] MDU = 1'b0, - parameter [0:0] COMPRESSED=0, - parameter [0:0] ALIGN = COMPRESSED) - ( - input wire clk, - input wire i_rst, - input wire i_timer_irq, -`ifdef RISCV_FORMAL - output wire rvfi_valid, - output wire [63:0] rvfi_order, - output wire [31:0] rvfi_insn, - output wire rvfi_trap, - output wire rvfi_halt, - output wire rvfi_intr, - output wire [1:0] rvfi_mode, - output wire [1:0] rvfi_ixl, - output wire [4:0] rvfi_rs1_addr, - output wire [4:0] rvfi_rs2_addr, - output wire [31:0] rvfi_rs1_rdata, - output wire [31:0] rvfi_rs2_rdata, - output wire [4:0] rvfi_rd_addr, - output wire [31:0] rvfi_rd_wdata, - output wire [31:0] rvfi_pc_rdata, - output wire [31:0] rvfi_pc_wdata, - output wire [31:0] rvfi_mem_addr, - output wire [3:0] rvfi_mem_rmask, - output wire [3:0] rvfi_mem_wmask, - output wire [31:0] rvfi_mem_rdata, - output wire [31:0] rvfi_mem_wdata, -`endif - //RF Interface - output wire o_rf_rreq, - output wire o_rf_wreq, - input wire i_rf_ready, - output wire [4+WITH_CSR:0] o_wreg0, - output wire [4+WITH_CSR:0] o_wreg1, - output wire o_wen0, - output wire o_wen1, - output wire [B:0] o_wdata0, - output wire [B:0] o_wdata1, - output wire [4+WITH_CSR:0] o_rreg0, - output wire [4+WITH_CSR:0] o_rreg1, - input wire [B:0] i_rdata0, - input wire [B:0] i_rdata1, - - output wire [31:0] o_ibus_adr, - output wire o_ibus_cyc, - input wire [31:0] i_ibus_rdt, - input wire i_ibus_ack, - output wire [31:0] o_dbus_adr, - output wire [31:0] o_dbus_dat, - output wire [3:0] o_dbus_sel, - output wire o_dbus_we , - output wire o_dbus_cyc, - input wire [31:0] i_dbus_rdt, - input wire i_dbus_ack, - //Extension - output wire [ 2:0] o_ext_funct3, - input wire i_ext_ready, - input wire [31:0] i_ext_rd, - output wire [31:0] o_ext_rs1, - output wire [31:0] o_ext_rs2, - //MDU - output wire o_mdu_valid); - - wire [4:0] rd_addr; - wire [4:0] rs1_addr; - wire [4:0] rs2_addr; - - wire [3:0] immdec_ctrl; - wire [3:0] immdec_en; - - wire sh_right; - wire bne_or_bge; - wire cond_branch; - wire two_stage_op; - wire e_op; - wire ebreak; - wire branch_op; - wire shift_op; - wire rd_op; - wire mdu_op; - - wire rd_alu_en; - wire rd_csr_en; - wire rd_mem_en; - wire [B:0] ctrl_rd; - wire [B:0] alu_rd; - wire [B:0] mem_rd; - wire [B:0] csr_rd; - wire mtval_pc; - - wire ctrl_pc_en; - wire jump; - wire jal_or_jalr; - wire utype; - wire mret; - wire [B:0] imm; - wire trap; - wire pc_rel; - wire iscomp; - - wire init; - wire cnt_en; - wire cnt0to3; - wire cnt12to31; - wire cnt0; - wire cnt1; - wire cnt2; - wire cnt3; - wire cnt7; - wire cnt11; - wire cnt12; - - wire cnt_done; - - wire bufreg_en; - wire bufreg_sh_signed; - wire bufreg_rs1_en; - wire bufreg_imm_en; - wire bufreg_clr_lsb; - wire [B:0] bufreg_q; - wire [B:0] bufreg2_q; - wire [31:0] dbus_rdt; - wire dbus_ack; - - wire alu_sub; - wire [1:0] alu_bool_op; - wire alu_cmp_eq; - wire alu_cmp_sig; - wire alu_cmp; - wire [2:0] alu_rd_sel; - - wire [B:0] rs1; - wire [B:0] rs2; - wire rd_en; - - wire [B:0] op_b; - wire op_b_sel; - - wire mem_signed; - wire mem_word; - wire mem_half; - wire [1:0] mem_bytecnt; - wire sh_done; - - wire mem_misalign; - - wire [B:0] bad_pc; - - wire csr_mstatus_en; - wire csr_mie_en; - wire csr_mcause_en; - wire [1:0] csr_source; - wire [B:0] csr_imm; - wire csr_d_sel; - wire csr_en; - wire [1:0] csr_addr; - wire [B:0] csr_pc; - wire csr_imm_en; - wire [B:0] csr_in; - wire [B:0] rf_csr_out; - wire dbus_en; - - wire new_irq; - - wire [1:0] lsb; - - //verilator lint_off UNUSED - wire [31:0] i_wb_rdt; - //verilator lint_on UNUSED - - wire [31:0] wb_ibus_adr; - wire wb_ibus_cyc; - wire [31:0] wb_ibus_rdt; - wire wb_ibus_ack; - - generate - if (ALIGN) begin : gen_align - serv_aligner align - ( - .clk(clk), - .rst(i_rst), - // serv_rf_top - .i_ibus_adr(wb_ibus_adr), - .i_ibus_cyc(wb_ibus_cyc), - .o_ibus_rdt(wb_ibus_rdt), - .o_ibus_ack(wb_ibus_ack), - // servant_arbiter - .o_wb_ibus_adr(o_ibus_adr), - .o_wb_ibus_cyc(o_ibus_cyc), - .i_wb_ibus_rdt(i_ibus_rdt), - .i_wb_ibus_ack(i_ibus_ack)); - end else begin : gen_no_align - assign o_ibus_adr = wb_ibus_adr; - assign o_ibus_cyc = wb_ibus_cyc; - assign wb_ibus_rdt = i_ibus_rdt; - assign wb_ibus_ack = i_ibus_ack; - end - endgenerate - - generate - if (COMPRESSED) begin : gen_compressed - serv_compdec compdec - ( - .i_clk(clk), - .i_instr(wb_ibus_rdt), - .i_ack(wb_ibus_ack), - .o_instr(i_wb_rdt), - .o_iscomp(iscomp)); - end else begin : gen_no_compressed - assign i_wb_rdt = wb_ibus_rdt; - assign iscomp = 1'b0; - end - endgenerate - - serv_state - #(.RESET_STRATEGY (RESET_STRATEGY), - .WITH_CSR (WITH_CSR[0:0]), - .MDU(MDU), - .ALIGN(ALIGN), - .W(W)) - state - ( - .i_clk (clk), - .i_rst (i_rst), - //State - .i_new_irq (new_irq), - .i_alu_cmp (alu_cmp), - .o_init (init), - .o_cnt_en (cnt_en), - .o_cnt0to3 (cnt0to3), - .o_cnt12to31 (cnt12to31), - .o_cnt0 (cnt0), - .o_cnt1 (cnt1), - .o_cnt2 (cnt2), - .o_cnt3 (cnt3), - .o_cnt7 (cnt7), - .o_cnt11 (cnt11), - .o_cnt12 (cnt12), - .o_cnt_done (cnt_done), - .o_bufreg_en (bufreg_en), - .o_ctrl_pc_en (ctrl_pc_en), - .o_ctrl_jump (jump), - .o_ctrl_trap (trap), - .i_ctrl_misalign(lsb[1]), - .i_sh_done (sh_done), - .o_mem_bytecnt (mem_bytecnt), - .i_mem_misalign (mem_misalign), - //Control - .i_bne_or_bge (bne_or_bge), - .i_cond_branch (cond_branch), - .i_dbus_en (dbus_en), - .i_two_stage_op (two_stage_op), - .i_branch_op (branch_op), - .i_shift_op (shift_op), - .i_sh_right (sh_right), - .i_alu_rd_sel1 (alu_rd_sel[1]), - .i_rd_alu_en (rd_alu_en), - .i_e_op (e_op), - .i_rd_op (rd_op), - //MDU - .i_mdu_op (mdu_op), - .o_mdu_valid (o_mdu_valid), - //Extension - .i_mdu_ready (i_ext_ready), - //External - .o_dbus_cyc (o_dbus_cyc), - .i_dbus_ack (i_dbus_ack), - .o_ibus_cyc (wb_ibus_cyc), - .i_ibus_ack (wb_ibus_ack), - //RF Interface - .o_rf_rreq (o_rf_rreq), - .o_rf_wreq (o_rf_wreq), - .i_rf_ready (i_rf_ready), - .o_rf_rd_en (rd_en)); - - serv_decode - #(.PRE_REGISTER (PRE_REGISTER), - .MDU(MDU)) - decode - ( - .clk (clk), - //Input - .i_wb_rdt (i_wb_rdt[31:2]), - .i_wb_en (wb_ibus_ack), - //To state - .o_bne_or_bge (bne_or_bge), - .o_cond_branch (cond_branch), - .o_dbus_en (dbus_en), - .o_e_op (e_op), - .o_ebreak (ebreak), - .o_branch_op (branch_op), - .o_shift_op (shift_op), - .o_rd_op (rd_op), - .o_sh_right (sh_right), - .o_mdu_op (mdu_op), - .o_two_stage_op (two_stage_op), - //Extension - .o_ext_funct3 (o_ext_funct3), - - //To bufreg - .o_bufreg_rs1_en (bufreg_rs1_en), - .o_bufreg_imm_en (bufreg_imm_en), - .o_bufreg_clr_lsb (bufreg_clr_lsb), - .o_bufreg_sh_signed (bufreg_sh_signed), - //To bufreg2 - .o_op_b_source (op_b_sel), - //To ctrl - .o_ctrl_jal_or_jalr (jal_or_jalr), - .o_ctrl_utype (utype), - .o_ctrl_pc_rel (pc_rel), - .o_ctrl_mret (mret), - //To alu - .o_alu_sub (alu_sub), - .o_alu_bool_op (alu_bool_op), - .o_alu_cmp_eq (alu_cmp_eq), - .o_alu_cmp_sig (alu_cmp_sig), - .o_alu_rd_sel (alu_rd_sel), - //To mem IF - .o_mem_cmd (o_dbus_we), - .o_mem_signed (mem_signed), - .o_mem_word (mem_word), - .o_mem_half (mem_half), - //To CSR - .o_csr_en (csr_en), - .o_csr_addr (csr_addr), - .o_csr_mstatus_en (csr_mstatus_en), - .o_csr_mie_en (csr_mie_en), - .o_csr_mcause_en (csr_mcause_en), - .o_csr_source (csr_source), - .o_csr_d_sel (csr_d_sel), - .o_csr_imm_en (csr_imm_en), - .o_mtval_pc (mtval_pc ), - //To top - .o_immdec_ctrl (immdec_ctrl), - .o_immdec_en (immdec_en), - //To RF IF - .o_rd_mem_en (rd_mem_en), - .o_rd_csr_en (rd_csr_en), - .o_rd_alu_en (rd_alu_en)); - - generate - if (W == 1) begin : gen_serv_immdec - serv_immdec immdec - ( - .i_clk (clk), - //State - .i_cnt_en (cnt_en), - .i_cnt_done (cnt_done), - //Control - .i_immdec_en (immdec_en), - .i_csr_imm_en (csr_imm_en), - .i_ctrl (immdec_ctrl), - .o_rd_addr (rd_addr), - .o_rs1_addr (rs1_addr), - .o_rs2_addr (rs2_addr), - //Data - .o_csr_imm (csr_imm), - .o_imm (imm), - //External - .i_wb_en (wb_ibus_ack), - .i_wb_rdt (i_wb_rdt[31:7])); - end else if (W == 4) begin : gen_qerv_immdec - qerv_immdec immdec - ( - .i_clk (clk), - //State - .i_cnt_en (cnt_en), - .i_cnt_done (cnt_done), - //Control - .i_immdec_en (immdec_en), - .i_csr_imm_en (csr_imm_en), - .i_ctrl (immdec_ctrl), - .o_rd_addr (rd_addr), - .o_rs1_addr (rs1_addr), - .o_rs2_addr (rs2_addr), - //Data - .o_csr_imm (csr_imm), - .o_imm (imm), - //External - .i_wb_en (wb_ibus_ack), - .i_wb_rdt (i_wb_rdt[31:7])); - end - endgenerate - - serv_bufreg - #(.MDU(MDU), - .W(W)) - bufreg - ( - .i_clk (clk), - //State - .i_cnt0 (cnt0), - .i_cnt1 (cnt1), - .i_cnt_done (cnt_done), - .i_en (bufreg_en), - .i_init (init), - .i_mdu_op (mdu_op), - .o_lsb (lsb), - //Control - .i_sh_signed (bufreg_sh_signed), - .i_rs1_en (bufreg_rs1_en), - .i_imm_en (bufreg_imm_en), - .i_clr_lsb (bufreg_clr_lsb), - .i_shift_op (shift_op), - .i_right_shift_op (sh_right), - .i_shamt (o_dbus_dat[26:24]), - //Data - .i_rs1 (rs1), - .i_imm (imm), - .o_q (bufreg_q), - //External - .o_dbus_adr (o_dbus_adr), - .o_ext_rs1 (o_ext_rs1)); - - serv_bufreg2 #(.W(W)) bufreg2 - ( - .i_clk (clk), - //State - .i_en (cnt_en), - .i_init (init), - .i_cnt7 (cnt7), - .i_cnt_done (cnt_done), - .i_sh_right (sh_right), - .i_lsb (lsb), - .i_bytecnt (mem_bytecnt), - .o_sh_done (sh_done), - //Control - .i_op_b_sel (op_b_sel), - .i_shift_op (shift_op), - //Data - .i_rs2 (rs2), - .i_imm (imm), - .o_op_b (op_b), - .o_q (bufreg2_q), - //External - .o_dat (o_dbus_dat), - .i_load (dbus_ack), - .i_dat (dbus_rdt)); - - serv_ctrl - #(.RESET_PC (RESET_PC), - .RESET_STRATEGY (RESET_STRATEGY), - .WITH_CSR (WITH_CSR), - .W (W)) - ctrl - ( - .clk (clk), - .i_rst (i_rst), - //State - .i_pc_en (ctrl_pc_en), - .i_cnt12to31 (cnt12to31), - .i_cnt0 (cnt0), - .i_cnt1 (cnt1), - .i_cnt2 (cnt2), - //Control - .i_jump (jump), - .i_jal_or_jalr (jal_or_jalr), - .i_utype (utype), - .i_pc_rel (pc_rel), - .i_trap (trap | mret), - .i_iscomp (iscomp), - //Data - .i_imm (imm), - .i_buf (bufreg_q), - .i_csr_pc (csr_pc), - .o_rd (ctrl_rd), - .o_bad_pc (bad_pc), - //External - .o_ibus_adr (wb_ibus_adr)); - - serv_alu #(.W (W)) alu - ( - .clk (clk), - //State - .i_en (cnt_en), - .i_cnt0 (cnt0), - .o_cmp (alu_cmp), - //Control - .i_sub (alu_sub), - .i_bool_op (alu_bool_op), - .i_cmp_eq (alu_cmp_eq), - .i_cmp_sig (alu_cmp_sig), - .i_rd_sel (alu_rd_sel), - //Data - .i_rs1 (rs1), - .i_op_b (op_b), - .i_buf (bufreg_q), - .o_rd (alu_rd)); - - serv_rf_if - #(.WITH_CSR (WITH_CSR), .W(W)) - rf_if - (//RF interface - .i_cnt_en (cnt_en), - .o_wreg0 (o_wreg0), - .o_wreg1 (o_wreg1), - .o_wen0 (o_wen0), - .o_wen1 (o_wen1), - .o_wdata0 (o_wdata0), - .o_wdata1 (o_wdata1), - .o_rreg0 (o_rreg0), - .o_rreg1 (o_rreg1), - .i_rdata0 (i_rdata0), - .i_rdata1 (i_rdata1), - - //Trap interface - .i_trap (trap), - .i_mret (mret), - .i_mepc (wb_ibus_adr[B:0]), - .i_mtval_pc (mtval_pc), - .i_bufreg_q (bufreg_q), - .i_bad_pc (bad_pc), - .o_csr_pc (csr_pc), - //CSR write port - .i_csr_en (csr_en), - .i_csr_addr (csr_addr), - .i_csr (csr_in), - //RD write port - .i_rd_wen (rd_en), - .i_rd_waddr (rd_addr), - .i_ctrl_rd (ctrl_rd), - .i_alu_rd (alu_rd), - .i_rd_alu_en (rd_alu_en), - .i_csr_rd (csr_rd), - .i_rd_csr_en (rd_csr_en), - .i_mem_rd (mem_rd), - .i_rd_mem_en (rd_mem_en), - - //RS1 read port - .i_rs1_raddr (rs1_addr), - .o_rs1 (rs1), - //RS2 read port - .i_rs2_raddr (rs2_addr), - .o_rs2 (rs2), - - //CSR read port - .o_csr (rf_csr_out)); - - serv_mem_if - #(.WITH_CSR (WITH_CSR[0:0]), - .W (W)) - mem_if - ( - .i_clk (clk), - //State - .i_bytecnt (mem_bytecnt), - .i_lsb (lsb), - .o_misalign (mem_misalign), - //Control - .i_mdu_op (mdu_op), - .i_signed (mem_signed), - .i_word (mem_word), - .i_half (mem_half), - //Data - .i_bufreg2_q (bufreg2_q), - .o_rd (mem_rd), - //External interface - .o_wb_sel (o_dbus_sel)); - - generate - if (|WITH_CSR) begin : gen_csr - serv_csr - #(.RESET_STRATEGY (RESET_STRATEGY), - .W(W)) - csr - ( - .i_clk (clk), - .i_rst (i_rst), - //State - .i_trig_irq (wb_ibus_ack), - .i_en (cnt_en), - .i_cnt0to3 (cnt0to3), - .i_cnt3 (cnt3), - .i_cnt7 (cnt7), - .i_cnt11 (cnt11), - .i_cnt12 (cnt12), - .i_cnt_done (cnt_done), - .i_mem_op (!mtval_pc), - .i_mtip (i_timer_irq), - .i_trap (trap), - .o_new_irq (new_irq), - //Control - .i_e_op (e_op), - .i_ebreak (ebreak), - .i_mem_cmd (o_dbus_we), - .i_mstatus_en (csr_mstatus_en), - .i_mie_en (csr_mie_en ), - .i_mcause_en (csr_mcause_en ), - .i_csr_source (csr_source), - .i_mret (mret), - .i_csr_d_sel (csr_d_sel), - //Data - .i_rf_csr_out (rf_csr_out), - .o_csr_in (csr_in), - .i_csr_imm (csr_imm), - .i_rs1 (rs1), - .o_q (csr_rd)); - end else begin : gen_no_csr - assign csr_in = {W{1'b0}}; - assign csr_rd = {W{1'b0}}; - assign new_irq = 1'b0; - end - endgenerate - - generate - if (DEBUG) begin : gen_debug - serv_debug #(.W (W), .RESET_PC (RESET_PC)) debug - ( -`ifdef RISCV_FORMAL - .rvfi_valid (rvfi_valid ), - .rvfi_order (rvfi_order ), - .rvfi_insn (rvfi_insn ), - .rvfi_trap (rvfi_trap ), - .rvfi_halt (rvfi_halt ), - .rvfi_intr (rvfi_intr ), - .rvfi_mode (rvfi_mode ), - .rvfi_ixl (rvfi_ixl ), - .rvfi_rs1_addr (rvfi_rs1_addr ), - .rvfi_rs2_addr (rvfi_rs2_addr ), - .rvfi_rs1_rdata (rvfi_rs1_rdata), - .rvfi_rs2_rdata (rvfi_rs2_rdata), - .rvfi_rd_addr (rvfi_rd_addr ), - .rvfi_rd_wdata (rvfi_rd_wdata ), - .rvfi_pc_rdata (rvfi_pc_rdata ), - .rvfi_pc_wdata (rvfi_pc_wdata ), - .rvfi_mem_addr (rvfi_mem_addr ), - .rvfi_mem_rmask (rvfi_mem_rmask), - .rvfi_mem_wmask (rvfi_mem_wmask), - .rvfi_mem_rdata (rvfi_mem_rdata), - .rvfi_mem_wdata (rvfi_mem_wdata), - .i_dbus_adr (o_dbus_adr), - .i_dbus_dat (o_dbus_dat), - .i_dbus_sel (o_dbus_sel), - .i_dbus_we (o_dbus_we ), - .i_dbus_rdt (i_dbus_rdt), - .i_dbus_ack (i_dbus_ack), - .i_ctrl_pc_en (ctrl_pc_en), - .rs1 (rs1), - .rs2 (rs2), - .rs1_addr (rs1_addr), - .rs2_addr (rs2_addr), - .immdec_en (immdec_en), - .rd_en (rd_en), - .trap (trap), - .i_rf_ready (i_rf_ready), - .i_ibus_cyc (o_ibus_cyc), - .two_stage_op (two_stage_op), - .init (init), - .i_ibus_adr (o_ibus_adr), -`endif - .i_clk (clk), - .i_rst (i_rst), - .i_ibus_rdt (i_ibus_rdt), - .i_ibus_ack (i_ibus_ack), - .i_rd_addr (rd_addr ), - .i_cnt_en (cnt_en ), - .i_csr_in (csr_in ), - .i_csr_mstatus_en (csr_mstatus_en), - .i_csr_mie_en (csr_mie_en ), - .i_csr_mcause_en (csr_mcause_en ), - .i_csr_en (csr_en ), - .i_csr_addr (csr_addr), - .i_wen0 (o_wen0), - .i_wdata0 (o_wdata0), - .i_cnt_done (cnt_done)); - end - endgenerate - - -generate - if (MDU) begin: gen_mdu - assign dbus_rdt = i_ext_ready ? i_ext_rd:i_dbus_rdt; - assign dbus_ack = i_dbus_ack | i_ext_ready; - end else begin : gen_no_mdu - assign dbus_rdt = i_dbus_rdt; - assign dbus_ack = i_dbus_ack; - end - assign o_ext_rs2 = o_dbus_dat; -endgenerate - -endmodule -`default_nettype wire \ No newline at end of file diff --git a/rtl/qerv/servile.v b/rtl/qerv/servile.v deleted file mode 100644 index 7a48b7f..0000000 --- a/rtl/qerv/servile.v +++ /dev/null @@ -1,279 +0,0 @@ -/* - * servile.v : Top-level for Servile, the SERV convenience wrapper - * - * SPDX-FileCopyrightText: 2024 Olof Kindgren - * SPDX-License-Identifier: Apache-2.0 - */ - -`default_nettype none -module servile - #( - parameter width = 1, - parameter reset_pc = 32'h00000000, - parameter reset_strategy = "MINI", - parameter rf_width = 2*width, - parameter [0:0] sim = 1'b0, - parameter [0:0] debug = 1'b0, - parameter [0:0] with_c = 1'b0, - parameter [0:0] with_csr = 1'b0, - parameter [0:0] with_mdu = 1'b0, - //Internally calculated. Do not touch - parameter B = width-1, - parameter regs = 32+with_csr*4, - parameter rf_l2d = $clog2(regs*32/rf_width)) - ( - input wire i_clk, - input wire i_rst, - input wire i_timer_irq, - - //Memory (WB) interface - output wire [31:0] o_wb_mem_adr, - output wire [31:0] o_wb_mem_dat, - output wire [3:0] o_wb_mem_sel, - output wire o_wb_mem_we , - output wire o_wb_mem_stb, - input wire [31:0] i_wb_mem_rdt, - input wire i_wb_mem_ack, - - //Extension (WB) interface - output wire [31:0] o_wb_ext_adr, - output wire [31:0] o_wb_ext_dat, - output wire [3:0] o_wb_ext_sel, - output wire o_wb_ext_we , - output wire o_wb_ext_stb, - input wire [31:0] i_wb_ext_rdt, - input wire i_wb_ext_ack, - - //RF (SRAM) interface - output wire [rf_l2d-1:0] o_rf_waddr, - output wire [rf_width-1:0] o_rf_wdata, - output wire o_rf_wen, - output wire [rf_l2d-1:0] o_rf_raddr, - input wire [rf_width-1:0] i_rf_rdata, - output wire o_rf_ren); - - - - wire [31:0] wb_ibus_adr; - wire wb_ibus_stb; - wire [31:0] wb_ibus_rdt; - wire wb_ibus_ack; - - wire [31:0] wb_dbus_adr; - wire [31:0] wb_dbus_dat; - wire [3:0] wb_dbus_sel; - wire wb_dbus_we; - wire wb_dbus_stb; - wire [31:0] wb_dbus_rdt; - wire wb_dbus_ack; - - wire [31:0] wb_dmem_adr; - wire [31:0] wb_dmem_dat; - wire [3:0] wb_dmem_sel; - wire wb_dmem_we; - wire wb_dmem_stb; - wire [31:0] wb_dmem_rdt; - wire wb_dmem_ack; - - wire rf_wreq; - wire rf_rreq; - wire [$clog2(regs)-1:0] wreg0; - wire [$clog2(regs)-1:0] wreg1; - wire wen0; - wire wen1; - wire [B:0] wdata0; - wire [B:0] wdata1; - wire [$clog2(regs)-1:0] rreg0; - wire [$clog2(regs)-1:0] rreg1; - wire rf_ready; - wire [B:0] rdata0; - wire [B:0] rdata1; - - wire [31:0] mdu_rs1; - wire [31:0] mdu_rs2; - wire [ 2:0] mdu_op; - wire mdu_valid; - wire [31:0] mdu_rd; - wire mdu_ready; - - servile_mux - #(.sim (sim)) - mux - (.i_clk (i_clk), - .i_rst (i_rst & (reset_strategy != "NONE")), - - .i_wb_cpu_adr (wb_dbus_adr), - .i_wb_cpu_dat (wb_dbus_dat), - .i_wb_cpu_sel (wb_dbus_sel), - .i_wb_cpu_we (wb_dbus_we), - .i_wb_cpu_stb (wb_dbus_stb), - .o_wb_cpu_rdt (wb_dbus_rdt), - .o_wb_cpu_ack (wb_dbus_ack), - - .o_wb_mem_adr (wb_dmem_adr), - .o_wb_mem_dat (wb_dmem_dat), - .o_wb_mem_sel (wb_dmem_sel), - .o_wb_mem_we (wb_dmem_we), - .o_wb_mem_stb (wb_dmem_stb), - .i_wb_mem_rdt (wb_dmem_rdt), - .i_wb_mem_ack (wb_dmem_ack), - - .o_wb_ext_adr (o_wb_ext_adr), - .o_wb_ext_dat (o_wb_ext_dat), - .o_wb_ext_sel (o_wb_ext_sel), - .o_wb_ext_we (o_wb_ext_we), - .o_wb_ext_stb (o_wb_ext_stb), - .i_wb_ext_rdt (i_wb_ext_rdt), - .i_wb_ext_ack (i_wb_ext_ack)); - - servile_arbiter arbiter - (.i_wb_cpu_dbus_adr (wb_dmem_adr), - .i_wb_cpu_dbus_dat (wb_dmem_dat), - .i_wb_cpu_dbus_sel (wb_dmem_sel), - .i_wb_cpu_dbus_we (wb_dmem_we ), - .i_wb_cpu_dbus_stb (wb_dmem_stb), - .o_wb_cpu_dbus_rdt (wb_dmem_rdt), - .o_wb_cpu_dbus_ack (wb_dmem_ack), - - .i_wb_cpu_ibus_adr (wb_ibus_adr), - .i_wb_cpu_ibus_stb (wb_ibus_stb), - .o_wb_cpu_ibus_rdt (wb_ibus_rdt), - .o_wb_cpu_ibus_ack (wb_ibus_ack), - - .o_wb_mem_adr (o_wb_mem_adr), - .o_wb_mem_dat (o_wb_mem_dat), - .o_wb_mem_sel (o_wb_mem_sel), - .o_wb_mem_we (o_wb_mem_we ), - .o_wb_mem_stb (o_wb_mem_stb), - .i_wb_mem_rdt (i_wb_mem_rdt), - .i_wb_mem_ack (i_wb_mem_ack)); - - - - serv_rf_ram_if - #(.width (rf_width), - .W (width), - .reset_strategy (reset_strategy), - .csr_regs (with_csr*4)) - rf_ram_if - (.i_clk (i_clk), - .i_rst (i_rst), - //RF IF - .i_wreq (rf_wreq), - .i_rreq (rf_rreq), - .o_ready (rf_ready), - .i_wreg0 (wreg0), - .i_wreg1 (wreg1), - .i_wen0 (wen0), - .i_wen1 (wen1), - .i_wdata0 (wdata0), - .i_wdata1 (wdata1), - .i_rreg0 (rreg0), - .i_rreg1 (rreg1), - .o_rdata0 (rdata0), - .o_rdata1 (rdata1), - //SRAM IF - .o_waddr (o_rf_waddr), - .o_wdata (o_rf_wdata), - .o_wen (o_rf_wen), - .o_raddr (o_rf_raddr), - .o_ren (o_rf_ren), - .i_rdata (i_rf_rdata)); - - generate - if (with_mdu) begin : gen_mdu - mdu_top mdu_serv - (.i_clk (i_clk), - .i_rst (i_rst), - .i_mdu_rs1 (mdu_rs1), - .i_mdu_rs2 (mdu_rs2), - .i_mdu_op (mdu_op), - .i_mdu_valid (mdu_valid), - .o_mdu_ready (mdu_ready), - .o_mdu_rd (mdu_rd)); - end else begin - assign mdu_ready = 1'b0; - assign mdu_rd = 32'd0; - end - endgenerate - - qerv_top - #( - .WITH_CSR (with_csr?1:0), - .W (width), - .PRE_REGISTER (1'b1), - .RESET_STRATEGY (reset_strategy), - .RESET_PC (reset_pc), - .DEBUG (debug), - .MDU (with_mdu), - .COMPRESSED (with_c)) - cpu - ( - .clk (i_clk), - .i_rst (i_rst), - .i_timer_irq (i_timer_irq), - -`ifdef RISCV_FORMAL - .rvfi_valid (), - .rvfi_order (), - .rvfi_insn (), - .rvfi_trap (), - .rvfi_halt (), - .rvfi_intr (), - .rvfi_mode (), - .rvfi_ixl (), - .rvfi_rs1_addr (), - .rvfi_rs2_addr (), - .rvfi_rs1_rdata (), - .rvfi_rs2_rdata (), - .rvfi_rd_addr (), - .rvfi_rd_wdata (), - .rvfi_pc_rdata (), - .rvfi_pc_wdata (), - .rvfi_mem_addr (), - .rvfi_mem_rmask (), - .rvfi_mem_wmask (), - .rvfi_mem_rdata (), - .rvfi_mem_wdata (), -`endif - //RF IF - .o_rf_rreq (rf_rreq), - .o_rf_wreq (rf_wreq), - .i_rf_ready (rf_ready), - .o_wreg0 (wreg0), - .o_wreg1 (wreg1), - .o_wen0 (wen0), - .o_wen1 (wen1), - .o_wdata0 (wdata0), - .o_wdata1 (wdata1), - .o_rreg0 (rreg0), - .o_rreg1 (rreg1), - .i_rdata0 (rdata0), - .i_rdata1 (rdata1), - - //Instruction bus - .o_ibus_adr (wb_ibus_adr), - .o_ibus_cyc (wb_ibus_stb), - .i_ibus_rdt (wb_ibus_rdt), - .i_ibus_ack (wb_ibus_ack), - - //Data bus - .o_dbus_adr (wb_dbus_adr), - .o_dbus_dat (wb_dbus_dat), - .o_dbus_sel (wb_dbus_sel), - .o_dbus_we (wb_dbus_we), - .o_dbus_cyc (wb_dbus_stb), - .i_dbus_rdt (wb_dbus_rdt), - .i_dbus_ack (wb_dbus_ack), - - //Extension IF - .o_ext_rs1 (mdu_rs1), - .o_ext_rs2 (mdu_rs2), - .o_ext_funct3 (mdu_op), - .i_ext_rd (mdu_rd), - .i_ext_ready (mdu_ready), - //MDU - .o_mdu_valid (mdu_valid)); - -endmodule -`default_nettype wire \ No newline at end of file diff --git a/rtl/qerv/servile_arbiter.v b/rtl/qerv/servile_arbiter.v deleted file mode 100644 index 2f3427d..0000000 --- a/rtl/qerv/servile_arbiter.v +++ /dev/null @@ -1,45 +0,0 @@ -/* - * servile_arbiter.v : I/D arbiter for the servile convenience wrapper. - * Relies on the fact that not ibus and dbus are active at the same time. - * - * SPDX-FileCopyrightText: 2024 Olof Kindgren - * SPDX-License-Identifier: Apache-2.0 - */ - -module servile_arbiter - ( - input wire [31:0] i_wb_cpu_dbus_adr, - input wire [31:0] i_wb_cpu_dbus_dat, - input wire [3:0] i_wb_cpu_dbus_sel, - input wire i_wb_cpu_dbus_we, - input wire i_wb_cpu_dbus_stb, - output wire [31:0] o_wb_cpu_dbus_rdt, - output wire o_wb_cpu_dbus_ack, - - input wire [31:0] i_wb_cpu_ibus_adr, - input wire i_wb_cpu_ibus_stb, - output wire [31:0] o_wb_cpu_ibus_rdt, - output wire o_wb_cpu_ibus_ack, - - output wire [31:0] o_wb_mem_adr, - output wire [31:0] o_wb_mem_dat, - output wire [3:0] o_wb_mem_sel, - output wire o_wb_mem_we, - output wire o_wb_mem_stb, - input wire [31:0] i_wb_mem_rdt, - input wire i_wb_mem_ack); - - assign o_wb_cpu_dbus_rdt = i_wb_mem_rdt; - assign o_wb_cpu_dbus_ack = i_wb_mem_ack & !i_wb_cpu_ibus_stb; - - assign o_wb_cpu_ibus_rdt = i_wb_mem_rdt; - assign o_wb_cpu_ibus_ack = i_wb_mem_ack & i_wb_cpu_ibus_stb; - - assign o_wb_mem_adr = i_wb_cpu_ibus_stb ? i_wb_cpu_ibus_adr : i_wb_cpu_dbus_adr; - assign o_wb_mem_dat = i_wb_cpu_dbus_dat; - assign o_wb_mem_sel = i_wb_cpu_dbus_sel; - assign o_wb_mem_we = i_wb_cpu_dbus_we & !i_wb_cpu_ibus_stb; - assign o_wb_mem_stb = i_wb_cpu_ibus_stb | i_wb_cpu_dbus_stb; - - -endmodule \ No newline at end of file diff --git a/rtl/qerv/servile_mux.v b/rtl/qerv/servile_mux.v deleted file mode 100644 index ebd31e4..0000000 --- a/rtl/qerv/servile_mux.v +++ /dev/null @@ -1,100 +0,0 @@ -/* - * servile_mux.v : Simple Wishbone mux for the servile convenience wrapper. - * - * SPDX-FileCopyrightText: 2024 Olof Kindgren - * SPDX-License-Identifier: Apache-2.0 - */ - -module servile_mux - #(parameter [0:0] sim = 1'b0, //Enable simulation features - parameter [31:0] sim_sig_adr = 32'h80000000, - parameter [31:0] sim_halt_adr = 32'h90000000) - ( - input wire i_clk, - input wire i_rst, - - input wire [31:0] i_wb_cpu_adr, - input wire [31:0] i_wb_cpu_dat, - input wire [3:0] i_wb_cpu_sel, - input wire i_wb_cpu_we, - input wire i_wb_cpu_stb, - output wire [31:0] o_wb_cpu_rdt, - output wire o_wb_cpu_ack, - - output wire [31:0] o_wb_mem_adr, - output wire [31:0] o_wb_mem_dat, - output wire [3:0] o_wb_mem_sel, - output wire o_wb_mem_we, - output wire o_wb_mem_stb, - input wire [31:0] i_wb_mem_rdt, - input wire i_wb_mem_ack, - - output wire [31:0] o_wb_ext_adr, - output wire [31:0] o_wb_ext_dat, - output wire [3:0] o_wb_ext_sel, - output wire o_wb_ext_we, - output wire o_wb_ext_stb, - input wire [31:0] i_wb_ext_rdt, - input wire i_wb_ext_ack); - - wire sig_en; - wire halt_en; - reg sim_ack; - - wire ext = (i_wb_cpu_adr[31:30] != 2'b00); - - assign o_wb_cpu_rdt = ext ? i_wb_ext_rdt : i_wb_mem_rdt; - assign o_wb_cpu_ack = i_wb_ext_ack | i_wb_mem_ack | sim_ack; - - assign o_wb_mem_adr = i_wb_cpu_adr; - assign o_wb_mem_dat = i_wb_cpu_dat; - assign o_wb_mem_sel = i_wb_cpu_sel; - assign o_wb_mem_we = i_wb_cpu_we; - assign o_wb_mem_stb = i_wb_cpu_stb & !ext & !(sig_en|halt_en); - - assign o_wb_ext_adr = i_wb_cpu_adr; - assign o_wb_ext_dat = i_wb_cpu_dat; - assign o_wb_ext_sel = i_wb_cpu_sel; - assign o_wb_ext_we = i_wb_cpu_we; - assign o_wb_ext_stb = i_wb_cpu_stb & ext & !(sig_en|halt_en); - - generate - if (sim) begin - - integer f = 0; - - assign sig_en = |f & i_wb_cpu_we & (i_wb_cpu_adr == sim_sig_adr); - assign halt_en = i_wb_cpu_we & (i_wb_cpu_adr == sim_halt_adr); - - reg [1023:0] signature_file; - - initial - /* verilator lint_off WIDTH */ - if ($value$plusargs("signature=%s", signature_file)) begin - $display("Writing signature to %0s", signature_file); - f = $fopen(signature_file, "w"); - end - /* verilator lint_on WIDTH */ - - always @(posedge i_clk) begin - sim_ack <= 1'b0; - if (i_wb_cpu_stb & !sim_ack) begin - sim_ack <= sig_en|halt_en; - if (sig_en & (f != 0)) - $fwrite(f, "%c", i_wb_cpu_dat[7:0]); - else if(halt_en) begin - $display("Test complete"); - $finish; - end - end - if (i_rst) - sim_ack <= 1'b0; - end - end else begin - assign sig_en = 1'b0; - assign halt_en = 1'b0; - initial sim_ack = 1'b0; - end - endgenerate - -endmodule \ No newline at end of file diff --git a/rtl/qerv/servile_rf_mem_if.v b/rtl/qerv/servile_rf_mem_if.v deleted file mode 100644 index b0c9d2c..0000000 --- a/rtl/qerv/servile_rf_mem_if.v +++ /dev/null @@ -1,77 +0,0 @@ -/* - * servile_rf_mem_if.v : Arbiter to allow a shared SRAM for RF and memory accesses. RF is mapped to the highest 128 bytes of the memory. Requires 8-bit RF accesses. - * - * SPDX-FileCopyrightText: 2024 Olof Kindgren - * SPDX-License-Identifier: Apache-2.0 - */ - -`default_nettype none -module servile_rf_mem_if - #(//Memory parameters - parameter depth = 256, - //RF parameters - parameter rf_regs = 32, - //Internally calculated. Do not touch - parameter rf_depth = $clog2(rf_regs*4), - parameter aw = $clog2(depth)) - ( - input wire i_clk, - input wire i_rst, - input wire [rf_depth-1:0] i_waddr, - input wire [7:0] i_wdata, - input wire i_wen, - input wire [rf_depth-1:0] i_raddr, - output wire [7:0] o_rdata, - input wire i_ren, - - output wire [aw-1:0] o_sram_waddr, - output wire [7:0] o_sram_wdata, - output wire o_sram_wen, - output wire [aw-1:0] o_sram_raddr, - input wire [7:0] i_sram_rdata, - output wire o_sram_ren, - - input wire [aw-1:2] i_wb_adr, - input wire [31:0] i_wb_dat, - input wire [3:0] i_wb_sel, - input wire i_wb_we, - input wire i_wb_stb, - output wire [31:0] o_wb_rdt, - output reg o_wb_ack); - - reg [1:0] bsel; - - wire wb_en = i_wb_stb & !i_wen & !o_wb_ack; - - wire wb_we = i_wb_we & i_wb_sel[bsel]; - - wire [aw-1:0] rf_waddr = ~{{aw-rf_depth{1'b0}},i_waddr}; - wire [aw-1:0] rf_raddr = ~{{aw-rf_depth{1'b0}},i_raddr}; - - assign o_sram_waddr = wb_en ? {i_wb_adr[aw-1:2],bsel} : rf_waddr; - assign o_sram_wdata = wb_en ? i_wb_dat[bsel*8+:8] : i_wdata; - assign o_sram_wen = wb_en ? wb_we : i_wen; - assign o_sram_raddr = wb_en ? {i_wb_adr[aw-1:2],bsel} : rf_raddr; - assign o_sram_ren = wb_en ? !i_wb_we : i_ren; - - reg [23:0] wb_rdt; - assign o_wb_rdt = {i_sram_rdata, wb_rdt}; - - reg regzero; - always @(posedge i_clk) begin - - if (wb_en) bsel <= bsel + 2'd1; - o_wb_ack <= wb_en & &bsel; - if (bsel == 2'b01) wb_rdt[7:0] <= i_sram_rdata; - if (bsel == 2'b10) wb_rdt[15:8] <= i_sram_rdata; - if (bsel == 2'b11) wb_rdt[23:16] <= i_sram_rdata; - if (i_rst) begin - bsel <= 2'd0; - o_wb_ack <= 1'b0; - end - regzero <= &i_raddr[rf_depth-1:2]; - end - - assign o_rdata = regzero ? 8'd0 : i_sram_rdata; - -endmodule \ No newline at end of file diff --git a/rtl/serv/LICENSE b/rtl/serv/LICENSE deleted file mode 100644 index 8572ea0..0000000 --- a/rtl/serv/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -ISC License - -Copyright 2019, Olof Kindgren - -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/rtl/serv/serv_aligner.v b/rtl/serv/serv_aligner.v deleted file mode 100644 index 27aefa4..0000000 --- a/rtl/serv/serv_aligner.v +++ /dev/null @@ -1,73 +0,0 @@ -/* - * serv_aligner.v : Realign a misaligned 32-bit word fetched from memory - * - * SPDX-FileCopyrightText: 2022 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -module serv_aligner - ( - input wire clk, - input wire rst, - // serv_top - input wire [31:0] i_ibus_adr, - input wire i_ibus_cyc, - output wire [31:0] o_ibus_rdt, - output wire o_ibus_ack, - // serv_rf_top - output wire [31:0] o_wb_ibus_adr, - output wire o_wb_ibus_cyc, - input wire [31:0] i_wb_ibus_rdt, - input wire i_wb_ibus_ack); - - wire [31:0] ibus_rdt_concat; - wire ack_en; - - reg [15:0] lower_hw; - reg ctrl_misal ; - - /* From SERV core to Memory - - o_wb_ibus_adr: Carries address of instruction to memory. In case of misaligned access, - which is caused by pc+2 due to compressed instruction, next instruction is fetched - by pc+4 and concatenation is done to make the instruction aligned. - - o_wb_ibus_cyc: Simply forwarded from SERV to Memory and is only altered by memory or SERV core. - */ - assign o_wb_ibus_adr = ctrl_misal ? (i_ibus_adr+32'b100) : i_ibus_adr; - assign o_wb_ibus_cyc = i_ibus_cyc; - - /* From Memory to SERV core - - o_ibus_ack: Instruction bus acknowledge is send to SERV only when the aligned instruction, - either compressed or un-compressed, is ready to dispatch. - - o_ibus_rdt: Carries the instruction from memory to SERV core. It can be either aligned - instruction coming from memory or made aligned by two bus transactions and concatenation. - */ - assign o_ibus_ack = i_wb_ibus_ack & ack_en; - assign o_ibus_rdt = ctrl_misal ? ibus_rdt_concat : i_wb_ibus_rdt; - - /* 16-bit register used to hold the upper half word of the current instruction in-case - concatenation will be required with the upper half word of upcoming instruction - */ - always @(posedge clk) begin - if(i_wb_ibus_ack)begin - lower_hw <= i_wb_ibus_rdt[31:16]; - end - end - - assign ibus_rdt_concat = {i_wb_ibus_rdt[15:0],lower_hw}; - - /* Two control signals: ack_en, ctrl_misal are set to control the bus transactions between - SERV core and the memory - */ - assign ack_en = !(i_ibus_adr[1] & !ctrl_misal); - - always @(posedge clk ) begin - if(rst) - ctrl_misal <= 0; - else if(i_wb_ibus_ack & i_ibus_adr[1]) - ctrl_misal <= !ctrl_misal; - end - -endmodule diff --git a/rtl/serv/serv_alu.v b/rtl/serv/serv_alu.v deleted file mode 100644 index 5dad42e..0000000 --- a/rtl/serv/serv_alu.v +++ /dev/null @@ -1,87 +0,0 @@ -/* - * serv_alu.v : SERV Arithmetic Logic Unit - * - * SPDX-FileCopyrightText: 2018 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -`default_nettype none -module serv_alu - #( - parameter W = 1, - parameter B = W-1 - ) - ( - input wire clk, - //State - input wire i_en, - input wire i_cnt0, - output wire o_cmp, - //Control - input wire i_sub, - input wire [1:0] i_bool_op, - input wire i_cmp_eq, - input wire i_cmp_sig, - input wire [2:0] i_rd_sel, - //Data - input wire [B:0] i_rs1, - input wire [B:0] i_op_b, - input wire [B:0] i_buf, - output wire [B:0] o_rd); - - wire [B:0] result_add; - wire [B:0] result_slt; - - reg cmp_r; - - wire add_cy; - reg [B:0] add_cy_r; - - //Sign-extended operands - wire rs1_sx = i_rs1[B] & i_cmp_sig; - wire op_b_sx = i_op_b[B] & i_cmp_sig; - - wire [B:0] add_b = i_op_b^{W{i_sub}}; - - assign {add_cy,result_add} = i_rs1+add_b+add_cy_r; - - wire result_lt = rs1_sx + ~op_b_sx + add_cy; - - wire result_eq = !(|result_add) & (cmp_r | i_cnt0); - - assign o_cmp = i_cmp_eq ? result_eq : result_lt; - - /* - The result_bool expression implements the following operations between - i_rs1 and i_op_b depending on the value of i_bool_op - - 00 xor - 01 0 - 10 or - 11 and - - i_bool_op will be 01 during shift operations, so by outputting zero under - this condition we can safely or result_bool with i_buf - */ - wire [B:0] result_bool = ((i_rs1 ^ i_op_b) & ~{W{i_bool_op[0]}}) | ({W{i_bool_op[1]}} & i_op_b & i_rs1); - - assign result_slt[0] = cmp_r & i_cnt0; - generate - if (W>1) begin : gen_w_gt_1 - assign result_slt[B:1] = {B{1'b0}}; - end - endgenerate - - assign o_rd = i_buf | - ({W{i_rd_sel[0]}} & result_add) | - ({W{i_rd_sel[1]}} & result_slt) | - ({W{i_rd_sel[2]}} & result_bool); - - always @(posedge clk) begin - add_cy_r <= {W{1'b0}}; - add_cy_r[0] <= i_en ? add_cy : i_sub; - - if (i_en) - cmp_r <= o_cmp; - end - -endmodule diff --git a/rtl/serv/serv_bufreg.v b/rtl/serv/serv_bufreg.v deleted file mode 100644 index dde66f4..0000000 --- a/rtl/serv/serv_bufreg.v +++ /dev/null @@ -1,101 +0,0 @@ -/* - * serv_bufreg.v : SERV buffer register for load/store address and shift data - * - * SPDX-FileCopyrightText: 2019 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -module serv_bufreg #( - parameter [0:0] MDU = 0, - parameter W = 1, - parameter B = W-1 -)( - input wire i_clk, - //State - input wire i_cnt0, - input wire i_cnt1, - input wire i_cnt_done, - input wire i_en, - input wire i_init, - input wire i_mdu_op, - output wire [1:0] o_lsb, - //Control - input wire i_rs1_en, - input wire i_imm_en, - input wire i_clr_lsb, - input wire i_shift_op, - input wire i_right_shift_op, - input wire [2:0] i_shamt, - input wire i_sh_signed, - //Data - input wire [B:0] i_rs1, - input wire [B:0] i_imm, - output wire [B:0] o_q, - //External - output wire [31:0] o_dbus_adr, - //Extension - output wire [31:0] o_ext_rs1); - - wire c; - wire [B:0] q; - reg [B:0] c_r; - reg [31:0] data; - wire [B:0] clr_lsb; - - assign clr_lsb[0] = i_cnt0 & i_clr_lsb; - - generate - if (W > 1) begin : gen_clr_lsb_w_gt_1 - assign clr_lsb[B:1] = {B{1'b0}}; - end - endgenerate - - assign {c,q} = {1'b0,(i_rs1 & {W{i_rs1_en}})} + {1'b0,(i_imm & {W{i_imm_en}} & ~clr_lsb)} + c_r; - - always @(posedge i_clk) begin - //Make sure carry is cleared before loading new data - c_r <= {W{1'b0}}; - c_r[0] <= c & i_en; - end - - generate - if (W == 1) begin : gen_w_eq_1 - always @(posedge i_clk) begin - if (i_en) - data[31:2] <= {i_init ? q : {W{data[31] & i_sh_signed}}, data[31:3]}; - - if (i_init ? (i_cnt0 | i_cnt1) : i_en) - data[1:0] <= {i_init ? q : data[2], data[1]}; - end - assign o_lsb = (MDU & i_mdu_op) ? 2'b00 : data[1:0]; - assign o_q = data[0] & {W{i_en}}; - end else if (W == 4) begin : gen_lsb_w_4 - reg [1:0] lsb; - reg [W-2:0] data_tail; - - wire [2:0] shift_amount - = !i_shift_op ? 3'd3 : - i_right_shift_op ? (3'd3+{1'b0,i_shamt[1:0]}) : - ({1'b0,~i_shamt[1:0]}); - - always @(posedge i_clk) begin - if (i_en) - if (i_cnt0) lsb <= q[1:0]; - if (i_en) - data <= {i_init ? q : {W{i_sh_signed & data[31]}}, data[31:W]}; - if (i_en) - data_tail <= data[B:1] & {B{~i_cnt_done}}; - end - - wire [2*W+B-2:0] muxdata = {data[W+B-1:0],data_tail}; - wire [B:0] muxout = muxdata[{1'b0,shift_amount}+:W]; - - assign o_lsb = (MDU & i_mdu_op) ? 2'b00 : lsb; - assign o_q = i_en ? muxout : {W{1'b0}}; - end - endgenerate - - - assign o_dbus_adr = {data[31:2], 2'b00}; - assign o_ext_rs1 = data; - -endmodule diff --git a/rtl/serv/serv_bufreg2.v b/rtl/serv/serv_bufreg2.v deleted file mode 100644 index 527a08d..0000000 --- a/rtl/serv/serv_bufreg2.v +++ /dev/null @@ -1,105 +0,0 @@ -/* - * serv_bufreg2.v : SERV buffer register for load/store data and shift amount - * - * SPDX-FileCopyrightText: 2022 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -module serv_bufreg2 - #(parameter W = 1, - //Internally calculated. Do not touch - parameter B=W-1) - ( - input wire i_clk, - //State - input wire i_en, - input wire i_init, - input wire i_cnt7, - input wire i_cnt_done, - input wire i_sh_right, - input wire [1:0] i_lsb, - input wire [1:0] i_bytecnt, - output wire o_sh_done, - //Control - input wire i_op_b_sel, - input wire i_shift_op, - //Data - input wire [B:0] i_rs2, - input wire [B:0] i_imm, - output wire [B:0] o_op_b, - output wire [B:0] o_q, - //External - output wire [31:0] o_dat, - input wire i_load, - input wire [31:0] i_dat); - - // High and low data words form a 32-bit word - reg [7:0] dhi; - reg [23:0] dlo; - - /* - Before a store operation, the data to be written needs to be shifted into - place. Depending on the address alignment, we need to shift different - amounts. One formula for calculating this is to say that we shift when - i_lsb + i_bytecnt < 4. Unfortunately, the synthesis tools don't seem to be - clever enough so the hideous expression below is used to achieve the same - thing in a more optimal way. - */ - wire byte_valid - = (!i_lsb[0] & !i_lsb[1]) | - (!i_bytecnt[0] & !i_bytecnt[1]) | - (!i_bytecnt[1] & !i_lsb[1]) | - (!i_bytecnt[1] & !i_lsb[0]) | - (!i_bytecnt[0] & !i_lsb[1]); - - assign o_op_b = i_op_b_sel ? i_rs2 : i_imm; - - wire shift_en = i_shift_op ? (i_en & i_init & (i_bytecnt == 2'b00)) : (i_en & byte_valid); - - wire cnt_en = (i_shift_op & (!i_init | (i_cnt_done & i_sh_right))); - - /* The dat register has three different use cases for store, load and - shift operations. - store : Data to be written is shifted to the correct position in dat during - init by shift_en and is presented on the data bus as o_wb_dat - load : Data from the bus gets latched into dat during i_wb_ack and is then - shifted out at the appropriate time to end up in the correct - position in rd - shift : Data is shifted in during init. After that, the six LSB are used as - a downcounter (with bit 5 initially set to 0) that trigger - o_sh_done when they wrap around to indicate that - the requested number of shifts have been performed - */ - - wire [7:0] cnt_next; - generate - if (W == 1) begin : gen_cnt_w_eq_1 - assign cnt_next = {o_op_b, dhi[7], dhi[5:0]-6'd1}; - end else if (W == 4) begin : gen_cnt_w_eq_4 - assign cnt_next = {o_op_b[3:2], dhi[5:0]-6'd4}; - end - endgenerate - - wire [7:0] dat_shamt = cnt_en ? - //Down counter mode - cnt_next : - //Shift reg mode - {o_op_b, dhi[7:W]}; - - assign o_sh_done = dat_shamt[5]; - - assign o_q = - ({W{(i_lsb == 2'd3)}} & o_dat[W+23:24]) | - ({W{(i_lsb == 2'd2)}} & o_dat[W+15:16]) | - ({W{(i_lsb == 2'd1)}} & o_dat[W+7:8]) | - ({W{(i_lsb == 2'd0)}} & o_dat[W-1:0]); - - assign o_dat = {dhi,dlo}; - - always @(posedge i_clk) begin - if (shift_en | cnt_en | i_load) - dhi <= i_load ? i_dat[31:24] : dat_shamt & {2'b11, !(i_shift_op & i_cnt7 & !cnt_en), 5'b11111}; - if (shift_en | i_load) - dlo <= i_load ? i_dat[23:0] : {dhi[B:0], dlo[23:W]}; - end - -endmodule diff --git a/rtl/serv/serv_compdec.v b/rtl/serv/serv_compdec.v deleted file mode 100644 index 380461a..0000000 --- a/rtl/serv/serv_compdec.v +++ /dev/null @@ -1,232 +0,0 @@ -/* Copyright lowRISC contributors. -Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md. -Licensed under the Apache License, Version 2.0, see LICENSE for details. -SPDX-License-Identifier: Apache-2.0 - -* Adapted to SERV by @Abdulwadoodd as part of the project under spring '22 LFX Mentorship program */ - -/* Decodes RISC-V compressed instructions into their RV32i equivalent. */ - -module serv_compdec - ( - input wire i_clk, - input wire [31:0] i_instr, - input wire i_ack, - output wire [31:0] o_instr, - output reg o_iscomp); - - localparam OPCODE_LOAD = 7'h03; - localparam OPCODE_OP_IMM = 7'h13; - localparam OPCODE_STORE = 7'h23; - localparam OPCODE_OP = 7'h33; - localparam OPCODE_LUI = 7'h37; - localparam OPCODE_BRANCH = 7'h63; - localparam OPCODE_JALR = 7'h67; - localparam OPCODE_JAL = 7'h6f; - - reg [31:0] comp_instr; - reg illegal_instr; - - assign o_instr = illegal_instr ? i_instr : comp_instr; - - always @(posedge i_clk) begin - if(i_ack) - o_iscomp <= !illegal_instr; - end - - always @ (*) begin - // By default, forward incoming instruction, mark it as legal. - comp_instr = i_instr; - illegal_instr = 1'b0; - - // Check if incoming instruction is compressed. - case (i_instr[1:0]) - // C0 - 2'b00: begin - case (i_instr[15:14]) - 2'b00: begin - // c.addi4spn -> addi rd', x2, imm - comp_instr = {2'b0, i_instr[10:7], i_instr[12:11], i_instr[5], - i_instr[6], 2'b00, 5'h02, 3'b000, 2'b01, i_instr[4:2], {OPCODE_OP_IMM}}; - end - - 2'b01: begin - // c.lw -> lw rd', imm(rs1') - comp_instr = {5'b0, i_instr[5], i_instr[12:10], i_instr[6], - 2'b00, 2'b01, i_instr[9:7], 3'b010, 2'b01, i_instr[4:2], {OPCODE_LOAD}}; - end - - 2'b11: begin - // c.sw -> sw rs2', imm(rs1') - comp_instr = {5'b0, i_instr[5], i_instr[12], 2'b01, i_instr[4:2], - 2'b01, i_instr[9:7], 3'b010, i_instr[11:10], i_instr[6], - 2'b00, {OPCODE_STORE}}; - end - - 2'b10: begin - illegal_instr = 1'b1; - end - - endcase - end - - // C1 - - // Register address checks for RV32E are performed in the regular instruction decoder. - // If this check fails, an illegal instruction exception is triggered and the controller - // writes the actual faulting instruction to mtval. - 2'b01: begin - case (i_instr[15:13]) - 3'b000: begin - // c.addi -> addi rd, rd, nzimm - // c.nop - comp_instr = {{6 {i_instr[12]}}, i_instr[12], i_instr[6:2], - i_instr[11:7], 3'b0, i_instr[11:7], {OPCODE_OP_IMM}}; - end - - 3'b001, 3'b101: begin - // 001: c.jal -> jal x1, imm - // 101: c.j -> jal x0, imm - comp_instr = {i_instr[12], i_instr[8], i_instr[10:9], i_instr[6], - i_instr[7], i_instr[2], i_instr[11], i_instr[5:3], - {9 {i_instr[12]}}, 4'b0, ~i_instr[15], {OPCODE_JAL}}; - end - - 3'b010: begin - // c.li -> addi rd, x0, nzimm - // (c.li hints are translated into an addi hint) - comp_instr = {{6 {i_instr[12]}}, i_instr[12], i_instr[6:2], 5'b0, - 3'b0, i_instr[11:7], {OPCODE_OP_IMM}}; - end - - 3'b011: begin - // c.lui -> lui rd, imm - // (c.lui hints are translated into a lui hint) - comp_instr = {{15 {i_instr[12]}}, i_instr[6:2], i_instr[11:7], {OPCODE_LUI}}; - - if (i_instr[11:7] == 5'h02) begin - // c.addi16sp -> addi x2, x2, nzimm - comp_instr = {{3 {i_instr[12]}}, i_instr[4:3], i_instr[5], i_instr[2], - i_instr[6], 4'b0, 5'h02, 3'b000, 5'h02, {OPCODE_OP_IMM}}; - end - - end - - 3'b100: begin - case (i_instr[11:10]) - 2'b00, - 2'b01: begin - // 00: c.srli -> srli rd, rd, shamt - // 01: c.srai -> srai rd, rd, shamt - // (c.srli/c.srai hints are translated into a srli/srai hint) - comp_instr = {1'b0, i_instr[10], 5'b0, i_instr[6:2], 2'b01, i_instr[9:7], - 3'b101, 2'b01, i_instr[9:7], {OPCODE_OP_IMM}}; - end - - 2'b10: begin - // c.andi -> andi rd, rd, imm - comp_instr = {{6 {i_instr[12]}}, i_instr[12], i_instr[6:2], 2'b01, i_instr[9:7], - 3'b111, 2'b01, i_instr[9:7], {OPCODE_OP_IMM}}; - end - - 2'b11: begin - case (i_instr[6:5]) - 2'b00: begin - // c.sub -> sub rd', rd', rs2' - comp_instr = {2'b01, 5'b0, 2'b01, i_instr[4:2], 2'b01, i_instr[9:7], - 3'b000, 2'b01, i_instr[9:7], {OPCODE_OP}}; - end - - 2'b01: begin - // c.xor -> xor rd', rd', rs2' - comp_instr = {7'b0, 2'b01, i_instr[4:2], 2'b01, i_instr[9:7], 3'b100, - 2'b01, i_instr[9:7], {OPCODE_OP}}; - end - - 2'b10: begin - // c.or -> or rd', rd', rs2' - comp_instr = {7'b0, 2'b01, i_instr[4:2], 2'b01, i_instr[9:7], 3'b110, - 2'b01, i_instr[9:7], {OPCODE_OP}}; - end - - 2'b11: begin - // c.and -> and rd', rd', rs2' - comp_instr = {7'b0, 2'b01, i_instr[4:2], 2'b01, i_instr[9:7], 3'b111, - 2'b01, i_instr[9:7], {OPCODE_OP}}; - end - endcase - end - endcase - end - - 3'b110, 3'b111: begin - // 0: c.beqz -> beq rs1', x0, imm - // 1: c.bnez -> bne rs1', x0, imm - comp_instr = {{4 {i_instr[12]}}, i_instr[6:5], i_instr[2], 5'b0, 2'b01, - i_instr[9:7], 2'b00, i_instr[13], i_instr[11:10], i_instr[4:3], - i_instr[12], {OPCODE_BRANCH}}; - end - endcase - end - - // C2 - - // Register address checks for RV32E are performed in the regular instruction decoder. - // If this check fails, an illegal instruction exception is triggered and the controller - // writes the actual faulting instruction to mtval. - 2'b10: begin - case (i_instr[15:14]) - 2'b00: begin - // c.slli -> slli rd, rd, shamt - // (c.slli hints are translated into a slli hint) - comp_instr = {7'b0, i_instr[6:2], i_instr[11:7], 3'b001, i_instr[11:7], {OPCODE_OP_IMM}}; - end - - 2'b01: begin - // c.lwsp -> lw rd, imm(x2) - comp_instr = {4'b0, i_instr[3:2], i_instr[12], i_instr[6:4], 2'b00, 5'h02, - 3'b010, i_instr[11:7], OPCODE_LOAD}; - end - - 2'b10: begin - if (i_instr[12] == 1'b0) begin - if (i_instr[6:2] != 5'b0) begin - // c.mv -> add rd/rs1, x0, rs2 - // (c.mv hints are translated into an add hint) - comp_instr = {7'b0, i_instr[6:2], 5'b0, 3'b0, i_instr[11:7], {OPCODE_OP}}; - end else begin - // c.jr -> jalr x0, rd/rs1, 0 - comp_instr = {12'b0, i_instr[11:7], 3'b0, 5'b0, {OPCODE_JALR}}; - end - end else begin - if (i_instr[6:2] != 5'b0) begin - // c.add -> add rd, rd, rs2 - // (c.add hints are translated into an add hint) - comp_instr = {7'b0, i_instr[6:2], i_instr[11:7], 3'b0, i_instr[11:7], {OPCODE_OP}}; - end else begin - if (i_instr[11:7] == 5'b0) begin - // c.ebreak -> ebreak - comp_instr = {32'h00_10_00_73}; - end else begin - // c.jalr -> jalr x1, rs1, 0 - comp_instr = {12'b0, i_instr[11:7], 3'b000, 5'b00001, {OPCODE_JALR}}; - end - end - end - end - - 2'b11: begin - // c.swsp -> sw rs2, imm(x2) - comp_instr = {4'b0, i_instr[8:7], i_instr[12], i_instr[6:2], 5'h02, 3'b010, - i_instr[11:9], 2'b00, {OPCODE_STORE}}; - end - endcase - end - - // Incoming instruction is not compressed. - 2'b11: illegal_instr = 1'b1; - - endcase - end - - endmodule diff --git a/rtl/serv/serv_csr.v b/rtl/serv/serv_csr.v deleted file mode 100644 index e3100e7..0000000 --- a/rtl/serv/serv_csr.v +++ /dev/null @@ -1,164 +0,0 @@ -/* - * serv_csr.v : SERV module for handling CSR registers - * - * SPDX-FileCopyrightText: 2018 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -`default_nettype none -module serv_csr - #( - parameter RESET_STRATEGY = "MINI", - parameter W = 1, - parameter B = W-1 - ) - ( - input wire i_clk, - input wire i_rst, - //State - input wire i_trig_irq, - input wire i_en, - input wire i_cnt0to3, - input wire i_cnt3, - input wire i_cnt7, - input wire i_cnt11, - input wire i_cnt12, - input wire i_cnt_done, - input wire i_mem_op, - input wire i_mtip, - input wire i_trap, - output reg o_new_irq, - //Control - input wire i_e_op, - input wire i_ebreak, - input wire i_mem_cmd, - input wire i_mstatus_en, - input wire i_mie_en, - input wire i_mcause_en, - input wire [1:0] i_csr_source, - input wire i_mret, - input wire i_csr_d_sel, - //Data - input wire [B:0] i_rf_csr_out, - output wire [B:0] o_csr_in, - input wire [B:0] i_csr_imm, - input wire [B:0] i_rs1, - output wire [B:0] o_q); - - localparam [1:0] - CSR_SOURCE_CSR = 2'b00, - CSR_SOURCE_EXT = 2'b01, - CSR_SOURCE_SET = 2'b10, - CSR_SOURCE_CLR = 2'b11; - - reg mstatus_mie; - reg mstatus_mpie; - reg mie_mtie; - - reg mcause31; - reg [3:0] mcause3_0; - wire [B:0] mcause; - - wire [B:0] csr_in; - wire [B:0] csr_out; - - reg timer_irq_r; - - wire [B:0] d = i_csr_d_sel ? i_csr_imm : i_rs1; - - assign csr_in = (i_csr_source == CSR_SOURCE_EXT) ? d : - (i_csr_source == CSR_SOURCE_SET) ? csr_out | d : - (i_csr_source == CSR_SOURCE_CLR) ? csr_out & ~d : - (i_csr_source == CSR_SOURCE_CSR) ? csr_out : - {W{1'bx}}; - - wire [B:0] mstatus; - - generate - if (W==1) begin : gen_mstatus_w1 - assign mstatus = ((mstatus_mie & i_cnt3) | (i_cnt11 | i_cnt12)); - end else if (W==4) begin : gen_mstatus_w4 - assign mstatus = {i_cnt11 | (mstatus_mie & i_cnt3), 2'b00, i_cnt12}; - end - endgenerate - - assign csr_out = ({W{i_mstatus_en & i_en}} & mstatus) | - i_rf_csr_out | - ({W{i_mcause_en & i_en}} & mcause); - - assign o_q = csr_out; - - wire timer_irq = i_mtip & mstatus_mie & mie_mtie; - - assign mcause = i_cnt0to3 ? mcause3_0[B:0] : //[3:0] - i_cnt_done ? {mcause31,{B{1'b0}}} //[31] - : {W{1'b0}}; - - assign o_csr_in = csr_in; - - always @(posedge i_clk) begin - if (i_trig_irq) begin - timer_irq_r <= timer_irq; - o_new_irq <= timer_irq & !timer_irq_r; - end - - if (i_mie_en & i_cnt7) - mie_mtie <= csr_in[B]; - - /* - The mie bit in mstatus gets updated under three conditions - - When a trap is taken, the bit is cleared - During an mret instruction, the bit is restored from mpie - During a mstatus CSR access instruction it's assigned when - bit 3 gets updated - - These conditions are all mutually exclusive - */ - if ((i_trap & i_cnt_done) | i_mstatus_en & i_cnt3 & i_en | i_mret) - mstatus_mie <= !i_trap & (i_mret ? mstatus_mpie : csr_in[B]); - - /* - Note: To save resources mstatus_mpie (mstatus bit 7) is not - readable or writable from sw - */ - if (i_trap & i_cnt_done) - mstatus_mpie <= mstatus_mie; - - /* - The four lowest bits in mcause hold the exception code - - These bits get updated under three conditions - - During an mcause CSR access function, they are assigned when - bits 0 to 3 gets updated - - During an external interrupt the exception code is set to - 7, since SERV only support timer interrupts - - During an exception, the exception code is assigned to indicate - if it was caused by an ebreak instruction (3), - ecall instruction (11), misaligned load (4), misaligned store (6) - or misaligned jump (0) - - The expressions below are derived from the following truth table - irq => 0111 (timer=7) - e_op => x011 (ebreak=3, ecall=11) - mem => 01x0 (store=6, load=4) - ctrl => 0000 (jump=0) - */ - if (i_mcause_en & i_en & i_cnt0to3 | (i_trap & i_cnt_done)) begin - mcause3_0[3] <= (i_e_op & !i_ebreak) | (!i_trap & csr_in[B]); - mcause3_0[2] <= o_new_irq | i_mem_op | (!i_trap & ((W == 1) ? mcause3_0[3] : csr_in[(W == 1) ? 0 : 2])); - mcause3_0[1] <= o_new_irq | i_e_op | (i_mem_op & i_mem_cmd) | (!i_trap & ((W == 1) ? mcause3_0[2] : csr_in[(W == 1) ? 0 : 1])); - mcause3_0[0] <= o_new_irq | i_e_op | (!i_trap & ((W == 1) ? mcause3_0[1] : csr_in[0])); - end - if (i_mcause_en & i_cnt_done | i_trap) - mcause31 <= i_trap ? o_new_irq : csr_in[B]; - if (i_rst) - if (RESET_STRATEGY != "NONE") begin - o_new_irq <= 1'b0; - mie_mtie <= 1'b0; - end - end - -endmodule diff --git a/rtl/serv/serv_ctrl.v b/rtl/serv/serv_ctrl.v deleted file mode 100644 index 9a14711..0000000 --- a/rtl/serv/serv_ctrl.v +++ /dev/null @@ -1,115 +0,0 @@ -/* - * serv_ctrl.v : SERV module for updating program counter - * - * SPDX-FileCopyrightText: 2018 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -`default_nettype none -module serv_ctrl - #(parameter RESET_STRATEGY = "MINI", - parameter RESET_PC = 32'd0, - parameter WITH_CSR = 1, - parameter W = 1, - parameter B = W-1 - ) - ( - input wire clk, - input wire i_rst, - //State - input wire i_pc_en, - input wire i_cnt12to31, - input wire i_cnt0, - input wire i_cnt1, - input wire i_cnt2, - //Control - input wire i_jump, - input wire i_jal_or_jalr, - input wire i_utype, - input wire i_pc_rel, - input wire i_trap, - input wire i_iscomp, - //Data - input wire [B:0] i_imm, - input wire [B:0] i_buf, - input wire [B:0] i_csr_pc, - output wire [B:0] o_rd, - output wire [B:0] o_bad_pc, - //External - output reg [31:0] o_ibus_adr); - - wire [B:0] pc_plus_4; - wire pc_plus_4_cy; - reg pc_plus_4_cy_r; - wire [B:0] pc_plus_4_cy_r_w; - wire [B:0] pc_plus_offset; - wire pc_plus_offset_cy; - reg pc_plus_offset_cy_r; - wire [B:0] pc_plus_offset_cy_r_w; - wire [B:0] pc_plus_offset_aligned; - wire [B:0] plus_4; - - wire [B:0] pc = o_ibus_adr[B:0]; - - wire [B:0] new_pc; - - wire [B:0] offset_a; - wire [B:0] offset_b; - - /* If i_iscomp=1: increment pc by 2 else increment pc by 4 */ - - generate - if (W == 1) begin : gen_plus_4_w_eq_1 - assign plus_4 = i_iscomp ? i_cnt1 : i_cnt2; - end else if (W == 4) begin : gen_plus_4_w_eq_4 - assign plus_4 = (i_cnt0 | i_cnt1) ? (i_iscomp ? 2 : 4) : 0; - end - endgenerate - - assign o_bad_pc = pc_plus_offset_aligned; - - assign {pc_plus_4_cy,pc_plus_4} = pc+plus_4+pc_plus_4_cy_r_w; - - generate - if (|WITH_CSR) begin : gen_csr - if (W == 1) begin : gen_new_pc_w_eq_1 - assign new_pc = i_trap ? (i_csr_pc & !(i_cnt0 || i_cnt1)) : i_jump ? pc_plus_offset_aligned : pc_plus_4; - end else if (W == 4) begin : gen_new_pc_w_eq_4 - assign new_pc = i_trap ? (i_csr_pc & ((i_cnt0 || i_cnt1) ? 4'b1100 : 4'b1111)) : i_jump ? pc_plus_offset_aligned : pc_plus_4; - end - end else begin : gen_no_csr - assign new_pc = i_jump ? pc_plus_offset_aligned : pc_plus_4; - end - endgenerate - assign o_rd = ({W{i_utype}} & pc_plus_offset_aligned) | (pc_plus_4 & {W{i_jal_or_jalr}}); - - assign offset_a = {W{i_pc_rel}} & pc; - assign offset_b = i_utype ? (i_imm & {W{i_cnt12to31}}) : i_buf; - assign {pc_plus_offset_cy,pc_plus_offset} = offset_a+offset_b+pc_plus_offset_cy_r_w; - - generate - if (W>1) begin : gen_w_gt_1 - assign pc_plus_offset_aligned[B:1] = pc_plus_offset[B:1]; - assign pc_plus_offset_cy_r_w[B:1] = {B{1'b0}}; - assign pc_plus_4_cy_r_w[B:1] = {B{1'b0}}; - end - endgenerate - - assign pc_plus_offset_aligned[0] = pc_plus_offset[0] & !i_cnt0; - assign pc_plus_offset_cy_r_w[0] = pc_plus_offset_cy_r; - assign pc_plus_4_cy_r_w[0] = pc_plus_4_cy_r; - - initial if (RESET_STRATEGY == "NONE") o_ibus_adr = RESET_PC; - - always @(posedge clk) begin - pc_plus_4_cy_r <= i_pc_en & pc_plus_4_cy; - pc_plus_offset_cy_r <= i_pc_en & pc_plus_offset_cy; - - if (RESET_STRATEGY == "NONE") begin - if (i_pc_en) - o_ibus_adr <= {new_pc, o_ibus_adr[31:W]}; - end else begin - if (i_pc_en | i_rst) - o_ibus_adr <= i_rst ? RESET_PC : {new_pc, o_ibus_adr[31:W]}; - end - end -endmodule diff --git a/rtl/serv/serv_debug.v b/rtl/serv/serv_debug.v deleted file mode 100644 index 1d5ac68..0000000 --- a/rtl/serv/serv_debug.v +++ /dev/null @@ -1,351 +0,0 @@ -/* - * serv_debug.v : SERV module for introspecting CPU/RF state during simulations - * - * SPDX-FileCopyrightText: 2024 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -module serv_debug - #(parameter W = 1, - parameter RESET_PC = 0, - //Internally calculated. Do not touch - parameter B=W-1) - ( -`ifdef RISCV_FORMAL - output reg rvfi_valid = 1'b0, - output reg [63:0] rvfi_order = 64'd0, - output reg [31:0] rvfi_insn = 32'd0, - output reg rvfi_trap = 1'b0, - output reg rvfi_halt = 1'b0, // Not used - output reg rvfi_intr = 1'b0, // Not used - output reg [1:0] rvfi_mode = 2'b11, // Not used - output reg [1:0] rvfi_ixl = 2'b01, // Not used - output reg [4:0] rvfi_rs1_addr, - output reg [4:0] rvfi_rs2_addr, - output reg [31:0] rvfi_rs1_rdata, - output reg [31:0] rvfi_rs2_rdata, - output reg [4:0] rvfi_rd_addr, - output wire [31:0] rvfi_rd_wdata, - output reg [31:0] rvfi_pc_rdata, - output wire [31:0] rvfi_pc_wdata, - output reg [31:0] rvfi_mem_addr, - output reg [3:0] rvfi_mem_rmask, - output reg [3:0] rvfi_mem_wmask, - output reg [31:0] rvfi_mem_rdata, - output reg [31:0] rvfi_mem_wdata, - input wire [31:0] i_dbus_adr, - input wire [31:0] i_dbus_dat, - input wire [3:0] i_dbus_sel, - input wire i_dbus_we, - input wire [31:0] i_dbus_rdt, - input wire i_dbus_ack, - input wire i_ctrl_pc_en, - input wire [B:0] rs1, - input wire [B:0] rs2, - input wire [4:0] rs1_addr, - input wire [4:0] rs2_addr, - input wire [3:0] immdec_en, - input wire rd_en, - input wire trap, - input wire i_rf_ready, - input wire i_ibus_cyc, - input wire two_stage_op, - input wire init, - input wire [31:0] i_ibus_adr, -`endif - input wire i_clk, - input wire i_rst, - input wire [31:0] i_ibus_rdt, - input wire i_ibus_ack, - input wire [4:0] i_rd_addr, - input wire i_cnt_en, - input wire [B:0] i_csr_in, - input wire i_csr_mstatus_en, - input wire i_csr_mie_en, - input wire i_csr_mcause_en, - input wire i_csr_en, - input wire [1:0] i_csr_addr, - input wire i_wen0, - input wire [B:0] i_wdata0, - input wire i_cnt_done); - - reg update_rd = 1'b0; - reg update_mscratch; - reg update_mtvec; - reg update_mepc; - reg update_mtval; - reg update_mstatus; - reg update_mie; - reg update_mcause; - - reg [31:0] dbg_rd = 32'hxxxxxxxx; - reg [31:0] dbg_csr = 32'hxxxxxxxx; - reg [31:0] dbg_mstatus = 32'hxxxxxxxx; - reg [31:0] dbg_mie = 32'hxxxxxxxx; - reg [31:0] dbg_mcause = 32'hxxxxxxxx; - reg [31:0] dbg_mscratch = 32'hxxxxxxxx; - reg [31:0] dbg_mtvec = 32'hxxxxxxxx; - reg [31:0] dbg_mepc = 32'hxxxxxxxx; - reg [31:0] dbg_mtval = 32'hxxxxxxxx; - reg [31:0] x1 = 32'hxxxxxxxx; - reg [31:0] x2 = 32'hxxxxxxxx; - reg [31:0] x3 = 32'hxxxxxxxx; - reg [31:0] x4 = 32'hxxxxxxxx; - reg [31:0] x5 = 32'hxxxxxxxx; - reg [31:0] x6 = 32'hxxxxxxxx; - reg [31:0] x7 = 32'hxxxxxxxx; - reg [31:0] x8 = 32'hxxxxxxxx; - reg [31:0] x9 = 32'hxxxxxxxx; - reg [31:0] x10 = 32'hxxxxxxxx; - reg [31:0] x11 = 32'hxxxxxxxx; - reg [31:0] x12 = 32'hxxxxxxxx; - reg [31:0] x13 = 32'hxxxxxxxx; - reg [31:0] x14 = 32'hxxxxxxxx; - reg [31:0] x15 = 32'hxxxxxxxx; - reg [31:0] x16 = 32'hxxxxxxxx; - reg [31:0] x17 = 32'hxxxxxxxx; - reg [31:0] x18 = 32'hxxxxxxxx; - reg [31:0] x19 = 32'hxxxxxxxx; - reg [31:0] x20 = 32'hxxxxxxxx; - reg [31:0] x21 = 32'hxxxxxxxx; - reg [31:0] x22 = 32'hxxxxxxxx; - reg [31:0] x23 = 32'hxxxxxxxx; - reg [31:0] x24 = 32'hxxxxxxxx; - reg [31:0] x25 = 32'hxxxxxxxx; - reg [31:0] x26 = 32'hxxxxxxxx; - reg [31:0] x27 = 32'hxxxxxxxx; - reg [31:0] x28 = 32'hxxxxxxxx; - reg [31:0] x29 = 32'hxxxxxxxx; - reg [31:0] x30 = 32'hxxxxxxxx; - reg [31:0] x31 = 32'hxxxxxxxx; - - always @(posedge i_clk) begin - update_rd <= i_cnt_done & i_wen0; - - if (i_wen0) - dbg_rd <= {i_wdata0,dbg_rd[31:W]}; - - //End of instruction that writes to RF - if (update_rd) begin - case (i_rd_addr) - 5'd1 : x1 <= dbg_rd; - 5'd2 : x2 <= dbg_rd; - 5'd3 : x3 <= dbg_rd; - 5'd4 : x4 <= dbg_rd; - 5'd5 : x5 <= dbg_rd; - 5'd6 : x6 <= dbg_rd; - 5'd7 : x7 <= dbg_rd; - 5'd8 : x8 <= dbg_rd; - 5'd9 : x9 <= dbg_rd; - 5'd10 : x10 <= dbg_rd; - 5'd11 : x11 <= dbg_rd; - 5'd12 : x12 <= dbg_rd; - 5'd13 : x13 <= dbg_rd; - 5'd14 : x14 <= dbg_rd; - 5'd15 : x15 <= dbg_rd; - 5'd16 : x16 <= dbg_rd; - 5'd17 : x17 <= dbg_rd; - 5'd18 : x18 <= dbg_rd; - 5'd19 : x19 <= dbg_rd; - 5'd20 : x20 <= dbg_rd; - 5'd21 : x21 <= dbg_rd; - 5'd22 : x22 <= dbg_rd; - 5'd23 : x23 <= dbg_rd; - 5'd24 : x24 <= dbg_rd; - 5'd25 : x25 <= dbg_rd; - 5'd26 : x26 <= dbg_rd; - 5'd27 : x27 <= dbg_rd; - 5'd28 : x28 <= dbg_rd; - 5'd29 : x29 <= dbg_rd; - 5'd30 : x30 <= dbg_rd; - 5'd31 : x31 <= dbg_rd; - default : ; - endcase - end - - update_mscratch <= i_cnt_done & i_csr_en & (i_csr_addr == 2'b00); - update_mtvec <= i_cnt_done & i_csr_en & (i_csr_addr == 2'b01); - update_mepc <= i_cnt_done & i_csr_en & (i_csr_addr == 2'b10); - update_mtval <= i_cnt_done & i_csr_en & (i_csr_addr == 2'b11); - update_mstatus <= i_cnt_done & i_csr_mstatus_en; - update_mie <= i_cnt_done & i_csr_mie_en; - update_mcause <= i_cnt_done & i_csr_mcause_en; - - if (i_cnt_en) - dbg_csr <= {i_csr_in, dbg_csr[31:W]}; - - if (update_mscratch) dbg_mscratch <= dbg_csr; - if (update_mtvec) dbg_mtvec <= dbg_csr; - if (update_mepc ) dbg_mepc <= dbg_csr; - if (update_mtval) dbg_mtval <= dbg_csr; - if (update_mstatus) dbg_mstatus <= dbg_csr; - if (update_mie) dbg_mie <= dbg_csr; - if (update_mcause) dbg_mcause <= dbg_csr; - end - - reg LUI, AUIPC, JAL, JALR, BEQ, BNE, BLT, BGE, BLTU, BGEU, LB, LH, LW, LBU, LHU, SB, SH, SW, ADDI, SLTI, SLTIU, XORI, ORI, ANDI,SLLI, SRLI, SRAI, ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND, FENCE, ECALL, EBREAK; - reg CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI; - reg OTHER; - - always @(posedge i_clk) begin - if (i_ibus_ack) begin - LUI <= 1'b0; - AUIPC <= 1'b0; - JAL <= 1'b0; - JALR <= 1'b0; - BEQ <= 1'b0; - BNE <= 1'b0; - BLT <= 1'b0; - BGE <= 1'b0; - BLTU <= 1'b0; - BGEU <= 1'b0; - LB <= 1'b0; - LH <= 1'b0; - LW <= 1'b0; - LBU <= 1'b0; - LHU <= 1'b0; - SB <= 1'b0; - SH <= 1'b0; - SW <= 1'b0; - ADDI <= 1'b0; - SLTI <= 1'b0; - SLTIU <= 1'b0; - XORI <= 1'b0; - ORI <= 1'b0; - ANDI <= 1'b0; - SLLI <= 1'b0; - SRLI <= 1'b0; - SRAI <= 1'b0; - ADD <= 1'b0; - SUB <= 1'b0; - SLL <= 1'b0; - SLT <= 1'b0; - SLTU <= 1'b0; - XOR <= 1'b0; - SRL <= 1'b0; - SRA <= 1'b0; - OR <= 1'b0; - AND <= 1'b0; - FENCE <= 1'b0; - ECALL <= 1'b0; - EBREAK <= 1'b0; - CSRRW <= 1'b0; - CSRRS <= 1'b0; - CSRRC <= 1'b0; - CSRRWI <= 1'b0; - CSRRSI <= 1'b0; - CSRRCI <= 1'b0; - OTHER <= 1'b0; - - casez(i_ibus_rdt) - // 3322222_22222 11111_111 11 - // 1098765_43210 98765_432 10987_65432_10 - 32'b???????_?????_?????_???_?????_01101_11 : LUI <= 1'b1; - 32'b???????_?????_?????_???_?????_00101_11 : AUIPC <= 1'b1; - 32'b???????_?????_?????_???_?????_11011_11 : JAL <= 1'b1; - 32'b???????_?????_?????_000_?????_11001_11 : JALR <= 1'b1; - 32'b???????_?????_?????_000_?????_11000_11 : BEQ <= 1'b1; - 32'b???????_?????_?????_001_?????_11000_11 : BNE <= 1'b1; - 32'b???????_?????_?????_100_?????_11000_11 : BLT <= 1'b1; - 32'b???????_?????_?????_101_?????_11000_11 : BGE <= 1'b1; - 32'b???????_?????_?????_110_?????_11000_11 : BLTU <= 1'b1; - 32'b???????_?????_?????_111_?????_11000_11 : BGEU <= 1'b1; - 32'b???????_?????_?????_000_?????_00000_11 : LB <= 1'b1; - 32'b???????_?????_?????_001_?????_00000_11 : LH <= 1'b1; - 32'b???????_?????_?????_010_?????_00000_11 : LW <= 1'b1; - 32'b???????_?????_?????_100_?????_00000_11 : LBU <= 1'b1; - 32'b???????_?????_?????_101_?????_00000_11 : LHU <= 1'b1; - 32'b???????_?????_?????_000_?????_01000_11 : SB <= 1'b1; - 32'b???????_?????_?????_001_?????_01000_11 : SH <= 1'b1; - 32'b???????_?????_?????_010_?????_01000_11 : SW <= 1'b1; - 32'b???????_?????_?????_000_?????_00100_11 : ADDI <= 1'b1; - 32'b???????_?????_?????_010_?????_00100_11 : SLTI <= 1'b1; - 32'b???????_?????_?????_011_?????_00100_11 : SLTIU <= 1'b1; - 32'b???????_?????_?????_100_?????_00100_11 : XORI <= 1'b1; - 32'b???????_?????_?????_110_?????_00100_11 : ORI <= 1'b1; - 32'b???????_?????_?????_111_?????_00100_11 : ANDI <= 1'b1; - 32'b0000000_?????_?????_001_?????_00100_11 : SLLI <= 1'b1; - 32'b0000000_?????_?????_101_?????_00100_11 : SRLI <= 1'b1; - 32'b0100000_?????_?????_101_?????_00100_11 : SRAI <= 1'b1; - 32'b0000000_?????_?????_000_?????_01100_11 : ADD <= 1'b1; - 32'b0100000_?????_?????_000_?????_01100_11 : SUB <= 1'b1; - 32'b0000000_?????_?????_001_?????_01100_11 : SLL <= 1'b1; - 32'b0000000_?????_?????_010_?????_01100_11 : SLT <= 1'b1; - 32'b0000000_?????_?????_011_?????_01100_11 : SLTU <= 1'b1; - 32'b???????_?????_?????_100_?????_01100_11 : XOR <= 1'b1; - 32'b0000000_?????_?????_101_?????_01100_11 : SRL <= 1'b1; - 32'b0100000_?????_?????_101_?????_01100_11 : SRA <= 1'b1; - 32'b???????_?????_?????_110_?????_01100_11 : OR <= 1'b1; - 32'b???????_?????_?????_111_?????_01100_11 : AND <= 1'b1; - 32'b???????_?????_?????_000_?????_00011_11 : FENCE <= 1'b1; - 32'b0000000_00000_00000_000_00000_11100_11 : ECALL <= 1'b1; - 32'b0000000_00001_00000_000_00000_11100_11 : EBREAK <= 1'b1; - 32'b???????_?????_?????_001_?????_11100_11 : CSRRW <= 1'b1; - 32'b???????_?????_?????_010_?????_11100_11 : CSRRS <= 1'b1; - 32'b???????_?????_?????_011_?????_11100_11 : CSRRC <= 1'b1; - 32'b???????_?????_?????_101_?????_11100_11 : CSRRWI <= 1'b1; - 32'b???????_?????_?????_110_?????_11100_11 : CSRRSI <= 1'b1; - 32'b???????_?????_?????_111_?????_11100_11 : CSRRCI <= 1'b1; - default : OTHER <= 1'b1; - endcase - end - end - -`ifdef RISCV_FORMAL - reg [31:0] pc = RESET_PC; - - wire rs_en = two_stage_op ? init : i_ctrl_pc_en; - - assign rvfi_rd_wdata = update_rd ? dbg_rd : 32'd0; - - always @(posedge i_clk) begin - /* End of instruction */ - rvfi_valid <= i_cnt_done & i_ctrl_pc_en & !i_rst; - rvfi_order <= rvfi_order + {63'd0,rvfi_valid}; - - /* Get instruction word when it's fetched from ibus */ - if (i_ibus_cyc & i_ibus_ack) - rvfi_insn <= i_ibus_rdt; - - - if (i_cnt_done & i_ctrl_pc_en) begin - rvfi_pc_rdata <= pc; - if (!(rd_en & (|i_rd_addr))) begin - rvfi_rd_addr <= 5'd0; - end - end - rvfi_trap <= trap; - if (rvfi_valid) begin - rvfi_trap <= 1'b0; - pc <= rvfi_pc_wdata; - end - - /* RS1 not valid during J, U instructions (immdec_en[1]) */ - /* RS2 not valid during I, J, U instructions (immdec_en[2]) */ - if (i_rf_ready) begin - rvfi_rs1_addr <= !immdec_en[1] ? rs1_addr : 5'd0; - rvfi_rs2_addr <= !immdec_en[2] /*rs2_valid*/ ? rs2_addr : 5'd0; - rvfi_rd_addr <= i_rd_addr; - end - if (rs_en) begin - rvfi_rs1_rdata <= {(!immdec_en[1] ? rs1 : {W{1'b0}}),rvfi_rs1_rdata[31:W]}; - rvfi_rs2_rdata <= {(!immdec_en[2] ? rs2 : {W{1'b0}}),rvfi_rs2_rdata[31:W]}; - end - - if (i_dbus_ack) begin - rvfi_mem_addr <= i_dbus_adr; - rvfi_mem_rmask <= i_dbus_we ? 4'b0000 : i_dbus_sel; - rvfi_mem_wmask <= i_dbus_we ? i_dbus_sel : 4'b0000; - rvfi_mem_rdata <= i_dbus_rdt; - rvfi_mem_wdata <= i_dbus_dat; - end - if (i_ibus_ack) begin - rvfi_mem_rmask <= 4'b0000; - rvfi_mem_wmask <= 4'b0000; - end - end - - assign rvfi_pc_wdata = i_ibus_adr; - -`endif - -endmodule diff --git a/rtl/serv/serv_decode.v b/rtl/serv/serv_decode.v deleted file mode 100644 index 5a9c34c..0000000 --- a/rtl/serv/serv_decode.v +++ /dev/null @@ -1,367 +0,0 @@ -/* - * serv_decode.v : SERV module decoding instruction word into control signals - * - * SPDX-FileCopyrightText: 2018 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -`default_nettype none -module serv_decode - #(parameter [0:0] PRE_REGISTER = 1, - parameter [0:0] MDU = 0) - ( - input wire clk, - //Input - input wire [31:2] i_wb_rdt, - input wire i_wb_en, - //To state - output reg o_sh_right, - output reg o_bne_or_bge, - output reg o_cond_branch, - output reg o_e_op, - output reg o_ebreak, - output reg o_branch_op, - output reg o_shift_op, - output reg o_rd_op, - output reg o_two_stage_op, - output reg o_dbus_en, - //MDU - output reg o_mdu_op, - //Extension - output reg [2:0] o_ext_funct3, - //To bufreg - output reg o_bufreg_rs1_en, - output reg o_bufreg_imm_en, - output reg o_bufreg_clr_lsb, - output reg o_bufreg_sh_signed, - //To ctrl - output reg o_ctrl_jal_or_jalr, - output reg o_ctrl_utype, - output reg o_ctrl_pc_rel, - output reg o_ctrl_mret, - //To alu - output reg o_alu_sub, - output reg [1:0] o_alu_bool_op, - output reg o_alu_cmp_eq, - output reg o_alu_cmp_sig, - output reg [2:0] o_alu_rd_sel, - //To mem IF - output reg o_mem_signed, - output reg o_mem_word, - output reg o_mem_half, - output reg o_mem_cmd, - //To CSR - output reg o_csr_en, - output reg [1:0] o_csr_addr, - output reg o_csr_mstatus_en, - output reg o_csr_mie_en, - output reg o_csr_mcause_en, - output reg [1:0] o_csr_source, - output reg o_csr_d_sel, - output reg o_csr_imm_en, - output reg o_mtval_pc, - //To top - output reg [3:0] o_immdec_ctrl, - output reg [3:0] o_immdec_en, - output reg o_op_b_source, - //To RF IF - output reg o_rd_mem_en, - output reg o_rd_csr_en, - output reg o_rd_alu_en); - - reg [4:0] opcode; - reg [2:0] funct3; - reg op20; - reg op21; - reg op22; - reg op26; - - reg imm25; - reg imm30; - - wire co_mdu_op = MDU & (opcode == 5'b01100) & imm25; - - wire co_two_stage_op = - ~opcode[2] | (funct3[0] & ~funct3[1] & ~opcode[0] & ~opcode[4]) | - (funct3[1] & ~funct3[2] & ~opcode[0] & ~opcode[4]) | co_mdu_op; - wire co_shift_op = (opcode[2] & ~funct3[1]) & !co_mdu_op; - wire co_branch_op = opcode[4]; - wire co_dbus_en = ~opcode[2] & ~opcode[4]; - wire co_mtval_pc = opcode[4]; - wire co_mem_word = funct3[1]; - wire co_rd_alu_en = !opcode[0] & opcode[2] & !opcode[4] & !co_mdu_op; - wire co_rd_mem_en = (!opcode[2] & !opcode[0]) | co_mdu_op; - wire [2:0] co_ext_funct3 = funct3; - - //jal,branch = imm - //jalr = rs1+imm - //mem = rs1+imm - //shift = rs1 - wire co_bufreg_rs1_en = !opcode[4] | (!opcode[1] & opcode[0]); - wire co_bufreg_imm_en = !opcode[2]; - - //Clear LSB of immediate for BRANCH and JAL ops - //True for BRANCH and JAL - //False for JALR/LOAD/STORE/OP/OPIMM? - wire co_bufreg_clr_lsb = opcode[4] & ((opcode[1:0] == 2'b00) | (opcode[1:0] == 2'b11)); - - //Conditional branch - //True for BRANCH - //False for JAL/JALR - wire co_cond_branch = !opcode[0]; - - wire co_ctrl_utype = !opcode[4] & opcode[2] & opcode[0]; - wire co_ctrl_jal_or_jalr = opcode[4] & opcode[0]; - - //PC-relative operations - //True for jal, b* auipc, ebreak - //False for jalr, lui - wire co_ctrl_pc_rel = (opcode[2:0] == 3'b000) | - (opcode[1:0] == 2'b11) | - (opcode[4] & opcode[2]) & op20| - (opcode[4:3] == 2'b00); - //Write to RD - //True for OP-IMM, AUIPC, OP, LUI, SYSTEM, JALR, JAL, LOAD - //False for STORE, BRANCH, MISC-MEM - wire co_rd_op = (opcode[2] | - (!opcode[2] & opcode[4] & opcode[0]) | - (!opcode[2] & !opcode[3] & !opcode[0])); - - // - //funct3 - // - - wire co_sh_right = funct3[2]; - wire co_bne_or_bge = funct3[0]; - - //Matches system ops except ecall/ebreak/mret - wire csr_op = opcode[4] & opcode[2] & (|funct3); - - - //op20 - wire co_ebreak = op20; - - - //opcode & funct3 & op21 - - wire co_ctrl_mret = opcode[4] & opcode[2] & op21 & !(|funct3); - //Matches system opcodes except CSR accesses (funct3 == 0) - //and mret (!op21) - wire co_e_op = opcode[4] & opcode[2] & !op21 & !(|funct3); - - //opcode & funct3 & imm30 - - wire co_bufreg_sh_signed = imm30; - - /* - True for sub, b*, slt* - False for add* - op opcode f3 i30 - b* 11000 xxx x t - addi 00100 000 x f - slt* 0x100 01x x t - add 01100 000 0 f - sub 01100 000 1 t - */ - wire co_alu_sub = funct3[1] | funct3[0] | (opcode[3] & imm30) | opcode[4]; - - /* - Bits 26, 22, 21 and 20 are enough to uniquely identify the eight supported CSR regs - mtvec, mscratch, mepc and mtval are stored externally (normally in the RF) and are - treated differently from mstatus, mie and mcause which are stored in serv_csr. - - The former get a 2-bit address as seen below while the latter get a - one-hot enable signal each. - - Hex|2 222|Reg |csr - adr|6 210|name |addr - ---|-----|--------|---- - 300|0_000|mstatus | xx - 304|0_100|mie | xx - 305|0_101|mtvec | 01 - 340|1_000|mscratch| 00 - 341|1_001|mepc | 10 - 342|1_010|mcause | xx - 343|1_011|mtval | 11 - - */ - - //true for mtvec,mscratch,mepc and mtval - //false for mstatus, mie, mcause - wire csr_valid = op20 | (op26 & !op21); - - wire co_rd_csr_en = csr_op; - - wire co_csr_en = csr_op & csr_valid; - wire co_csr_mstatus_en = csr_op & !op26 & !op22 & !op20; - wire co_csr_mie_en = csr_op & !op26 & op22 & !op20; - wire co_csr_mcause_en = csr_op & op21 & !op20; - - wire [1:0] co_csr_source = funct3[1:0]; - wire co_csr_d_sel = funct3[2]; - wire co_csr_imm_en = opcode[4] & opcode[2] & funct3[2]; - wire [1:0] co_csr_addr = {op26 & op20, !op26 | op21}; - - wire co_alu_cmp_eq = funct3[2:1] == 2'b00; - - wire co_alu_cmp_sig = ~((funct3[0] & funct3[1]) | (funct3[1] & funct3[2])); - - wire co_mem_cmd = opcode[3]; - wire co_mem_signed = ~funct3[2]; - wire co_mem_half = funct3[0]; - - wire [1:0] co_alu_bool_op = funct3[1:0]; - - wire [3:0] co_immdec_ctrl; - //True for S (STORE) or B (BRANCH) type instructions - //False for J type instructions - assign co_immdec_ctrl[0] = opcode[3:0] == 4'b1000; - //True for OP-IMM, LOAD, STORE, JALR (I S) - //False for LUI, AUIPC, JAL (U J) - assign co_immdec_ctrl[1] = (opcode[1:0] == 2'b00) | (opcode[2:1] == 2'b00); - assign co_immdec_ctrl[2] = opcode[4] & !opcode[0]; - assign co_immdec_ctrl[3] = opcode[4]; - - wire [3:0] co_immdec_en; - assign co_immdec_en[3] = opcode[4] | opcode[3] | opcode[2] | !opcode[0]; //B I J S U - assign co_immdec_en[2] = (opcode[4] & opcode[2]) | !opcode[3] | opcode[0]; // I J U - assign co_immdec_en[1] = (opcode[2:1] == 2'b01) | (opcode[2] & opcode[0]) | co_csr_imm_en;// J U - assign co_immdec_en[0] = ~co_rd_op; //B S - - wire [2:0] co_alu_rd_sel; - assign co_alu_rd_sel[0] = (funct3 == 3'b000); // Add/sub - assign co_alu_rd_sel[1] = (funct3[2:1] == 2'b01); //SLT* - assign co_alu_rd_sel[2] = funct3[2]; //Bool - - //0 (OP_B_SOURCE_IMM) when OPIMM - //1 (OP_B_SOURCE_RS2) when BRANCH or OP - wire co_op_b_source = opcode[3]; - - generate - if (PRE_REGISTER) begin : gen_pre_register - - always @(posedge clk) begin - if (i_wb_en) begin - funct3 <= i_wb_rdt[14:12]; - imm30 <= i_wb_rdt[30]; - imm25 <= i_wb_rdt[25]; - opcode <= i_wb_rdt[6:2]; - op20 <= i_wb_rdt[20]; - op21 <= i_wb_rdt[21]; - op22 <= i_wb_rdt[22]; - op26 <= i_wb_rdt[26]; - end - end - - always @(*) begin - o_sh_right = co_sh_right; - o_bne_or_bge = co_bne_or_bge; - o_cond_branch = co_cond_branch; - o_dbus_en = co_dbus_en; - o_mtval_pc = co_mtval_pc; - o_two_stage_op = co_two_stage_op; - o_e_op = co_e_op; - o_ebreak = co_ebreak; - o_branch_op = co_branch_op; - o_shift_op = co_shift_op; - o_rd_op = co_rd_op; - o_mdu_op = co_mdu_op; - o_ext_funct3 = co_ext_funct3; - o_bufreg_rs1_en = co_bufreg_rs1_en; - o_bufreg_imm_en = co_bufreg_imm_en; - o_bufreg_clr_lsb = co_bufreg_clr_lsb; - o_bufreg_sh_signed = co_bufreg_sh_signed; - o_ctrl_jal_or_jalr = co_ctrl_jal_or_jalr; - o_ctrl_utype = co_ctrl_utype; - o_ctrl_pc_rel = co_ctrl_pc_rel; - o_ctrl_mret = co_ctrl_mret; - o_alu_sub = co_alu_sub; - o_alu_bool_op = co_alu_bool_op; - o_alu_cmp_eq = co_alu_cmp_eq; - o_alu_cmp_sig = co_alu_cmp_sig; - o_alu_rd_sel = co_alu_rd_sel; - o_mem_signed = co_mem_signed; - o_mem_word = co_mem_word; - o_mem_half = co_mem_half; - o_mem_cmd = co_mem_cmd; - o_csr_en = co_csr_en; - o_csr_addr = co_csr_addr; - o_csr_mstatus_en = co_csr_mstatus_en; - o_csr_mie_en = co_csr_mie_en; - o_csr_mcause_en = co_csr_mcause_en; - o_csr_source = co_csr_source; - o_csr_d_sel = co_csr_d_sel; - o_csr_imm_en = co_csr_imm_en; - o_immdec_ctrl = co_immdec_ctrl; - o_immdec_en = co_immdec_en; - o_op_b_source = co_op_b_source; - o_rd_csr_en = co_rd_csr_en; - o_rd_alu_en = co_rd_alu_en; - o_rd_mem_en = co_rd_mem_en; - end - - end else begin : gen_post_register - - always @(*) begin - funct3 = i_wb_rdt[14:12]; - imm30 = i_wb_rdt[30]; - imm25 = i_wb_rdt[25]; - opcode = i_wb_rdt[6:2]; - op20 = i_wb_rdt[20]; - op21 = i_wb_rdt[21]; - op22 = i_wb_rdt[22]; - op26 = i_wb_rdt[26]; - end - - always @(posedge clk) begin - if (i_wb_en) begin - o_sh_right <= co_sh_right; - o_bne_or_bge <= co_bne_or_bge; - o_cond_branch <= co_cond_branch; - o_e_op <= co_e_op; - o_ebreak <= co_ebreak; - o_two_stage_op <= co_two_stage_op; - o_dbus_en <= co_dbus_en; - o_mtval_pc <= co_mtval_pc; - o_branch_op <= co_branch_op; - o_shift_op <= co_shift_op; - o_rd_op <= co_rd_op; - o_mdu_op <= co_mdu_op; - o_ext_funct3 <= co_ext_funct3; - o_bufreg_rs1_en <= co_bufreg_rs1_en; - o_bufreg_imm_en <= co_bufreg_imm_en; - o_bufreg_clr_lsb <= co_bufreg_clr_lsb; - o_bufreg_sh_signed <= co_bufreg_sh_signed; - o_ctrl_jal_or_jalr <= co_ctrl_jal_or_jalr; - o_ctrl_utype <= co_ctrl_utype; - o_ctrl_pc_rel <= co_ctrl_pc_rel; - o_ctrl_mret <= co_ctrl_mret; - o_alu_sub <= co_alu_sub; - o_alu_bool_op <= co_alu_bool_op; - o_alu_cmp_eq <= co_alu_cmp_eq; - o_alu_cmp_sig <= co_alu_cmp_sig; - o_alu_rd_sel <= co_alu_rd_sel; - o_mem_signed <= co_mem_signed; - o_mem_word <= co_mem_word; - o_mem_half <= co_mem_half; - o_mem_cmd <= co_mem_cmd; - o_csr_en <= co_csr_en; - o_csr_addr <= co_csr_addr; - o_csr_mstatus_en <= co_csr_mstatus_en; - o_csr_mie_en <= co_csr_mie_en; - o_csr_mcause_en <= co_csr_mcause_en; - o_csr_source <= co_csr_source; - o_csr_d_sel <= co_csr_d_sel; - o_csr_imm_en <= co_csr_imm_en; - o_immdec_ctrl <= co_immdec_ctrl; - o_immdec_en <= co_immdec_en; - o_op_b_source <= co_op_b_source; - o_rd_csr_en <= co_rd_csr_en; - o_rd_alu_en <= co_rd_alu_en; - o_rd_mem_en <= co_rd_mem_en; - end - end - - end - endgenerate - -endmodule diff --git a/rtl/serv/serv_immdec.v b/rtl/serv/serv_immdec.v deleted file mode 100644 index e31cbb3..0000000 --- a/rtl/serv/serv_immdec.v +++ /dev/null @@ -1,234 +0,0 @@ -/* - * serv_immdec.v : SERV module for decoding immediates from instruction words - * - * SPDX-FileCopyrightText: 2020 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -`default_nettype none -module serv_immdec - #(parameter SHARED_RFADDR_IMM_REGS = 1, - parameter W = 1) - ( - input wire i_clk, - //State - input wire i_cnt_en, - input wire i_cnt_done, - //Control - input wire [3:0] i_immdec_en, - input wire i_csr_imm_en, - input wire [3:0] i_ctrl, - output wire [4:0] o_rd_addr, - output wire [4:0] o_rs1_addr, - output wire [4:0] o_rs2_addr, - //Data - output wire [W-1:0] o_csr_imm, - output wire [W-1:0] o_imm, - //External - input wire i_wb_en, - input wire [31:7] i_wb_rdt); - -generate - if (W == 1) begin : gen_immdec_w_eq_1 - reg imm31; - - reg [8:0] imm19_12_20; - reg imm7; - reg [5:0] imm30_25; - reg [4:0] imm24_20; - reg [4:0] imm11_7; - - assign o_csr_imm = imm19_12_20[4]; - - wire signbit = imm31 & !i_csr_imm_en; - - if (SHARED_RFADDR_IMM_REGS) begin : gen_shared_imm_regs - assign o_rs1_addr = imm19_12_20[8:4]; - assign o_rs2_addr = imm24_20; - assign o_rd_addr = imm11_7; - - always @(posedge i_clk) begin - if (i_wb_en) begin - /* CSR immediates are always zero-extended, hence clear the signbit */ - imm31 <= i_wb_rdt[31]; - end - if (i_wb_en | (i_cnt_en & i_immdec_en[1])) - imm19_12_20 <= i_wb_en ? {i_wb_rdt[19:12],i_wb_rdt[20]} : {i_ctrl[3] ? signbit : imm24_20[0], imm19_12_20[8:1]}; - if (i_wb_en | (i_cnt_en)) - imm7 <= i_wb_en ? i_wb_rdt[7] : signbit; - - if (i_wb_en | (i_cnt_en & i_immdec_en[3])) - imm30_25 <= i_wb_en ? i_wb_rdt[30:25] : {i_ctrl[2] ? imm7 : i_ctrl[1] ? signbit : imm19_12_20[0], imm30_25[5:1]}; - - if (i_wb_en | (i_cnt_en & i_immdec_en[2])) - imm24_20 <= i_wb_en ? i_wb_rdt[24:20] : {imm30_25[0], imm24_20[4:1]}; - - if (i_wb_en | (i_cnt_en & i_immdec_en[0])) - imm11_7 <= i_wb_en ? i_wb_rdt[11:7] : {imm30_25[0], imm11_7[4:1]}; - end - end else begin : gen_separate_imm_regs - reg [4:0] rd_addr; - reg [4:0] rs1_addr; - reg [4:0] rs2_addr; - - assign o_rd_addr = rd_addr; - assign o_rs1_addr = rs1_addr; - assign o_rs2_addr = rs2_addr; - always @(posedge i_clk) begin - if (i_wb_en) begin - /* CSR immediates are always zero-extended, hence clear the signbit */ - imm31 <= i_wb_rdt[31]; - imm19_12_20 <= {i_wb_rdt[19:12],i_wb_rdt[20]}; - imm7 <= i_wb_rdt[7]; - imm30_25 <= i_wb_rdt[30:25]; - imm24_20 <= i_wb_rdt[24:20]; - imm11_7 <= i_wb_rdt[11:7]; - - rd_addr <= i_wb_rdt[11:7]; - rs1_addr <= i_wb_rdt[19:15]; - rs2_addr <= i_wb_rdt[24:20]; - end - if (i_cnt_en) begin - imm19_12_20 <= {i_ctrl[3] ? signbit : imm24_20[0], imm19_12_20[8:1]}; - imm7 <= signbit; - imm30_25 <= {i_ctrl[2] ? imm7 : i_ctrl[1] ? signbit : imm19_12_20[0], imm30_25[5:1]}; - imm24_20 <= {imm30_25[0], imm24_20[4:1]}; - imm11_7 <= {imm30_25[0], imm11_7[4:1]}; - end - end - end - - assign o_imm = i_cnt_done ? signbit : i_ctrl[0] ? imm11_7[0] : imm24_20[0]; - end else begin : gen_immdec_w_eq_4 - reg [4:0] rd_addr; - reg [4:0] rs1_addr; - reg [4:0] rs2_addr; - - reg i31; - reg i30; - reg i29; - reg i28; - reg i27; - reg i26; - reg i25; - reg i24; - reg i23; - reg i22; - reg i21; - reg i20; - reg i19; - reg i18; - reg i17; - reg i16; - reg i15; - reg i14; - reg i13; - reg i12; - reg i11; - reg i10; - reg i9; - reg i8; - reg i7; - - reg i7_2; - reg i20_2; - - wire signbit = i31 & !i_csr_imm_en; - - assign o_csr_imm[3] = i18; - assign o_csr_imm[2] = i17; - assign o_csr_imm[1] = i16; - assign o_csr_imm[0] = i15; - - assign o_rd_addr = rd_addr; - assign o_rs1_addr = rs1_addr; - assign o_rs2_addr = rs2_addr; - always @(posedge i_clk) begin - if (i_wb_en) begin - //Common - i31 <= i_wb_rdt[31]; - - //Bit lane 3 - i19 <= i_wb_rdt[19]; - i15 <= i_wb_rdt[15]; - i20 <= i_wb_rdt[20]; - i7 <= i_wb_rdt[7]; - i27 <= i_wb_rdt[27]; - i23 <= i_wb_rdt[23]; - i10 <= i_wb_rdt[10]; - - //Bit lane 2 - i22 <= i_wb_rdt[22]; - i9 <= i_wb_rdt[ 9]; - i26 <= i_wb_rdt[26]; - i30 <= i_wb_rdt[30]; - i14 <= i_wb_rdt[14]; - i18 <= i_wb_rdt[18]; - - //Bit lane 1 - i21 <= i_wb_rdt[21]; - i8 <= i_wb_rdt[ 8]; - i25 <= i_wb_rdt[25]; - i29 <= i_wb_rdt[29]; - i13 <= i_wb_rdt[13]; - i17 <= i_wb_rdt[17]; - - //Bit lane 0 - i11 <= i_wb_rdt[11]; - i7_2 <= i_wb_rdt[7 ]; - i20_2 <= i_wb_rdt[20]; - i24 <= i_wb_rdt[24]; - i28 <= i_wb_rdt[28]; - i12 <= i_wb_rdt[12]; - i16 <= i_wb_rdt[16]; - - rd_addr <= i_wb_rdt[11:7]; - rs1_addr <= i_wb_rdt[19:15]; - rs2_addr <= i_wb_rdt[24:20]; - end - if (i_cnt_en) begin - //Bit lane 3 - i10 <= i27; - i23 <= i27; - i27 <= i_ctrl[2] ? i7 : i_ctrl[1] ? signbit : i20; - i7 <= signbit; - i20 <= i15; - i15 <= i19; - i19 <= i_ctrl[3] ? signbit : i23; - - //Bit lane 2 - i22 <= i26; - i9 <= i26; - i26 <= i30; - i30 <= (i_ctrl[1] | i_ctrl[2]) ? signbit : i14; - i14 <= i18; - i18 <= i_ctrl[3] ? signbit : i22; - - //Bit lane 1 - i21 <= i25; - i8 <= i25; - i25 <= i29; - i29 <= (i_ctrl[1] | i_ctrl[2]) ? signbit : i13; - i13 <= i17; - i17 <= i_ctrl[3] ? signbit : i21; - - //Bit lane 0 - i7_2 <= i11; - i11 <= i28; - i20_2 <= i24; - i24 <= i28; - i28 <= (i_ctrl[1] | i_ctrl[2]) ? signbit : i12; - i12 <= i16; - i16 <= i_ctrl[3] ? signbit : i20_2; - - end - end - - assign o_imm[3] = (i_cnt_done ? signbit : (i_ctrl[0] ? i10 : i23)); - assign o_imm[2] = i_ctrl[0] ? i9 : i22; - assign o_imm[1] = i_ctrl[0] ? i8 : i21; - assign o_imm[0] = i_ctrl[0] ? i7_2 : i20_2; - - end -endgenerate - -endmodule diff --git a/rtl/serv/serv_mem_if.v b/rtl/serv/serv_mem_if.v deleted file mode 100644 index 52c0923..0000000 --- a/rtl/serv/serv_mem_if.v +++ /dev/null @@ -1,59 +0,0 @@ -/* - * serv_mem_if.v : SERV memory interface - * - * SPDX-FileCopyrightText: 2018 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -`default_nettype none -module serv_mem_if - #( - parameter [0:0] WITH_CSR = 1, - parameter W = 1, - parameter B = W-1 - ) - ( - input wire i_clk, - //State - input wire [1:0] i_bytecnt, - input wire [1:0] i_lsb, - output wire o_misalign, - //Control - input wire i_signed, - input wire i_word, - input wire i_half, - //MDU - input wire i_mdu_op, - //Data - input wire [B:0] i_bufreg2_q, - output wire [B:0] o_rd, - //External interface - output wire [3:0] o_wb_sel); - - reg signbit; - - wire dat_valid = - i_mdu_op | - i_word | - (i_bytecnt == 2'b00) | - (i_half & !i_bytecnt[1]); - - assign o_rd = dat_valid ? i_bufreg2_q : {W{i_signed & signbit}}; - - assign o_wb_sel[3] = (i_lsb == 2'b11) | i_word | (i_half & i_lsb[1]); - assign o_wb_sel[2] = (i_lsb == 2'b10) | i_word; - assign o_wb_sel[1] = (i_lsb == 2'b01) | i_word | (i_half & !i_lsb[1]); - assign o_wb_sel[0] = (i_lsb == 2'b00); - - always @(posedge i_clk) begin - if (dat_valid) - signbit <= i_bufreg2_q[B]; - end - - /* - mem_misalign is checked after the init stage to decide whether to do a data - bus transaction or go to the trap state. It is only guaranteed to be correct - at this time - */ - assign o_misalign = WITH_CSR & ((i_lsb[0] & (i_word | i_half)) | (i_lsb[1] & i_word)); - -endmodule diff --git a/rtl/serv/serv_rf_if.v b/rtl/serv/serv_rf_if.v deleted file mode 100644 index ee291d5..0000000 --- a/rtl/serv/serv_rf_if.v +++ /dev/null @@ -1,159 +0,0 @@ -/* - * serv_rf_if.v : SERV register file interface - * - * SPDX-FileCopyrightText: 2019 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -`default_nettype none -module serv_rf_if - #(parameter WITH_CSR = 1, - parameter W = 1, - parameter B = W-1 - ) - (//RF Interface - input wire i_cnt_en, - output wire [4+WITH_CSR:0] o_wreg0, - output wire [4+WITH_CSR:0] o_wreg1, - output wire o_wen0, - output wire o_wen1, - output wire [B:0] o_wdata0, - output wire [B:0] o_wdata1, - output wire [4+WITH_CSR:0] o_rreg0, - output wire [4+WITH_CSR:0] o_rreg1, - input wire [B:0] i_rdata0, - input wire [B:0] i_rdata1, - - //Trap interface - input wire i_trap, - input wire i_mret, - input wire [B:0] i_mepc, - input wire i_mtval_pc, - input wire [B:0] i_bufreg_q, - input wire [B:0] i_bad_pc, - output wire [B:0] o_csr_pc, - //CSR interface - input wire i_csr_en, - input wire [1:0] i_csr_addr, - input wire [B:0] i_csr, - output wire [B:0] o_csr, - //RD write port - input wire i_rd_wen, - input wire [4:0] i_rd_waddr, - input wire [B:0] i_ctrl_rd, - input wire [B:0] i_alu_rd, - input wire i_rd_alu_en, - input wire [B:0] i_csr_rd, - input wire i_rd_csr_en, - input wire [B:0] i_mem_rd, - input wire i_rd_mem_en, - - //RS1 read port - input wire [4:0] i_rs1_raddr, - output wire [B:0] o_rs1, - //RS2 read port - input wire [4:0] i_rs2_raddr, - output wire [B:0] o_rs2); - - - /* - ********** Write side *********** - */ - - wire rd_wen = i_rd_wen & (|i_rd_waddr); - - generate - if (|WITH_CSR) begin : gen_csr - wire [B:0] rd = - {W{i_rd_alu_en}} & i_alu_rd | - {W{i_rd_csr_en}} & i_csr_rd | - {W{i_rd_mem_en}} & i_mem_rd | - i_ctrl_rd; - - wire [B:0] mtval = i_mtval_pc ? i_bad_pc : i_bufreg_q; - - assign o_wdata0 = i_trap ? mtval : rd; - assign o_wdata1 = i_trap ? i_mepc : i_csr; - - /* Port 0 handles writes to mtval during traps and rd otherwise - * Port 1 handles writes to mepc during traps and csr accesses otherwise - * - * GPR registers are mapped to address 0-31 (bits 0xxxxx). - * Following that are four CSR registers - * mscratch 100000 - * mtvec 100001 - * mepc 100010 - * mtval 100011 - */ - - assign o_wreg0 = i_trap ? {6'b100011} : {1'b0,i_rd_waddr}; - assign o_wreg1 = i_trap ? {6'b100010} : {4'b1000,i_csr_addr}; - - assign o_wen0 = i_cnt_en & (i_trap | rd_wen); - assign o_wen1 = i_cnt_en & (i_trap | i_csr_en); - - /* - ********** Read side *********** - */ - - //0 : RS1 - //1 : RS2 / CSR - - assign o_rreg0 = {1'b0, i_rs1_raddr}; - - /* - The address of the second read port (o_rreg1) can get assigned from four - different sources - - Normal operations : i_rs2_raddr - CSR access : i_csr_addr - trap : MTVEC - mret : MEPC - - Address 0-31 in the RF are assigned to the GPRs. After that follows the four - CSRs on addresses 32-35 - - 32 MSCRATCH - 33 MTVEC - 34 MEPC - 35 MTVAL - - The expression below is an optimized version of this logic - */ - wire sel_rs2 = !(i_trap | i_mret | i_csr_en); - assign o_rreg1 = {~sel_rs2, - i_rs2_raddr[4:2] & {3{sel_rs2}}, - {1'b0,i_trap} | {i_mret,1'b0} | ({2{i_csr_en}} & i_csr_addr) | ({2{sel_rs2}} & i_rs2_raddr[1:0])}; - - assign o_rs1 = i_rdata0; - assign o_rs2 = i_rdata1; - assign o_csr = i_rdata1 & {W{i_csr_en}}; - assign o_csr_pc = i_rdata1; - - end else begin : gen_no_csr - wire [B:0] rd = (i_ctrl_rd) | - i_alu_rd & {W{i_rd_alu_en}} | - i_mem_rd & {W{i_rd_mem_en}}; - - assign o_wdata0 = rd; - assign o_wdata1 = {W{1'b0}}; - - assign o_wreg0 = i_rd_waddr; - assign o_wreg1 = 5'd0; - - assign o_wen0 = i_cnt_en & rd_wen; - assign o_wen1 = 1'b0; - - /* - ********** Read side *********** - */ - - assign o_rreg0 = i_rs1_raddr; - assign o_rreg1 = i_rs2_raddr; - - assign o_rs1 = i_rdata0; - assign o_rs2 = i_rdata1; - assign o_csr = {W{1'b0}}; - assign o_csr_pc = {W{1'b0}}; - end // else: !if(WITH_CSR) - endgenerate -endmodule diff --git a/rtl/serv/serv_rf_ram.v b/rtl/serv/serv_rf_ram.v deleted file mode 100644 index e5bce37..0000000 --- a/rtl/serv/serv_rf_ram.v +++ /dev/null @@ -1,52 +0,0 @@ -/* - * serv_rf_ram.v : SRAM-based RF storage for SERV - * - * SPDX-FileCopyrightText: 2019 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -`include "../util/clog2.vh" -module serv_rf_ram - #(parameter width=0, - parameter csr_regs=4, - parameter depth=32*(32+csr_regs)/width) - (input wire i_clk, - input wire [`CLOG2(depth)-1:0] i_waddr, - input wire [width-1:0] i_wdata, - input wire i_wen, - input wire [`CLOG2(depth)-1:0] i_raddr, - input wire i_ren, - output wire [width-1:0] o_rdata); - - reg [width-1:0] memory [0:depth-1]; - reg [width-1:0] rdata ; - - always @(posedge i_clk) begin - if (i_wen) - memory[i_waddr] <= i_wdata; - rdata <= i_ren ? memory[i_raddr] : {width{1'bx}}; - end - - /* Reads from reg x0 needs to return 0 - Check that the part of the read address corresponding to the register - is zero and gate the output - width LSB of reg index `CLOG2(width) - 2 4 1 - 4 3 2 - 8 2 3 - 16 1 4 - 32 0 5 - */ - reg regzero; - - always @(posedge i_clk) - regzero <= !(|i_raddr[`CLOG2(depth)-1:5-`CLOG2(width)]); - - assign o_rdata = rdata & ~{width{regzero}}; - -`ifdef SERV_CLEAR_RAM - integer i; - initial - for (i=0;i - * SPDX-License-Identifier: ISC - */ -`default_nettype none -`include "../util/clog2.vh" -module serv_rf_ram_if - #(//Data width. Adjust to preferred width of SRAM data interface - parameter width=8, - - parameter W = 1, - //Select reset strategy. - // "MINI" for resetting minimally required FFs - // "NONE" for relying on FFs having a defined value on startup - parameter reset_strategy="MINI", - - //Number of CSR registers. These are allocated after the normal - // GPR registers in the RAM. - parameter csr_regs=4, - - //Internal parameters calculated from above values. Do not change - parameter B=W-1, - parameter raw=`CLOG2(32+csr_regs), //Register address width - parameter l2w=`CLOG2(width), //log2 of width - parameter aw=5+raw-l2w) //Address width - ( - //SERV side - input wire i_clk, - input wire i_rst, - input wire i_wreq, - input wire i_rreq, - output wire o_ready, - input wire [raw-1:0] i_wreg0, - input wire [raw-1:0] i_wreg1, - input wire i_wen0, - input wire i_wen1, - input wire [B:0] i_wdata0, - input wire [B:0] i_wdata1, - input wire [raw-1:0] i_rreg0, - input wire [raw-1:0] i_rreg1, - output wire [B:0] o_rdata0, - output wire [B:0] o_rdata1, - //RAM side - output wire [aw-1:0] o_waddr, - output wire [width-1:0] o_wdata, - output wire o_wen, - output wire [aw-1:0] o_raddr, - output wire o_ren, - input wire [width-1:0] i_rdata); - - localparam ratio = width/W; - localparam CMSB = 4-`CLOG2(W); //Counter MSB - localparam l2r = `CLOG2(ratio); - - reg rgnt; - assign o_ready = rgnt | i_wreq; - reg [CMSB:0] rcnt; - - reg rtrig1; - /* - ********** Write side *********** - */ - - wire [CMSB:0] wcnt; - - reg [width-1:0] wdata0_r; - reg [width+W-1:0] wdata1_r; - - reg wen0_r; - reg wen1_r; - wire wtrig0; - wire wtrig1; - - assign wtrig0 = rtrig1; - - generate if (ratio == 2) begin : gen_wtrig_ratio_eq_2 - assign wtrig1 = wcnt[0]; - end else begin : gen_wtrig_ratio_neq_2 - reg wtrig0_r; - always @(posedge i_clk) wtrig0_r <= wtrig0; - assign wtrig1 = wtrig0_r; - end - endgenerate - - assign o_wdata = wtrig1 ? - wdata1_r[width-1:0] : - wdata0_r; - - wire [raw-1:0] wreg = wtrig1 ? i_wreg1 : i_wreg0; - generate if (width == 32) begin : gen_w_eq_32 - assign o_waddr = wreg; - end else begin : gen_w_neq_32 - assign o_waddr = {wreg, wcnt[CMSB:l2r]}; - end - endgenerate - - assign o_wen = (wtrig0 & wen0_r) | (wtrig1 & wen1_r); - - assign wcnt = rcnt-4; - - always @(posedge i_clk) begin - if (wcnt[0]) begin - wen0_r <= i_wen0; - wen1_r <= i_wen1; - end - - wdata0_r <= {i_wdata0,wdata0_r[width-1:W]}; - wdata1_r <= {i_wdata1,wdata1_r[width+W-1:W]}; - - end - - /* - ********** Read side *********** - */ - - - wire rtrig0; - - wire [raw-1:0] rreg = rtrig0 ? i_rreg1 : i_rreg0; - generate if (width == 32) begin : gen_rreg_eq_32 - assign o_raddr = rreg; - end else begin : gen_rreg_neq_32 - assign o_raddr = {rreg, rcnt[CMSB:l2r]}; - end - endgenerate - - reg [width-1:0] rdata0; - reg [width-1-W:0] rdata1; - - reg rgate; - - assign o_rdata0 = rdata0[B:0]; - assign o_rdata1 = rtrig1 ? i_rdata[B:0] : rdata1[B:0]; - - assign rtrig0 = (rcnt[l2r-1:0] == 1); - - generate if (ratio == 2) begin : gen_ren_w_eq_2 - assign o_ren = rgate; - end else begin : gen_ren_w_neq_2 - assign o_ren = rgate & (rcnt[l2r-1:1] == 0); - end - endgenerate - - reg rreq_r; - - generate if (ratio > 2) begin : gen_rdata1_w_neq_2 - always @(posedge i_clk) begin - rdata1 <= {{W{1'b0}},rdata1[width-W-1:W]}; - if (rtrig1) - rdata1[width-W-1:0] <= i_rdata[width-1:W]; - end - end else begin : gen_rdata1_w_eq_2 - always @(posedge i_clk) if (rtrig1) rdata1 <= i_rdata[W*2-1:W]; - end - endgenerate - - always @(posedge i_clk) begin - if (&rcnt | i_rreq) - rgate <= i_rreq; - - rtrig1 <= rtrig0; - rcnt <= rcnt+{{CMSB{1'b0}},1'b1}; - if (i_rreq | i_wreq) - rcnt <= {{CMSB-1{1'b0}},i_wreq,1'b0}; - - rreq_r <= i_rreq; - rgnt <= rreq_r; - - rdata0 <= {{W{1'b0}}, rdata0[width-1:W]}; - if (rtrig0) - rdata0 <= i_rdata; - - if (i_rst) begin - if (reset_strategy != "NONE") begin - rgate <= 1'b0; - rgnt <= 1'b0; - rreq_r <= 1'b0; - rcnt <= {CMSB+1{1'b0}}; - end - end - end - - - -endmodule diff --git a/rtl/serv/serv_rf_top.v b/rtl/serv/serv_rf_top.v deleted file mode 100644 index 0d231e0..0000000 --- a/rtl/serv/serv_rf_top.v +++ /dev/null @@ -1,228 +0,0 @@ -/* - * serv_rf_top.v : Toplevel including SERV and SRAM-based RF storage - * - * SPDX-FileCopyrightText: 2019 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -`default_nettype none -`include "../util/clog2.vh" - -module serv_rf_top - #(parameter RESET_PC = 32'd0, - /* COMPRESSED=1: Enable the compressed decoder and allowed misaligned jump of pc - COMPRESSED=0: Disable the compressed decoder and does not allow the misaligned jump of pc - */ - parameter [0:0] COMPRESSED = 0, - /* - ALIGN = 1: Fetch the aligned instruction by making two bus transactions if the misaligned address - is given to the instruction bus. - */ - parameter [0:0] ALIGN = COMPRESSED, - /* Multiplication and Division Unit - This parameter enables the interface for connecting SERV and MDU - */ - parameter [0:0] MDU = 0, - /* Register signals before or after the decoder - 0 : Register after the decoder. Faster but uses more resources - 1 : (default) Register before the decoder. Slower but uses less resources - */ - parameter PRE_REGISTER = 1, - /* Amount of reset applied to design - "NONE" : No reset at all. Relies on a POR to set correct initialization - values and that core isn't reset during runtime - "MINI" : Standard setting. Resets the minimal amount of FFs needed to - restart execution from the instruction at RESET_PC - */ - parameter RESET_STRATEGY = "MINI", - parameter [0:0] DEBUG = 1'b0, - parameter WITH_CSR = 1, - parameter W = 1, - parameter RF_WIDTH = W * 2, - parameter RF_L2D = `CLOG2((32+(WITH_CSR*4))*32/RF_WIDTH)) - ( - input wire clk, - input wire i_rst, - input wire i_timer_irq, -`ifdef RISCV_FORMAL - output wire rvfi_valid, - output wire [63:0] rvfi_order, - output wire [31:0] rvfi_insn, - output wire rvfi_trap, - output wire rvfi_halt, - output wire rvfi_intr, - output wire [1:0] rvfi_mode, - output wire [1:0] rvfi_ixl, - output wire [4:0] rvfi_rs1_addr, - output wire [4:0] rvfi_rs2_addr, - output wire [31:0] rvfi_rs1_rdata, - output wire [31:0] rvfi_rs2_rdata, - output wire [4:0] rvfi_rd_addr, - output wire [31:0] rvfi_rd_wdata, - output wire [31:0] rvfi_pc_rdata, - output wire [31:0] rvfi_pc_wdata, - output wire [31:0] rvfi_mem_addr, - output wire [3:0] rvfi_mem_rmask, - output wire [3:0] rvfi_mem_wmask, - output wire [31:0] rvfi_mem_rdata, - output wire [31:0] rvfi_mem_wdata, -`endif - output wire [31:0] o_ibus_adr, - output wire o_ibus_cyc, - input wire [31:0] i_ibus_rdt, - input wire i_ibus_ack, - output wire [31:0] o_dbus_adr, - output wire [31:0] o_dbus_dat, - output wire [3:0] o_dbus_sel, - output wire o_dbus_we , - output wire o_dbus_cyc, - input wire [31:0] i_dbus_rdt, - input wire i_dbus_ack, - - // Extension - output wire [31:0] o_ext_rs1, - output wire [31:0] o_ext_rs2, - output wire [ 2:0] o_ext_funct3, - input wire [31:0] i_ext_rd, - input wire i_ext_ready, - // MDU - output wire o_mdu_valid); - - localparam CSR_REGS = WITH_CSR*4; - - wire rf_wreq; - wire rf_rreq; - wire [4+WITH_CSR:0] wreg0; - wire [4+WITH_CSR:0] wreg1; - wire wen0; - wire wen1; - wire [W-1:0] wdata0; - wire [W-1:0] wdata1; - wire [4+WITH_CSR:0] rreg0; - wire [4+WITH_CSR:0] rreg1; - wire rf_ready; - wire [W-1:0] rdata0; - wire [W-1:0] rdata1; - - wire [RF_L2D-1:0] waddr; - wire [RF_WIDTH-1:0] wdata; - wire wen; - wire [RF_L2D-1:0] raddr; - wire ren; - wire [RF_WIDTH-1:0] rdata; - - serv_rf_ram_if - #(.width (RF_WIDTH), - .reset_strategy (RESET_STRATEGY), - .csr_regs (CSR_REGS), - .W(W)) - rf_ram_if - (.i_clk (clk), - .i_rst (i_rst), - .i_wreq (rf_wreq), - .i_rreq (rf_rreq), - .o_ready (rf_ready), - .i_wreg0 (wreg0), - .i_wreg1 (wreg1), - .i_wen0 (wen0), - .i_wen1 (wen1), - .i_wdata0 (wdata0), - .i_wdata1 (wdata1), - .i_rreg0 (rreg0), - .i_rreg1 (rreg1), - .o_rdata0 (rdata0), - .o_rdata1 (rdata1), - .o_waddr (waddr), - .o_wdata (wdata), - .o_wen (wen), - .o_raddr (raddr), - .o_ren (ren), - .i_rdata (rdata)); - - serv_rf_ram - #(.width (RF_WIDTH), - .csr_regs (CSR_REGS)) - rf_ram - (.i_clk (clk), - .i_waddr (waddr), - .i_wdata (wdata), - .i_wen (wen), - .i_raddr (raddr), - .i_ren (ren), - .o_rdata (rdata)); - - serv_top - #(.RESET_PC (RESET_PC), - .PRE_REGISTER (PRE_REGISTER), - .RESET_STRATEGY (RESET_STRATEGY), - .WITH_CSR (WITH_CSR), - .DEBUG (DEBUG), - .MDU(MDU), - .COMPRESSED(COMPRESSED), - .ALIGN(ALIGN), - .W(W)) - cpu - ( - .clk (clk), - .i_rst (i_rst), - .i_timer_irq (i_timer_irq), -`ifdef RISCV_FORMAL - .rvfi_valid (rvfi_valid ), - .rvfi_order (rvfi_order ), - .rvfi_insn (rvfi_insn ), - .rvfi_trap (rvfi_trap ), - .rvfi_halt (rvfi_halt ), - .rvfi_intr (rvfi_intr ), - .rvfi_mode (rvfi_mode ), - .rvfi_ixl (rvfi_ixl ), - .rvfi_rs1_addr (rvfi_rs1_addr ), - .rvfi_rs2_addr (rvfi_rs2_addr ), - .rvfi_rs1_rdata (rvfi_rs1_rdata), - .rvfi_rs2_rdata (rvfi_rs2_rdata), - .rvfi_rd_addr (rvfi_rd_addr ), - .rvfi_rd_wdata (rvfi_rd_wdata ), - .rvfi_pc_rdata (rvfi_pc_rdata ), - .rvfi_pc_wdata (rvfi_pc_wdata ), - .rvfi_mem_addr (rvfi_mem_addr ), - .rvfi_mem_rmask (rvfi_mem_rmask), - .rvfi_mem_wmask (rvfi_mem_wmask), - .rvfi_mem_rdata (rvfi_mem_rdata), - .rvfi_mem_wdata (rvfi_mem_wdata), -`endif - .o_rf_rreq (rf_rreq), - .o_rf_wreq (rf_wreq), - .i_rf_ready (rf_ready), - .o_wreg0 (wreg0), - .o_wreg1 (wreg1), - .o_wen0 (wen0), - .o_wen1 (wen1), - .o_wdata0 (wdata0), - .o_wdata1 (wdata1), - .o_rreg0 (rreg0), - .o_rreg1 (rreg1), - .i_rdata0 (rdata0), - .i_rdata1 (rdata1), - - .o_ibus_adr (o_ibus_adr), - .o_ibus_cyc (o_ibus_cyc), - .i_ibus_rdt (i_ibus_rdt), - .i_ibus_ack (i_ibus_ack), - - .o_dbus_adr (o_dbus_adr), - .o_dbus_dat (o_dbus_dat), - .o_dbus_sel (o_dbus_sel), - .o_dbus_we (o_dbus_we), - .o_dbus_cyc (o_dbus_cyc), - .i_dbus_rdt (i_dbus_rdt), - .i_dbus_ack (i_dbus_ack), - - //Extension - .o_ext_funct3 (o_ext_funct3), - .i_ext_ready (i_ext_ready), - .i_ext_rd (i_ext_rd), - .o_ext_rs1 (o_ext_rs1), - .o_ext_rs2 (o_ext_rs2), - //MDU - .o_mdu_valid (o_mdu_valid)); - -endmodule -`default_nettype wire diff --git a/rtl/serv/serv_state.v b/rtl/serv/serv_state.v deleted file mode 100644 index acb3014..0000000 --- a/rtl/serv/serv_state.v +++ /dev/null @@ -1,239 +0,0 @@ -/* - * serv_state.v : SERV module for handling internal state during instructions - * - * SPDX-FileCopyrightText: 2019 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -module serv_state - #(parameter RESET_STRATEGY = "MINI", - parameter [0:0] WITH_CSR = 1, - parameter [0:0] ALIGN =0, - parameter [0:0] MDU = 0, - parameter W = 1 - ) - ( - input wire i_clk, - input wire i_rst, - //State - input wire i_new_irq, - input wire i_alu_cmp, - output wire o_init, - output wire o_cnt_en, - output wire o_cnt0to3, - output wire o_cnt12to31, - output wire o_cnt0, - output wire o_cnt1, - output wire o_cnt2, - output wire o_cnt3, - output wire o_cnt7, - output wire o_cnt11, - output wire o_cnt12, - output wire o_cnt_done, - output wire o_bufreg_en, - output wire o_ctrl_pc_en, - output reg o_ctrl_jump, - output wire o_ctrl_trap, - input wire i_ctrl_misalign, - input wire i_sh_done, - output wire [1:0] o_mem_bytecnt, - input wire i_mem_misalign, - //Control - input wire i_bne_or_bge, - input wire i_cond_branch, - input wire i_dbus_en, - input wire i_two_stage_op, - input wire i_branch_op, - input wire i_shift_op, - input wire i_sh_right, - input wire i_alu_rd_sel1, - input wire i_rd_alu_en, - input wire i_e_op, - input wire i_rd_op, - //MDU - input wire i_mdu_op, - output wire o_mdu_valid, - //Extension - input wire i_mdu_ready, - //External - output wire o_dbus_cyc, - input wire i_dbus_ack, - output wire o_ibus_cyc, - input wire i_ibus_ack, - //RF Interface - output wire o_rf_rreq, - output wire o_rf_wreq, - input wire i_rf_ready, - output wire o_rf_rd_en); - - reg init_done; - wire misalign_trap_sync; - - reg [4:2] o_cnt; - wire [3:0] cnt_r; - - reg ibus_cyc; - //Update PC in RUN or TRAP states - assign o_ctrl_pc_en = o_cnt_en & !o_init; - - assign o_mem_bytecnt = o_cnt[4:3]; - - assign o_cnt0to3 = (o_cnt[4:2] == 3'd0); - assign o_cnt12to31 = (o_cnt[4] | (o_cnt[3:2] == 2'b11)); - assign o_cnt0 = (o_cnt[4:2] == 3'd0) & cnt_r[0]; - assign o_cnt1 = (o_cnt[4:2] == 3'd0) & cnt_r[1]; - assign o_cnt2 = (o_cnt[4:2] == 3'd0) & cnt_r[2]; - assign o_cnt3 = (o_cnt[4:2] == 3'd0) & cnt_r[3]; - assign o_cnt7 = (o_cnt[4:2] == 3'd1) & cnt_r[3]; - assign o_cnt11 = (o_cnt[4:2] == 3'd2) & cnt_r[3]; - assign o_cnt12 = (o_cnt[4:2] == 3'd3) & cnt_r[0]; - - //Take branch for jump or branch instructions (opcode == 1x0xx) if - //a) It's an unconditional branch (opcode[0] == 1) - //b) It's a conditional branch (opcode[0] == 0) of type beq,blt,bltu (funct3[0] == 0) and ALU compare is true - //c) It's a conditional branch (opcode[0] == 0) of type bne,bge,bgeu (funct3[0] == 1) and ALU compare is false - //Only valid during the last cycle of INIT, when the branch condition has - //been calculated. - wire take_branch = i_branch_op & (!i_cond_branch | (i_alu_cmp^i_bne_or_bge)); - - wire last_init = o_cnt_done & o_init; - - //valid signal for mdu - assign o_mdu_valid = MDU & !o_cnt_en & init_done & i_mdu_op; - - //trap_pending is only guaranteed to have correct value during the - // last cycle of the init stage - wire trap_pending = WITH_CSR & ((take_branch & i_ctrl_misalign & !ALIGN) | - (i_dbus_en & i_mem_misalign)); - - //Prepare RF for writes when everything is ready to enter stage two - // and the first stage didn't cause a misalign exception - //Left shifts, SLT & Branch ops. First cycle after init - //Right shift. o_sh_done - //Mem ops. i_dbus_ack - //MDU ops. i_mdu_ready - assign o_rf_wreq = (i_shift_op & (i_sh_right ? (i_sh_done & (last_init | !o_cnt_en & init_done)) : last_init)) | - i_dbus_ack | (MDU & i_mdu_ready) | - (i_branch_op & (last_init & !trap_pending)) | - (i_rd_alu_en & i_alu_rd_sel1 & last_init); - - assign o_dbus_cyc = !o_cnt_en & init_done & i_dbus_en & !i_mem_misalign; - - //Prepare RF for reads when a new instruction is fetched - // or when stage one caused an exception (rreq implies a write request too) - assign o_rf_rreq = i_ibus_ack | (trap_pending & last_init); - - assign o_rf_rd_en = i_rd_op & !o_init; - - /* - bufreg is used during mem, branch, and shift operations - - mem : bufreg is used for dbus address. Shift in data during phase 1. - Shift out during phase 2 if there was a misalignment exception. - - branch : Shift in during phase 1. Shift out during phase 2 - - shift : Shift in during phase 1. Continue shifting between phases (except - for the first cycle after init). Shift out during phase 2 - */ - - assign o_bufreg_en = (o_cnt_en & (o_init | ((o_ctrl_trap | i_branch_op) & i_two_stage_op))) | (i_shift_op & init_done & (i_sh_right | i_sh_done)); - - assign o_ibus_cyc = ibus_cyc & !i_rst; - - assign o_init = i_two_stage_op & !i_new_irq & !init_done; - - assign o_cnt_done = (o_cnt[4:2] == 3'b111) & cnt_r[3]; - - always @(posedge i_clk) begin - //ibus_cyc changes on three conditions. - //1. i_rst is asserted. Together with the async gating above, o_ibus_cyc - // will be asserted as soon as the reset is released. This is how the - // first instruction is fetched - //2. o_cnt_done and o_ctrl_pc_en are asserted. This means that SERV just - // finished updating the PC, is done with the current instruction and - // o_ibus_cyc gets asserted to fetch a new instruction - //3. When i_ibus_ack, a new instruction is fetched and o_ibus_cyc gets - // deasserted to finish the transaction - if (i_ibus_ack | o_cnt_done | i_rst) - ibus_cyc <= o_ctrl_pc_en | i_rst; - - if (o_cnt_done) begin - init_done <= o_init & !init_done; - o_ctrl_jump <= o_init & take_branch; - end - - if (i_rst) begin - if (RESET_STRATEGY != "NONE") begin - init_done <= 1'b0; - o_ctrl_jump <= 1'b0; - end - end - end - - generate - /* - Because SERV is 32-bit bit-serial we need a counter than can count 0-31 - to keep track of which bit we are currently processing. o_cnt and cnt_r - are used together to create such a counter. - The top three bits (o_cnt) are implemented as a normal counter, but - instead of the two LSB, cnt_r is a 4-bit shift register which loops 0-3 - When cnt_r[3] is 1, o_cnt will be increased. - - The counting starts when the core is idle and the i_rf_ready signal - comes in from the RF module by shifting in the i_rf_ready bit as LSB of - the shift register. Counting is stopped by using o_cnt_done to block the - bit that was supposed to be shifted into bit 0 of cnt_r. - - There are two benefit of doing the counter this way - 1. We only need to check four bits instead of five when we want to check - if the counter is at a certain value. For 4-LUT architectures this means - we only need one LUT instead of two for each comparison. - 2. We don't need a separate enable signal to turn on and off the counter - between stages, which saves an extra FF and a unique control signal. We - just need to check if cnt_r is not zero to see if the counter is - currently running - */ - if (W == 1) begin : gen_cnt_w_eq_1 - reg [3:0] cnt_lsb; - always @(posedge i_clk) begin - o_cnt <= o_cnt + {2'd0,cnt_r[3]}; - cnt_lsb <= {cnt_lsb[2:0],(cnt_lsb[3] & !o_cnt_done) | i_rf_ready}; - if (i_rst & (RESET_STRATEGY != "NONE")) begin - o_cnt <= 3'd0; - cnt_lsb <= 4'b0000; - end - end - assign cnt_r = cnt_lsb; - assign o_cnt_en = |cnt_lsb; - end else if (W == 4) begin : gen_cnt_w_eq_4 - reg cnt_en; - always @(posedge i_clk) begin - if (i_rf_ready) cnt_en <= 1; else - if (o_cnt_done) cnt_en <= 0; - o_cnt <= o_cnt + { 2'd0, cnt_en }; - if (i_rst & (RESET_STRATEGY != "NONE")) begin - o_cnt <= 3'd0; - cnt_en <= 1'b0; - end - end - assign cnt_r = 4'b1111; - assign o_cnt_en = cnt_en; - end - endgenerate - - assign o_ctrl_trap = WITH_CSR & (i_e_op | i_new_irq | misalign_trap_sync); - - generate - if (WITH_CSR) begin : gen_csr - reg misalign_trap_sync_r; - - always @(posedge i_clk) begin - if (i_ibus_ack | o_cnt_done | i_rst) - misalign_trap_sync_r <= !(i_ibus_ack | i_rst) & ((trap_pending & o_init) | misalign_trap_sync_r); - end - assign misalign_trap_sync = misalign_trap_sync_r; - end else begin : gen_no_csr - assign misalign_trap_sync = 1'b0; - end - endgenerate -endmodule diff --git a/rtl/serv/serv_synth_wrapper.v b/rtl/serv/serv_synth_wrapper.v deleted file mode 100644 index 50df6b7..0000000 --- a/rtl/serv/serv_synth_wrapper.v +++ /dev/null @@ -1,139 +0,0 @@ -/* - * serv_synth_wrapper.v : SERV wrapper for synthesis - * - * SPDX-FileCopyrightText: 2021 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -`default_nettype none -`include "../util/clog2.vh" - -module serv_synth_wrapper - #( - /* Register signals before or after the decoder - 0 : Register after the decoder. Faster but uses more resources - 1 : (default) Register before the decoder. Slower but uses less resources - */ - parameter PRE_REGISTER = 1, - /* Amount of reset applied to design - "NONE" : No reset at all. Relies on a POR to set correct initialization - values and that core isn't reset during runtime - "MINI" : Standard setting. Resets the minimal amount of FFs needed to - restart execution from the instruction at RESET_PC - */ - parameter RESET_STRATEGY = "MINI", - parameter WITH_CSR = 1, - parameter RF_WIDTH = 2, - parameter RF_L2D = `CLOG2((32+(WITH_CSR*4))*32/RF_WIDTH)) - ( - input wire clk, - input wire i_rst, - input wire i_timer_irq, - output wire [31:0] o_ibus_adr, - output wire o_ibus_cyc, - input wire [31:0] i_ibus_rdt, - input wire i_ibus_ack, - output wire [31:0] o_dbus_adr, - output wire [31:0] o_dbus_dat, - output wire [3:0] o_dbus_sel, - output wire o_dbus_we , - output wire o_dbus_cyc, - input wire [31:0] i_dbus_rdt, - input wire i_dbus_ack, - - output wire [RF_L2D-1:0] o_waddr, - output wire [RF_WIDTH-1:0] o_wdata, - output wire o_wen, - output wire [RF_L2D-1:0] o_raddr, - input wire [RF_WIDTH-1:0] i_rdata); - - localparam CSR_REGS = WITH_CSR*4; - - wire rf_wreq; - wire rf_rreq; - wire [4+WITH_CSR:0] wreg0; - wire [4+WITH_CSR:0] wreg1; - wire wen0; - wire wen1; - wire wdata0; - wire wdata1; - wire [4+WITH_CSR:0] rreg0; - wire [4+WITH_CSR:0] rreg1; - wire rf_ready; - wire rdata0; - wire rdata1; - - serv_rf_ram_if - #(.width (RF_WIDTH), - .reset_strategy (RESET_STRATEGY), - .csr_regs (CSR_REGS)) - rf_ram_if - (.i_clk (clk), - .i_rst (i_rst), - .i_wreq (rf_wreq), - .i_rreq (rf_rreq), - .o_ready (rf_ready), - .i_wreg0 (wreg0), - .i_wreg1 (wreg1), - .i_wen0 (wen0), - .i_wen1 (wen1), - .i_wdata0 (wdata0), - .i_wdata1 (wdata1), - .i_rreg0 (rreg0), - .i_rreg1 (rreg1), - .o_rdata0 (rdata0), - .o_rdata1 (rdata1), - .o_waddr (o_waddr), - .o_wdata (o_wdata), - .o_wen (o_wen), - .o_raddr (o_raddr), - .i_rdata (i_rdata)); - - serv_top - #(.RESET_PC (32'd0), - .PRE_REGISTER (PRE_REGISTER), - .RESET_STRATEGY (RESET_STRATEGY), - .WITH_CSR (WITH_CSR), - .MDU(1'b0)) - cpu - ( - .clk (clk), - .i_rst (i_rst), - .i_timer_irq (i_timer_irq), - .o_rf_rreq (rf_rreq), - .o_rf_wreq (rf_wreq), - .i_rf_ready (rf_ready), - .o_wreg0 (wreg0), - .o_wreg1 (wreg1), - .o_wen0 (wen0), - .o_wen1 (wen1), - .o_wdata0 (wdata0), - .o_wdata1 (wdata1), - .o_rreg0 (rreg0), - .o_rreg1 (rreg1), - .i_rdata0 (rdata0), - .i_rdata1 (rdata1), - - .o_ibus_adr (o_ibus_adr), - .o_ibus_cyc (o_ibus_cyc), - .i_ibus_rdt (i_ibus_rdt), - .i_ibus_ack (i_ibus_ack), - - .o_dbus_adr (o_dbus_adr), - .o_dbus_dat (o_dbus_dat), - .o_dbus_sel (o_dbus_sel), - .o_dbus_we (o_dbus_we), - .o_dbus_cyc (o_dbus_cyc), - .i_dbus_rdt (i_dbus_rdt), - .i_dbus_ack (i_dbus_ack), - - //Extension - .o_ext_funct3 (), - .i_ext_ready (1'b0), - .i_ext_rd (32'd0), - .o_ext_rs1 (), - .o_ext_rs2 (), - //MDU - .o_mdu_valid ()); - -endmodule -`default_nettype wire diff --git a/rtl/serv/serv_top.v b/rtl/serv/serv_top.v deleted file mode 100644 index 95e7b1c..0000000 --- a/rtl/serv/serv_top.v +++ /dev/null @@ -1,674 +0,0 @@ -/* - * serv_top.v : SERV toplevel - * - * SPDX-FileCopyrightText: 2018 Olof Kindgren - * SPDX-License-Identifier: ISC - */ -`default_nettype none - -module serv_top - #(parameter WITH_CSR = 1, - parameter W = 1, - parameter B = W-1, - parameter PRE_REGISTER = 1, - parameter RESET_STRATEGY = "MINI", - parameter RESET_PC = 32'd0, - parameter [0:0] DEBUG = 1'b0, - parameter [0:0] MDU = 1'b0, - parameter [0:0] COMPRESSED=0, - parameter [0:0] ALIGN = COMPRESSED) - ( - input wire clk, - input wire i_rst, - input wire i_timer_irq, -`ifdef RISCV_FORMAL - output wire rvfi_valid, - output wire [63:0] rvfi_order, - output wire [31:0] rvfi_insn, - output wire rvfi_trap, - output wire rvfi_halt, - output wire rvfi_intr, - output wire [1:0] rvfi_mode, - output wire [1:0] rvfi_ixl, - output wire [4:0] rvfi_rs1_addr, - output wire [4:0] rvfi_rs2_addr, - output wire [31:0] rvfi_rs1_rdata, - output wire [31:0] rvfi_rs2_rdata, - output wire [4:0] rvfi_rd_addr, - output wire [31:0] rvfi_rd_wdata, - output wire [31:0] rvfi_pc_rdata, - output wire [31:0] rvfi_pc_wdata, - output wire [31:0] rvfi_mem_addr, - output wire [3:0] rvfi_mem_rmask, - output wire [3:0] rvfi_mem_wmask, - output wire [31:0] rvfi_mem_rdata, - output wire [31:0] rvfi_mem_wdata, -`endif - //RF Interface - output wire o_rf_rreq, - output wire o_rf_wreq, - input wire i_rf_ready, - output wire [4+WITH_CSR:0] o_wreg0, - output wire [4+WITH_CSR:0] o_wreg1, - output wire o_wen0, - output wire o_wen1, - output wire [B:0] o_wdata0, - output wire [B:0] o_wdata1, - output wire [4+WITH_CSR:0] o_rreg0, - output wire [4+WITH_CSR:0] o_rreg1, - input wire [B:0] i_rdata0, - input wire [B:0] i_rdata1, - - output wire [31:0] o_ibus_adr, - output wire o_ibus_cyc, - input wire [31:0] i_ibus_rdt, - input wire i_ibus_ack, - output wire [31:0] o_dbus_adr, - output wire [31:0] o_dbus_dat, - output wire [3:0] o_dbus_sel, - output wire o_dbus_we , - output wire o_dbus_cyc, - input wire [31:0] i_dbus_rdt, - input wire i_dbus_ack, - //Extension - output wire [ 2:0] o_ext_funct3, - input wire i_ext_ready, - input wire [31:0] i_ext_rd, - output wire [31:0] o_ext_rs1, - output wire [31:0] o_ext_rs2, - //MDU - output wire o_mdu_valid); - - wire [4:0] rd_addr; - wire [4:0] rs1_addr; - wire [4:0] rs2_addr; - - wire [3:0] immdec_ctrl; - wire [3:0] immdec_en; - - wire sh_right; - wire bne_or_bge; - wire cond_branch; - wire two_stage_op; - wire e_op; - wire ebreak; - wire branch_op; - wire shift_op; - wire rd_op; - wire mdu_op; - - wire rd_alu_en; - wire rd_csr_en; - wire rd_mem_en; - wire [B:0] ctrl_rd; - wire [B:0] alu_rd; - wire [B:0] mem_rd; - wire [B:0] csr_rd; - wire mtval_pc; - - wire ctrl_pc_en; - wire jump; - wire jal_or_jalr; - wire utype; - wire mret; - wire [B:0] imm; - wire trap; - wire pc_rel; - wire iscomp; - - wire init; - wire cnt_en; - wire cnt0to3; - wire cnt12to31; - wire cnt0; - wire cnt1; - wire cnt2; - wire cnt3; - wire cnt7; - wire cnt11; - wire cnt12; - - wire cnt_done; - - wire bufreg_en; - wire bufreg_sh_signed; - wire bufreg_rs1_en; - wire bufreg_imm_en; - wire bufreg_clr_lsb; - wire [B:0] bufreg_q; - wire [B:0] bufreg2_q; - wire [31:0] dbus_rdt; - wire dbus_ack; - - wire alu_sub; - wire [1:0] alu_bool_op; - wire alu_cmp_eq; - wire alu_cmp_sig; - wire alu_cmp; - wire [2:0] alu_rd_sel; - - wire [B:0] rs1; - wire [B:0] rs2; - wire rd_en; - - wire [B:0] op_b; - wire op_b_sel; - - wire mem_signed; - wire mem_word; - wire mem_half; - wire [1:0] mem_bytecnt; - wire sh_done; - - wire mem_misalign; - - wire [B:0] bad_pc; - - wire csr_mstatus_en; - wire csr_mie_en; - wire csr_mcause_en; - wire [1:0] csr_source; - wire [B:0] csr_imm; - wire csr_d_sel; - wire csr_en; - wire [1:0] csr_addr; - wire [B:0] csr_pc; - wire csr_imm_en; - wire [B:0] csr_in; - wire [B:0] rf_csr_out; - wire dbus_en; - - wire new_irq; - - wire [1:0] lsb; - - wire [31:0] i_wb_rdt; - - wire [31:0] wb_ibus_adr; - wire wb_ibus_cyc; - wire [31:0] wb_ibus_rdt; - wire wb_ibus_ack; - - generate - if (ALIGN) begin : gen_align - serv_aligner align - ( - .clk(clk), - .rst(i_rst), - // serv_rf_top - .i_ibus_adr(wb_ibus_adr), - .i_ibus_cyc(wb_ibus_cyc), - .o_ibus_rdt(wb_ibus_rdt), - .o_ibus_ack(wb_ibus_ack), - // servant_arbiter - .o_wb_ibus_adr(o_ibus_adr), - .o_wb_ibus_cyc(o_ibus_cyc), - .i_wb_ibus_rdt(i_ibus_rdt), - .i_wb_ibus_ack(i_ibus_ack)); - end else begin : gen_no_align - assign o_ibus_adr = wb_ibus_adr; - assign o_ibus_cyc = wb_ibus_cyc; - assign wb_ibus_rdt = i_ibus_rdt; - assign wb_ibus_ack = i_ibus_ack; - end - endgenerate - - generate - if (COMPRESSED) begin : gen_compressed - serv_compdec compdec - ( - .i_clk(clk), - .i_instr(wb_ibus_rdt), - .i_ack(wb_ibus_ack), - .o_instr(i_wb_rdt), - .o_iscomp(iscomp)); - end else begin : gen_no_compressed - assign i_wb_rdt = wb_ibus_rdt; - assign iscomp = 1'b0; - end - endgenerate - - serv_state - #(.RESET_STRATEGY (RESET_STRATEGY), - .WITH_CSR (WITH_CSR[0:0]), - .MDU(MDU), - .ALIGN(ALIGN), - .W(W)) - state - ( - .i_clk (clk), - .i_rst (i_rst), - //State - .i_new_irq (new_irq), - .i_alu_cmp (alu_cmp), - .o_init (init), - .o_cnt_en (cnt_en), - .o_cnt0to3 (cnt0to3), - .o_cnt12to31 (cnt12to31), - .o_cnt0 (cnt0), - .o_cnt1 (cnt1), - .o_cnt2 (cnt2), - .o_cnt3 (cnt3), - .o_cnt7 (cnt7), - .o_cnt11 (cnt11), - .o_cnt12 (cnt12), - .o_cnt_done (cnt_done), - .o_bufreg_en (bufreg_en), - .o_ctrl_pc_en (ctrl_pc_en), - .o_ctrl_jump (jump), - .o_ctrl_trap (trap), - .i_ctrl_misalign(lsb[1]), - .i_sh_done (sh_done), - .o_mem_bytecnt (mem_bytecnt), - .i_mem_misalign (mem_misalign), - //Control - .i_bne_or_bge (bne_or_bge), - .i_cond_branch (cond_branch), - .i_dbus_en (dbus_en), - .i_two_stage_op (two_stage_op), - .i_branch_op (branch_op), - .i_shift_op (shift_op), - .i_sh_right (sh_right), - .i_alu_rd_sel1 (alu_rd_sel[1]), - .i_rd_alu_en (rd_alu_en), - .i_e_op (e_op), - .i_rd_op (rd_op), - //MDU - .i_mdu_op (mdu_op), - .o_mdu_valid (o_mdu_valid), - //Extension - .i_mdu_ready (i_ext_ready), - //External - .o_dbus_cyc (o_dbus_cyc), - .i_dbus_ack (i_dbus_ack), - .o_ibus_cyc (wb_ibus_cyc), - .i_ibus_ack (wb_ibus_ack), - //RF Interface - .o_rf_rreq (o_rf_rreq), - .o_rf_wreq (o_rf_wreq), - .i_rf_ready (i_rf_ready), - .o_rf_rd_en (rd_en)); - - serv_decode - #(.PRE_REGISTER (PRE_REGISTER), - .MDU(MDU)) - decode - ( - .clk (clk), - //Input - .i_wb_rdt (i_wb_rdt[31:2]), - .i_wb_en (wb_ibus_ack), - //To state - .o_bne_or_bge (bne_or_bge), - .o_cond_branch (cond_branch), - .o_dbus_en (dbus_en), - .o_e_op (e_op), - .o_ebreak (ebreak), - .o_branch_op (branch_op), - .o_shift_op (shift_op), - .o_rd_op (rd_op), - .o_sh_right (sh_right), - .o_mdu_op (mdu_op), - .o_two_stage_op (two_stage_op), - //Extension - .o_ext_funct3 (o_ext_funct3), - - //To bufreg - .o_bufreg_rs1_en (bufreg_rs1_en), - .o_bufreg_imm_en (bufreg_imm_en), - .o_bufreg_clr_lsb (bufreg_clr_lsb), - .o_bufreg_sh_signed (bufreg_sh_signed), - //To bufreg2 - .o_op_b_source (op_b_sel), - //To ctrl - .o_ctrl_jal_or_jalr (jal_or_jalr), - .o_ctrl_utype (utype), - .o_ctrl_pc_rel (pc_rel), - .o_ctrl_mret (mret), - //To alu - .o_alu_sub (alu_sub), - .o_alu_bool_op (alu_bool_op), - .o_alu_cmp_eq (alu_cmp_eq), - .o_alu_cmp_sig (alu_cmp_sig), - .o_alu_rd_sel (alu_rd_sel), - //To mem IF - .o_mem_cmd (o_dbus_we), - .o_mem_signed (mem_signed), - .o_mem_word (mem_word), - .o_mem_half (mem_half), - //To CSR - .o_csr_en (csr_en), - .o_csr_addr (csr_addr), - .o_csr_mstatus_en (csr_mstatus_en), - .o_csr_mie_en (csr_mie_en), - .o_csr_mcause_en (csr_mcause_en), - .o_csr_source (csr_source), - .o_csr_d_sel (csr_d_sel), - .o_csr_imm_en (csr_imm_en), - .o_mtval_pc (mtval_pc ), - //To top - .o_immdec_ctrl (immdec_ctrl), - .o_immdec_en (immdec_en), - //To RF IF - .o_rd_mem_en (rd_mem_en), - .o_rd_csr_en (rd_csr_en), - .o_rd_alu_en (rd_alu_en)); - - serv_immdec #(.W (W)) immdec - ( - .i_clk (clk), - //State - .i_cnt_en (cnt_en), - .i_cnt_done (cnt_done), - //Control - .i_immdec_en (immdec_en), - .i_csr_imm_en (csr_imm_en), - .i_ctrl (immdec_ctrl), - .o_rd_addr (rd_addr), - .o_rs1_addr (rs1_addr), - .o_rs2_addr (rs2_addr), - //Data - .o_csr_imm (csr_imm), - .o_imm (imm), - //External - .i_wb_en (wb_ibus_ack), - .i_wb_rdt (i_wb_rdt[31:7])); - - serv_bufreg - #(.MDU(MDU), - .W(W)) - bufreg - ( - .i_clk (clk), - //State - .i_cnt0 (cnt0), - .i_cnt1 (cnt1), - .i_cnt_done (cnt_done), - .i_en (bufreg_en), - .i_init (init), - .i_mdu_op (mdu_op), - .o_lsb (lsb), - //Control - .i_sh_signed (bufreg_sh_signed), - .i_rs1_en (bufreg_rs1_en), - .i_imm_en (bufreg_imm_en), - .i_clr_lsb (bufreg_clr_lsb), - .i_shift_op (shift_op), - .i_right_shift_op (sh_right), - .i_shamt (o_dbus_dat[26:24]), - //Data - .i_rs1 (rs1), - .i_imm (imm), - .o_q (bufreg_q), - //External - .o_dbus_adr (o_dbus_adr), - .o_ext_rs1 (o_ext_rs1)); - - serv_bufreg2 #(.W(W)) bufreg2 - ( - .i_clk (clk), - //State - .i_en (cnt_en), - .i_init (init), - .i_cnt7 (cnt7), - .i_cnt_done (cnt_done), - .i_sh_right (sh_right), - .i_lsb (lsb), - .i_bytecnt (mem_bytecnt), - .o_sh_done (sh_done), - //Control - .i_op_b_sel (op_b_sel), - .i_shift_op (shift_op), - //Data - .i_rs2 (rs2), - .i_imm (imm), - .o_op_b (op_b), - .o_q (bufreg2_q), - //External - .o_dat (o_dbus_dat), - .i_load (dbus_ack), - .i_dat (dbus_rdt)); - - serv_ctrl - #(.RESET_PC (RESET_PC), - .RESET_STRATEGY (RESET_STRATEGY), - .WITH_CSR (WITH_CSR), - .W (W)) - ctrl - ( - .clk (clk), - .i_rst (i_rst), - //State - .i_pc_en (ctrl_pc_en), - .i_cnt12to31 (cnt12to31), - .i_cnt0 (cnt0), - .i_cnt1 (cnt1), - .i_cnt2 (cnt2), - //Control - .i_jump (jump), - .i_jal_or_jalr (jal_or_jalr), - .i_utype (utype), - .i_pc_rel (pc_rel), - .i_trap (trap | mret), - .i_iscomp (iscomp), - //Data - .i_imm (imm), - .i_buf (bufreg_q), - .i_csr_pc (csr_pc), - .o_rd (ctrl_rd), - .o_bad_pc (bad_pc), - //External - .o_ibus_adr (wb_ibus_adr)); - - serv_alu #(.W (W)) alu - ( - .clk (clk), - //State - .i_en (cnt_en), - .i_cnt0 (cnt0), - .o_cmp (alu_cmp), - //Control - .i_sub (alu_sub), - .i_bool_op (alu_bool_op), - .i_cmp_eq (alu_cmp_eq), - .i_cmp_sig (alu_cmp_sig), - .i_rd_sel (alu_rd_sel), - //Data - .i_rs1 (rs1), - .i_op_b (op_b), - .i_buf (bufreg_q), - .o_rd (alu_rd)); - - serv_rf_if - #(.WITH_CSR (WITH_CSR), .W(W)) - rf_if - (//RF interface - .i_cnt_en (cnt_en), - .o_wreg0 (o_wreg0), - .o_wreg1 (o_wreg1), - .o_wen0 (o_wen0), - .o_wen1 (o_wen1), - .o_wdata0 (o_wdata0), - .o_wdata1 (o_wdata1), - .o_rreg0 (o_rreg0), - .o_rreg1 (o_rreg1), - .i_rdata0 (i_rdata0), - .i_rdata1 (i_rdata1), - - //Trap interface - .i_trap (trap), - .i_mret (mret), - .i_mepc (wb_ibus_adr[B:0]), - .i_mtval_pc (mtval_pc), - .i_bufreg_q (bufreg_q), - .i_bad_pc (bad_pc), - .o_csr_pc (csr_pc), - //CSR write port - .i_csr_en (csr_en), - .i_csr_addr (csr_addr), - .i_csr (csr_in), - //RD write port - .i_rd_wen (rd_en), - .i_rd_waddr (rd_addr), - .i_ctrl_rd (ctrl_rd), - .i_alu_rd (alu_rd), - .i_rd_alu_en (rd_alu_en), - .i_csr_rd (csr_rd), - .i_rd_csr_en (rd_csr_en), - .i_mem_rd (mem_rd), - .i_rd_mem_en (rd_mem_en), - - //RS1 read port - .i_rs1_raddr (rs1_addr), - .o_rs1 (rs1), - //RS2 read port - .i_rs2_raddr (rs2_addr), - .o_rs2 (rs2), - - //CSR read port - .o_csr (rf_csr_out)); - - serv_mem_if - #(.WITH_CSR (WITH_CSR[0:0]), - .W (W)) - mem_if - ( - .i_clk (clk), - //State - .i_bytecnt (mem_bytecnt), - .i_lsb (lsb), - .o_misalign (mem_misalign), - //Control - .i_mdu_op (mdu_op), - .i_signed (mem_signed), - .i_word (mem_word), - .i_half (mem_half), - //Data - .i_bufreg2_q (bufreg2_q), - .o_rd (mem_rd), - //External interface - .o_wb_sel (o_dbus_sel)); - - generate - if (|WITH_CSR) begin : gen_csr - serv_csr - #(.RESET_STRATEGY (RESET_STRATEGY), - .W(W)) - csr - ( - .i_clk (clk), - .i_rst (i_rst), - //State - .i_trig_irq (wb_ibus_ack), - .i_en (cnt_en), - .i_cnt0to3 (cnt0to3), - .i_cnt3 (cnt3), - .i_cnt7 (cnt7), - .i_cnt11 (cnt11), - .i_cnt12 (cnt12), - .i_cnt_done (cnt_done), - .i_mem_op (!mtval_pc), - .i_mtip (i_timer_irq), - .i_trap (trap), - .o_new_irq (new_irq), - //Control - .i_e_op (e_op), - .i_ebreak (ebreak), - .i_mem_cmd (o_dbus_we), - .i_mstatus_en (csr_mstatus_en), - .i_mie_en (csr_mie_en ), - .i_mcause_en (csr_mcause_en ), - .i_csr_source (csr_source), - .i_mret (mret), - .i_csr_d_sel (csr_d_sel), - //Data - .i_rf_csr_out (rf_csr_out), - .o_csr_in (csr_in), - .i_csr_imm (csr_imm), - .i_rs1 (rs1), - .o_q (csr_rd)); - end else begin : gen_no_csr - assign csr_in = {W{1'b0}}; - assign csr_rd = {W{1'b0}}; - assign new_irq = 1'b0; - end - endgenerate - - generate - if (DEBUG) begin : gen_debug - serv_debug #(.W (W), .RESET_PC (RESET_PC)) debug - ( -`ifdef RISCV_FORMAL - .rvfi_valid (rvfi_valid ), - .rvfi_order (rvfi_order ), - .rvfi_insn (rvfi_insn ), - .rvfi_trap (rvfi_trap ), - .rvfi_halt (rvfi_halt ), - .rvfi_intr (rvfi_intr ), - .rvfi_mode (rvfi_mode ), - .rvfi_ixl (rvfi_ixl ), - .rvfi_rs1_addr (rvfi_rs1_addr ), - .rvfi_rs2_addr (rvfi_rs2_addr ), - .rvfi_rs1_rdata (rvfi_rs1_rdata), - .rvfi_rs2_rdata (rvfi_rs2_rdata), - .rvfi_rd_addr (rvfi_rd_addr ), - .rvfi_rd_wdata (rvfi_rd_wdata ), - .rvfi_pc_rdata (rvfi_pc_rdata ), - .rvfi_pc_wdata (rvfi_pc_wdata ), - .rvfi_mem_addr (rvfi_mem_addr ), - .rvfi_mem_rmask (rvfi_mem_rmask), - .rvfi_mem_wmask (rvfi_mem_wmask), - .rvfi_mem_rdata (rvfi_mem_rdata), - .rvfi_mem_wdata (rvfi_mem_wdata), - .i_dbus_adr (o_dbus_adr), - .i_dbus_dat (o_dbus_dat), - .i_dbus_sel (o_dbus_sel), - .i_dbus_we (o_dbus_we ), - .i_dbus_rdt (i_dbus_rdt), - .i_dbus_ack (i_dbus_ack), - .i_ctrl_pc_en (ctrl_pc_en), - .rs1 (rs1), - .rs2 (rs2), - .rs1_addr (rs1_addr), - .rs2_addr (rs2_addr), - .immdec_en (immdec_en), - .rd_en (rd_en), - .trap (trap), - .i_rf_ready (i_rf_ready), - .i_ibus_cyc (o_ibus_cyc), - .two_stage_op (two_stage_op), - .init (init), - .i_ibus_adr (o_ibus_adr), -`endif - .i_clk (clk), - .i_rst (i_rst), - .i_ibus_rdt (i_ibus_rdt), - .i_ibus_ack (i_ibus_ack), - .i_rd_addr (rd_addr ), - .i_cnt_en (cnt_en ), - .i_csr_in (csr_in ), - .i_csr_mstatus_en (csr_mstatus_en), - .i_csr_mie_en (csr_mie_en ), - .i_csr_mcause_en (csr_mcause_en ), - .i_csr_en (csr_en ), - .i_csr_addr (csr_addr), - .i_wen0 (o_wen0), - .i_wdata0 (o_wdata0), - .i_cnt_done (cnt_done)); - end - endgenerate - - -generate - if (MDU) begin: gen_mdu - assign dbus_rdt = i_ext_ready ? i_ext_rd:i_dbus_rdt; - assign dbus_ack = i_dbus_ack | i_ext_ready; - end else begin : gen_no_mdu - assign dbus_rdt = i_dbus_rdt; - assign dbus_ack = i_dbus_ack; - end - assign o_ext_rs2 = o_dbus_dat; -endgenerate - -endmodule -`default_nettype wire diff --git a/rtl/serv/servile.v b/rtl/serv/servile.v deleted file mode 100644 index 8e5b138..0000000 --- a/rtl/serv/servile.v +++ /dev/null @@ -1,280 +0,0 @@ -/* - * servile.v : Top-level for Servile, the SERV convenience wrapper - * - * SPDX-FileCopyrightText: 2024 Olof Kindgren - * SPDX-License-Identifier: Apache-2.0 - */ - -`default_nettype none -`include "../util/clog2.vh" -module servile - #( - parameter width = 1, - parameter reset_pc = 32'h00000000, - parameter reset_strategy = "MINI", - parameter rf_width = 2*width, - parameter [0:0] sim = 1'b0, - parameter [0:0] debug = 1'b0, - parameter [0:0] with_c = 1'b0, - parameter [0:0] with_csr = 1'b0, - parameter [0:0] with_mdu = 1'b0, - //Internally calculated. Do not touch - parameter B = width-1, - parameter regs = 32+with_csr*4, - parameter rf_l2d = `CLOG2(regs*32/rf_width)) - ( - input wire i_clk, - input wire i_rst, - input wire i_timer_irq, - - //Memory (WB) interface - output wire [31:0] o_wb_mem_adr, - output wire [31:0] o_wb_mem_dat, - output wire [3:0] o_wb_mem_sel, - output wire o_wb_mem_we , - output wire o_wb_mem_stb, - input wire [31:0] i_wb_mem_rdt, - input wire i_wb_mem_ack, - - //Extension (WB) interface - output wire [31:0] o_wb_ext_adr, - output wire [31:0] o_wb_ext_dat, - output wire [3:0] o_wb_ext_sel, - output wire o_wb_ext_we , - output wire o_wb_ext_stb, - input wire [31:0] i_wb_ext_rdt, - input wire i_wb_ext_ack, - - //RF (SRAM) interface - output wire [rf_l2d-1:0] o_rf_waddr, - output wire [rf_width-1:0] o_rf_wdata, - output wire o_rf_wen, - output wire [rf_l2d-1:0] o_rf_raddr, - input wire [rf_width-1:0] i_rf_rdata, - output wire o_rf_ren); - - - - wire [31:0] wb_ibus_adr; - wire wb_ibus_stb; - wire [31:0] wb_ibus_rdt; - wire wb_ibus_ack; - - wire [31:0] wb_dbus_adr; - wire [31:0] wb_dbus_dat; - wire [3:0] wb_dbus_sel; - wire wb_dbus_we; - wire wb_dbus_stb; - wire [31:0] wb_dbus_rdt; - wire wb_dbus_ack; - - wire [31:0] wb_dmem_adr; - wire [31:0] wb_dmem_dat; - wire [3:0] wb_dmem_sel; - wire wb_dmem_we; - wire wb_dmem_stb; - wire [31:0] wb_dmem_rdt; - wire wb_dmem_ack; - - wire rf_wreq; - wire rf_rreq; - wire [`CLOG2(regs)-1:0] wreg0; - wire [`CLOG2(regs)-1:0] wreg1; - wire wen0; - wire wen1; - wire [B:0] wdata0; - wire [B:0] wdata1; - wire [`CLOG2(regs)-1:0] rreg0; - wire [`CLOG2(regs)-1:0] rreg1; - wire rf_ready; - wire [B:0] rdata0; - wire [B:0] rdata1; - - wire [31:0] mdu_rs1; - wire [31:0] mdu_rs2; - wire [ 2:0] mdu_op; - wire mdu_valid; - wire [31:0] mdu_rd; - wire mdu_ready; - - servile_mux - #(.sim (sim)) - mux - (.i_clk (i_clk), - .i_rst (i_rst & (reset_strategy != "NONE")), - - .i_wb_cpu_adr (wb_dbus_adr), - .i_wb_cpu_dat (wb_dbus_dat), - .i_wb_cpu_sel (wb_dbus_sel), - .i_wb_cpu_we (wb_dbus_we), - .i_wb_cpu_stb (wb_dbus_stb), - .o_wb_cpu_rdt (wb_dbus_rdt), - .o_wb_cpu_ack (wb_dbus_ack), - - .o_wb_mem_adr (wb_dmem_adr), - .o_wb_mem_dat (wb_dmem_dat), - .o_wb_mem_sel (wb_dmem_sel), - .o_wb_mem_we (wb_dmem_we), - .o_wb_mem_stb (wb_dmem_stb), - .i_wb_mem_rdt (wb_dmem_rdt), - .i_wb_mem_ack (wb_dmem_ack), - - .o_wb_ext_adr (o_wb_ext_adr), - .o_wb_ext_dat (o_wb_ext_dat), - .o_wb_ext_sel (o_wb_ext_sel), - .o_wb_ext_we (o_wb_ext_we), - .o_wb_ext_stb (o_wb_ext_stb), - .i_wb_ext_rdt (i_wb_ext_rdt), - .i_wb_ext_ack (i_wb_ext_ack)); - - servile_arbiter arbiter - (.i_wb_cpu_dbus_adr (wb_dmem_adr), - .i_wb_cpu_dbus_dat (wb_dmem_dat), - .i_wb_cpu_dbus_sel (wb_dmem_sel), - .i_wb_cpu_dbus_we (wb_dmem_we ), - .i_wb_cpu_dbus_stb (wb_dmem_stb), - .o_wb_cpu_dbus_rdt (wb_dmem_rdt), - .o_wb_cpu_dbus_ack (wb_dmem_ack), - - .i_wb_cpu_ibus_adr (wb_ibus_adr), - .i_wb_cpu_ibus_stb (wb_ibus_stb), - .o_wb_cpu_ibus_rdt (wb_ibus_rdt), - .o_wb_cpu_ibus_ack (wb_ibus_ack), - - .o_wb_mem_adr (o_wb_mem_adr), - .o_wb_mem_dat (o_wb_mem_dat), - .o_wb_mem_sel (o_wb_mem_sel), - .o_wb_mem_we (o_wb_mem_we ), - .o_wb_mem_stb (o_wb_mem_stb), - .i_wb_mem_rdt (i_wb_mem_rdt), - .i_wb_mem_ack (i_wb_mem_ack)); - - - - serv_rf_ram_if - #(.width (rf_width), - .W (width), - .reset_strategy (reset_strategy), - .csr_regs (with_csr*4)) - rf_ram_if - (.i_clk (i_clk), - .i_rst (i_rst), - //RF IF - .i_wreq (rf_wreq), - .i_rreq (rf_rreq), - .o_ready (rf_ready), - .i_wreg0 (wreg0), - .i_wreg1 (wreg1), - .i_wen0 (wen0), - .i_wen1 (wen1), - .i_wdata0 (wdata0), - .i_wdata1 (wdata1), - .i_rreg0 (rreg0), - .i_rreg1 (rreg1), - .o_rdata0 (rdata0), - .o_rdata1 (rdata1), - //SRAM IF - .o_waddr (o_rf_waddr), - .o_wdata (o_rf_wdata), - .o_wen (o_rf_wen), - .o_raddr (o_rf_raddr), - .o_ren (o_rf_ren), - .i_rdata (i_rf_rdata)); - - generate - if (with_mdu) begin : gen_mdu - mdu_top mdu_serv - (.i_clk (i_clk), - .i_rst (i_rst), - .i_mdu_rs1 (mdu_rs1), - .i_mdu_rs2 (mdu_rs2), - .i_mdu_op (mdu_op), - .i_mdu_valid (mdu_valid), - .o_mdu_ready (mdu_ready), - .o_mdu_rd (mdu_rd)); - end else begin - assign mdu_ready = 1'b0; - assign mdu_rd = 32'd0; - end - endgenerate - - serv_top - #( - .WITH_CSR (with_csr?1:0), - .W (width), - .PRE_REGISTER (1'b1), - .RESET_STRATEGY (reset_strategy), - .RESET_PC (reset_pc), - .DEBUG (debug), - .MDU (with_mdu), - .COMPRESSED (with_c)) - cpu - ( - .clk (i_clk), - .i_rst (i_rst), - .i_timer_irq (i_timer_irq), - -`ifdef RISCV_FORMAL - .rvfi_valid (), - .rvfi_order (), - .rvfi_insn (), - .rvfi_trap (), - .rvfi_halt (), - .rvfi_intr (), - .rvfi_mode (), - .rvfi_ixl (), - .rvfi_rs1_addr (), - .rvfi_rs2_addr (), - .rvfi_rs1_rdata (), - .rvfi_rs2_rdata (), - .rvfi_rd_addr (), - .rvfi_rd_wdata (), - .rvfi_pc_rdata (), - .rvfi_pc_wdata (), - .rvfi_mem_addr (), - .rvfi_mem_rmask (), - .rvfi_mem_wmask (), - .rvfi_mem_rdata (), - .rvfi_mem_wdata (), -`endif - //RF IF - .o_rf_rreq (rf_rreq), - .o_rf_wreq (rf_wreq), - .i_rf_ready (rf_ready), - .o_wreg0 (wreg0), - .o_wreg1 (wreg1), - .o_wen0 (wen0), - .o_wen1 (wen1), - .o_wdata0 (wdata0), - .o_wdata1 (wdata1), - .o_rreg0 (rreg0), - .o_rreg1 (rreg1), - .i_rdata0 (rdata0), - .i_rdata1 (rdata1), - - //Instruction bus - .o_ibus_adr (wb_ibus_adr), - .o_ibus_cyc (wb_ibus_stb), - .i_ibus_rdt (wb_ibus_rdt), - .i_ibus_ack (wb_ibus_ack), - - //Data bus - .o_dbus_adr (wb_dbus_adr), - .o_dbus_dat (wb_dbus_dat), - .o_dbus_sel (wb_dbus_sel), - .o_dbus_we (wb_dbus_we), - .o_dbus_cyc (wb_dbus_stb), - .i_dbus_rdt (wb_dbus_rdt), - .i_dbus_ack (wb_dbus_ack), - - //Extension IF - .o_ext_rs1 (mdu_rs1), - .o_ext_rs2 (mdu_rs2), - .o_ext_funct3 (mdu_op), - .i_ext_rd (mdu_rd), - .i_ext_ready (mdu_ready), - //MDU - .o_mdu_valid (mdu_valid)); - -endmodule -`default_nettype wire diff --git a/rtl/serv/servile_arbiter.v b/rtl/serv/servile_arbiter.v deleted file mode 100644 index 720fa2b..0000000 --- a/rtl/serv/servile_arbiter.v +++ /dev/null @@ -1,45 +0,0 @@ -/* - * servile_arbiter.v : I/D arbiter for the servile convenience wrapper. - * Relies on the fact that not ibus and dbus are active at the same time. - * - * SPDX-FileCopyrightText: 2024 Olof Kindgren - * SPDX-License-Identifier: Apache-2.0 - */ - -module servile_arbiter - ( - input wire [31:0] i_wb_cpu_dbus_adr, - input wire [31:0] i_wb_cpu_dbus_dat, - input wire [3:0] i_wb_cpu_dbus_sel, - input wire i_wb_cpu_dbus_we, - input wire i_wb_cpu_dbus_stb, - output wire [31:0] o_wb_cpu_dbus_rdt, - output wire o_wb_cpu_dbus_ack, - - input wire [31:0] i_wb_cpu_ibus_adr, - input wire i_wb_cpu_ibus_stb, - output wire [31:0] o_wb_cpu_ibus_rdt, - output wire o_wb_cpu_ibus_ack, - - output wire [31:0] o_wb_mem_adr, - output wire [31:0] o_wb_mem_dat, - output wire [3:0] o_wb_mem_sel, - output wire o_wb_mem_we, - output wire o_wb_mem_stb, - input wire [31:0] i_wb_mem_rdt, - input wire i_wb_mem_ack); - - assign o_wb_cpu_dbus_rdt = i_wb_mem_rdt; - assign o_wb_cpu_dbus_ack = i_wb_mem_ack & !i_wb_cpu_ibus_stb; - - assign o_wb_cpu_ibus_rdt = i_wb_mem_rdt; - assign o_wb_cpu_ibus_ack = i_wb_mem_ack & i_wb_cpu_ibus_stb; - - assign o_wb_mem_adr = i_wb_cpu_ibus_stb ? i_wb_cpu_ibus_adr : i_wb_cpu_dbus_adr; - assign o_wb_mem_dat = i_wb_cpu_dbus_dat; - assign o_wb_mem_sel = i_wb_cpu_dbus_sel; - assign o_wb_mem_we = i_wb_cpu_dbus_we & !i_wb_cpu_ibus_stb; - assign o_wb_mem_stb = i_wb_cpu_ibus_stb | i_wb_cpu_dbus_stb; - - -endmodule diff --git a/rtl/serv/servile_mux.v b/rtl/serv/servile_mux.v deleted file mode 100644 index e4d8c5c..0000000 --- a/rtl/serv/servile_mux.v +++ /dev/null @@ -1,100 +0,0 @@ -/* - * servile_mux.v : Simple Wishbone mux for the servile convenience wrapper. - * - * SPDX-FileCopyrightText: 2024 Olof Kindgren - * SPDX-License-Identifier: Apache-2.0 - */ - -module servile_mux - #(parameter [0:0] sim = 1'b0, //Enable simulation features - parameter [31:0] sim_sig_adr = 32'h80000000, - parameter [31:0] sim_halt_adr = 32'h90000000) - ( - input wire i_clk, - input wire i_rst, - - input wire [31:0] i_wb_cpu_adr, - input wire [31:0] i_wb_cpu_dat, - input wire [3:0] i_wb_cpu_sel, - input wire i_wb_cpu_we, - input wire i_wb_cpu_stb, - output wire [31:0] o_wb_cpu_rdt, - output wire o_wb_cpu_ack, - - output wire [31:0] o_wb_mem_adr, - output wire [31:0] o_wb_mem_dat, - output wire [3:0] o_wb_mem_sel, - output wire o_wb_mem_we, - output wire o_wb_mem_stb, - input wire [31:0] i_wb_mem_rdt, - input wire i_wb_mem_ack, - - output wire [31:0] o_wb_ext_adr, - output wire [31:0] o_wb_ext_dat, - output wire [3:0] o_wb_ext_sel, - output wire o_wb_ext_we, - output wire o_wb_ext_stb, - input wire [31:0] i_wb_ext_rdt, - input wire i_wb_ext_ack); - - wire sig_en; - wire halt_en; - reg sim_ack; - - wire ext = (i_wb_cpu_adr[31:30] != 2'b00); - - assign o_wb_cpu_rdt = ext ? i_wb_ext_rdt : i_wb_mem_rdt; - assign o_wb_cpu_ack = i_wb_ext_ack | i_wb_mem_ack | sim_ack; - - assign o_wb_mem_adr = i_wb_cpu_adr; - assign o_wb_mem_dat = i_wb_cpu_dat; - assign o_wb_mem_sel = i_wb_cpu_sel; - assign o_wb_mem_we = i_wb_cpu_we; - assign o_wb_mem_stb = i_wb_cpu_stb & !ext & !(sig_en|halt_en); - - assign o_wb_ext_adr = i_wb_cpu_adr; - assign o_wb_ext_dat = i_wb_cpu_dat; - assign o_wb_ext_sel = i_wb_cpu_sel; - assign o_wb_ext_we = i_wb_cpu_we; - assign o_wb_ext_stb = i_wb_cpu_stb & ext & !(sig_en|halt_en); - - generate - if (sim) begin - - integer f = 0; - - assign sig_en = |f & i_wb_cpu_we & (i_wb_cpu_adr == sim_sig_adr); - assign halt_en = i_wb_cpu_we & (i_wb_cpu_adr == sim_halt_adr); - - reg [1023:0] signature_file; - - initial - /* verilator lint_off WIDTH */ - if ($value$plusargs("signature=%s", signature_file)) begin - $display("Writing signature to %0s", signature_file); - f = $fopen(signature_file, "w"); - end - /* verilator lint_on WIDTH */ - - always @(posedge i_clk) begin - sim_ack <= 1'b0; - if (i_wb_cpu_stb & !sim_ack) begin - sim_ack <= sig_en|halt_en; - if (sig_en & (f != 0)) - $fwrite(f, "%c", i_wb_cpu_dat[7:0]); - else if(halt_en) begin - $display("Test complete"); - $finish; - end - end - if (i_rst) - sim_ack <= 1'b0; - end - end else begin - assign sig_en = 1'b0; - assign halt_en = 1'b0; - initial sim_ack = 1'b0; - end - endgenerate - -endmodule diff --git a/rtl/serv/servile_rf_mem_if.v b/rtl/serv/servile_rf_mem_if.v deleted file mode 100644 index f7c613f..0000000 --- a/rtl/serv/servile_rf_mem_if.v +++ /dev/null @@ -1,78 +0,0 @@ -/* - * servile_rf_mem_if.v : Arbiter to allow a shared SRAM for RF and memory accesses. RF is mapped to the highest 128 bytes of the memory. Requires 8-bit RF accesses. - * - * SPDX-FileCopyrightText: 2024 Olof Kindgren - * SPDX-License-Identifier: Apache-2.0 - */ - -`default_nettype none -`include "../util/clog2.vh" -module servile_rf_mem_if - #(//Memory parameters - parameter depth = 256, - //RF parameters - parameter rf_regs = 32, - //Internally calculated. Do not touch - parameter rf_depth = `CLOG2(rf_regs*4), - parameter aw = `CLOG2(depth)) - ( - input wire i_clk, - input wire i_rst, - input wire [rf_depth-1:0] i_waddr, - input wire [7:0] i_wdata, - input wire i_wen, - input wire [rf_depth-1:0] i_raddr, - output wire [7:0] o_rdata, - input wire i_ren, - - output wire [aw-1:0] o_sram_waddr, - output wire [7:0] o_sram_wdata, - output wire o_sram_wen, - output wire [aw-1:0] o_sram_raddr, - input wire [7:0] i_sram_rdata, - output wire o_sram_ren, - - input wire [aw-1:2] i_wb_adr, - input wire [31:0] i_wb_dat, - input wire [3:0] i_wb_sel, - input wire i_wb_we, - input wire i_wb_stb, - output wire [31:0] o_wb_rdt, - output reg o_wb_ack); - - reg [1:0] bsel; - - wire wb_en = i_wb_stb & !i_wen & !o_wb_ack; - - wire wb_we = i_wb_we & i_wb_sel[bsel]; - - wire [aw-1:0] rf_waddr = ~{{aw-rf_depth{1'b0}},i_waddr}; - wire [aw-1:0] rf_raddr = ~{{aw-rf_depth{1'b0}},i_raddr}; - - assign o_sram_waddr = wb_en ? {i_wb_adr[aw-1:2],bsel} : rf_waddr; - assign o_sram_wdata = wb_en ? i_wb_dat[bsel*8+:8] : i_wdata; - assign o_sram_wen = wb_en ? wb_we : i_wen; - assign o_sram_raddr = wb_en ? {i_wb_adr[aw-1:2],bsel} : rf_raddr; - assign o_sram_ren = wb_en ? !i_wb_we : i_ren; - - reg [23:0] wb_rdt; - assign o_wb_rdt = {i_sram_rdata, wb_rdt}; - - reg regzero; - always @(posedge i_clk) begin - - if (wb_en) bsel <= bsel + 2'd1; - o_wb_ack <= wb_en & &bsel; - if (bsel == 2'b01) wb_rdt[7:0] <= i_sram_rdata; - if (bsel == 2'b10) wb_rdt[15:8] <= i_sram_rdata; - if (bsel == 2'b11) wb_rdt[23:16] <= i_sram_rdata; - if (i_rst) begin - bsel <= 2'd0; - o_wb_ack <= 1'b0; - end - regzero <= &i_raddr[rf_depth-1:2]; - end - - assign o_rdata = regzero ? 8'd0 : i_sram_rdata; - -endmodule diff --git a/rtl/serv/serving.v b/rtl/serv/serving.v deleted file mode 100644 index 61ab779..0000000 --- a/rtl/serv/serving.v +++ /dev/null @@ -1,149 +0,0 @@ -/* serving.v : Top-level for the serving SoC - * - * ISC License - * - * Copyright (C) 2020 Olof Kindgren - * - * 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. - */ - -`default_nettype none -`include "../util/clog2.vh" -module serving - ( - input wire i_clk, - input wire i_rst, - input wire i_timer_irq, - - output wire [31:0] o_wb_adr, - output wire [31:0] o_wb_dat, - output wire [3:0] o_wb_sel, - output wire o_wb_we , - output wire o_wb_stb, - input wire [31:0] i_wb_rdt, - input wire i_wb_ack); - - parameter memfile = ""; - parameter memsize = 8192; - parameter sim = 1'b0; - parameter RESET_STRATEGY = "NONE"; - parameter WITH_CSR = 1; - localparam regs = 32+WITH_CSR*4; - - localparam rf_width = 8; - - wire [31:0] wb_mem_adr; - wire [31:0] wb_mem_dat; - wire [3:0] wb_mem_sel; - wire wb_mem_we; - wire wb_mem_stb; - wire [31:0] wb_mem_rdt; - wire wb_mem_ack; - - wire [6+WITH_CSR:0] rf_waddr; - wire [rf_width-1:0] rf_wdata; - wire rf_wen; - wire [6+WITH_CSR:0] rf_raddr; - wire [rf_width-1:0] rf_rdata; - wire rf_ren; - - wire [`CLOG2(memsize)-1:0] sram_waddr; - wire [rf_width-1:0] sram_wdata; - wire sram_wen; - wire [`CLOG2(memsize)-1:0] sram_raddr; - wire [rf_width-1:0] sram_rdata; - wire sram_ren; - - serving_ram - #(.memfile (memfile), - .depth (memsize), - .sim (sim)) - ram - (// Wishbone interface - .i_clk (i_clk), - .i_waddr (sram_waddr), - .i_wdata (sram_wdata), - .i_wen (sram_wen), - .i_raddr (sram_raddr), - .o_rdata (sram_rdata)/*, - .i_ren (rf_ren)*/); - - servile_rf_mem_if - #(.depth (memsize), - .rf_regs (regs)) - rf_mem_if - (// Wishbone interface - .i_clk (i_clk), - .i_rst (i_rst), - - .i_waddr (rf_waddr), - .i_wdata (rf_wdata), - .i_wen (rf_wen), - .i_raddr (rf_raddr), - .o_rdata (rf_rdata), - .i_ren (rf_ren), - - .o_sram_waddr (sram_waddr), - .o_sram_wdata (sram_wdata), - .o_sram_wen (sram_wen), - .o_sram_raddr (sram_raddr), - .i_sram_rdata (sram_rdata), - .o_sram_ren (sram_ren), - - .i_wb_adr (wb_mem_adr[`CLOG2(memsize)-1:2]), - .i_wb_stb (wb_mem_stb), - .i_wb_we (wb_mem_we) , - .i_wb_sel (wb_mem_sel), - .i_wb_dat (wb_mem_dat), - .o_wb_rdt (wb_mem_rdt), - .o_wb_ack (wb_mem_ack)); - - servile - #(.reset_pc (32'h0000_0000), - .reset_strategy (RESET_STRATEGY), - .rf_width (rf_width), - .sim (sim), - .with_csr (WITH_CSR)) - servile - ( - .i_clk (i_clk), - .i_rst (i_rst), - .i_timer_irq (i_timer_irq), - //Memory interface - .o_wb_mem_adr (wb_mem_adr), - .o_wb_mem_dat (wb_mem_dat), - .o_wb_mem_sel (wb_mem_sel), - .o_wb_mem_we (wb_mem_we), - .o_wb_mem_stb (wb_mem_stb), - .i_wb_mem_rdt (wb_mem_rdt), - .i_wb_mem_ack (wb_mem_ack), - - //Extension interface - .o_wb_ext_adr (o_wb_adr), - .o_wb_ext_dat (o_wb_dat), - .o_wb_ext_sel (o_wb_sel), - .o_wb_ext_we (o_wb_we), - .o_wb_ext_stb (o_wb_stb), - .i_wb_ext_rdt (i_wb_rdt), - .i_wb_ext_ack (i_wb_ack), - - //RF IF - .o_rf_waddr (rf_waddr), - .o_rf_wdata (rf_wdata), - .o_rf_wen (rf_wen), - .o_rf_raddr (rf_raddr), - .o_rf_ren (rf_ren), - .i_rf_rdata (rf_rdata)); - - -endmodule diff --git a/rtl/serv/serving_ram.v b/rtl/serv/serving_ram.v deleted file mode 100644 index 05429e7..0000000 --- a/rtl/serv/serving_ram.v +++ /dev/null @@ -1,54 +0,0 @@ -/* serving_ram.v : I/D SRAM for the serving SoC - * - * ISC License - * - * Copyright (C) 2020 Olof Kindgren - * - * 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. - */ - -`default_nettype none -`include "../util/clog2.vh" -module serving_ram - #(//Memory parameters - parameter depth = 256, - parameter aw = `CLOG2(depth), - parameter memfile = "", - parameter sim = 1'b0) - (input wire i_clk, - input wire [aw-1:0] i_waddr, - input wire [7:0] i_wdata, - input wire i_wen, - input wire [aw-1:0] i_raddr, - output reg [7:0] o_rdata); - - reg [7:0] mem [0:depth-1] /* verilator public */; - - always @(posedge i_clk) begin - if (i_wen) mem[i_waddr] <= i_wdata; - o_rdata <= mem[i_raddr]; - end - - integer i; - initial begin - if(sim==1'b1) begin - for (i = 0; i < depth; i = i + 1) - mem[i] = 8'h00; - - end - if(|memfile) begin - $display("Preloading %m from %s", memfile); - $readmemh(memfile, mem); - end - end -endmodule diff --git a/rtl/toplevel/top_jtag.v b/rtl/toplevel/top_jtag.v deleted file mode 100644 index fa48fc9..0000000 --- a/rtl/toplevel/top_jtag.v +++ /dev/null @@ -1,73 +0,0 @@ -module top_jtag( - input wire aclk, - input wire aresetn, - - output wire led_green, - output wire led_red, - output wire [7:0] LED, - - output wire [5:0] r2r -); - // Clocking - wire clk_100; - wire clk_15; - assign clk_100 = aclk; - clk_gen clk( - .clk_in(clk_100), - .clk_out_15(clk_15) - ); - - wire i_rst; - assign i_rst = !aresetn; - - wire [31:0] wb_adr; - wire [31:0] wb_dat; - wire [31:0] wb_rdt; - wire [3:0] wb_sel; - wire wb_cyc; - wire wb_we; - wire wb_stb; - wire wb_ack; - wire cmd_reset; - - jtag_wb_bridge #( - .chain(1) - ) jtag_wb ( - .i_clk(clk_15), - .i_rst(!aresetn), - - .o_wb_adr(wb_adr), - .o_wb_dat(wb_dat), - .o_wb_sel(wb_sel), - .o_wb_we(wb_we), - .o_wb_cyc(wb_cyc), - .o_wb_stb(wb_stb), - .i_wb_rdt(wb_rdt), - .i_wb_ack(wb_ack), - .o_cmd_reset(cmd_reset) - ); - - wire [31:0] gpio; - - wb_gpio #( - .address(32'h00000000) - ) u_wb_gpio ( - .i_wb_clk(clk_15), - .i_wb_rst(i_rst), - .i_wb_adr(wb_adr), - .i_wb_dat(wb_dat), - .i_wb_sel(wb_sel), - .i_wb_we(wb_we), - .i_wb_stb(wb_stb & wb_cyc), - .i_gpio(gpio), - .o_wb_rdt(wb_rdt), - .o_wb_ack(wb_ack), - .o_gpio(gpio) - ); - - assign LED = gpio[7:0]; - assign r2r = gpio[13:8]; - assign led_green = cmd_reset; - assign led_red = 'b0; - -endmodule diff --git a/rtl/wb/wb_gpio.v b/rtl/wb/wb_gpio.v deleted file mode 100644 index da5fcc2..0000000 --- a/rtl/wb/wb_gpio.v +++ /dev/null @@ -1,55 +0,0 @@ -module wb_gpio #( - parameter address = 32'h00000000 -)( - input wire i_wb_clk, - input wire i_wb_rst, // optional; tie low if unused - input wire [31:0] i_wb_adr, // optional; can ignore for single-reg - input wire [31:0] i_wb_dat, - input wire [3:0] i_wb_sel, - input wire i_wb_we, - input wire i_wb_stb, - input wire [31:0] i_gpio, - - output reg [31:0] o_wb_rdt, - output reg o_wb_ack, - output reg [31:0] o_gpio -); - - initial o_gpio <= 32'h00000000; - initial o_wb_rdt <= 32'h00000000; - - wire addr_check; - assign addr_check = (i_wb_adr == address); - - // One-cycle ACK pulse per request (works even if stb stays high) - always @(posedge i_wb_clk) begin - if (i_wb_rst) begin - o_wb_ack <= 1'b0; - end else begin - o_wb_ack <= i_wb_stb & ~o_wb_ack; // pulse while stb asserted - end - end - - // Read data (combinational or registered; registered here) - always @(posedge i_wb_clk) begin - if (i_wb_rst) begin - o_wb_rdt <= 32'h0; - end else if (i_wb_stb && !i_wb_we) begin - o_wb_rdt <= i_gpio; - end - end - - // Write latch (update on the acknowledged cycle) - always @(posedge i_wb_clk) begin - if (i_wb_rst) begin - o_gpio <= 32'h0; - end else if (i_wb_stb && i_wb_we && addr_check && (i_wb_stb & ~o_wb_ack)) begin - // Apply byte enables (so sb works if the master uses sel) - if (i_wb_sel[0]) o_gpio[7:0] <= i_wb_dat[7:0]; - if (i_wb_sel[1]) o_gpio[15:8] <= i_wb_dat[15:8]; - if (i_wb_sel[2]) o_gpio[23:16] <= i_wb_dat[23:16]; - if (i_wb_sel[3]) o_gpio[31:24] <= i_wb_dat[31:24]; - end - end - -endmodule diff --git a/rtl/wb/wb_gpio_banks.v b/rtl/wb/wb_gpio_banks.v deleted file mode 100644 index 48f4936..0000000 --- a/rtl/wb/wb_gpio_banks.v +++ /dev/null @@ -1,63 +0,0 @@ -`default_nettype none - -module wb_gpio_banks #( - parameter integer NUM_BANKS = 4, - parameter [31:0] BASE_ADDR = 32'h8000_0000 -) ( - input wire i_wb_clk, - input wire i_wb_rst, - input wire [31:0] i_wb_adr, - input wire [31:0] i_wb_dat, - input wire [3:0] i_wb_sel, - input wire i_wb_we, - input wire i_wb_stb, - input wire [NUM_BANKS*32-1:0] i_gpio, - output reg [31:0] o_wb_rdt, - output reg o_wb_ack, - output wire [NUM_BANKS*32-1:0] o_gpio -); - - wire [NUM_BANKS-1:0] bank_sel; - wire [NUM_BANKS-1:0] bank_stb; - wire [NUM_BANKS*32-1:0] bank_rdt; - wire [NUM_BANKS-1:0] bank_ack; - - genvar gi; - generate - for (gi = 0; gi < NUM_BANKS; gi = gi + 1) begin : gen_gpio - localparam [31:0] BANK_ADDR = BASE_ADDR + (gi * 4); - - assign bank_sel[gi] = (i_wb_adr == BANK_ADDR); - assign bank_stb[gi] = i_wb_stb & bank_sel[gi]; - - wb_gpio #( - .address(BANK_ADDR) - ) u_gpio ( - .i_wb_clk(i_wb_clk), - .i_wb_rst(i_wb_rst), - .i_wb_adr(i_wb_adr), - .i_wb_dat(i_wb_dat), - .i_wb_sel(i_wb_sel), - .i_wb_we(i_wb_we), - .i_wb_stb(bank_stb[gi]), - .i_gpio(i_gpio[gi*32 +: 32]), - .o_wb_rdt(bank_rdt[gi*32 +: 32]), - .o_wb_ack(bank_ack[gi]), - .o_gpio(o_gpio[gi*32 +: 32]) - ); - end - endgenerate - - integer bi; - always @* begin - o_wb_rdt = 32'h0000_0000; - o_wb_ack = 1'b0; - for (bi = 0; bi < NUM_BANKS; bi = bi + 1) begin - if (bank_sel[bi]) begin - o_wb_rdt = bank_rdt[bi*32 +: 32]; - o_wb_ack = bank_ack[bi]; - end - end - end - -endmodule diff --git a/rtl/wb/wb_timer.v b/rtl/wb/wb_timer.v deleted file mode 100644 index ac14586..0000000 --- a/rtl/wb/wb_timer.v +++ /dev/null @@ -1,74 +0,0 @@ -`timescale 1ns/1ps - -module wb_countdown_timer #( - parameter WIDTH = 32, // counter width (<=32 makes bus mapping easy) - parameter DIVIDER = 0 // optional prescaler: tick every 2^DIVIDER cycles -)( - input wire i_clk, - input wire i_rst, - output reg o_irq, - - input wire [31:0] i_wb_dat, - output reg [31:0] o_wb_dat, - input wire i_wb_we, - input wire i_wb_cyc, - input wire i_wb_stb, - output wire o_wb_ack -); - - // One-cycle acknowledge on any valid WB access - // (classic, zero-wait-state peripheral) - assign o_wb_ack = i_wb_cyc & i_wb_stb; - - // Internal countdown and prescaler - reg [WIDTH-1:0] counter; - reg [DIVIDER:0] presc; // enough bits to count up to 2^DIVIDER-1 - wire tick = (DIVIDER == 0) ? 1'b1 : (presc[DIVIDER] == 1'b1); - - // Readback: expose the current counter value - always @(*) begin - o_wb_dat = 32'd0; - o_wb_dat[WIDTH-1:0] = counter; - end - - // Main logic - always @(posedge i_clk) begin - if (i_rst) begin - counter <= {WIDTH{1'b0}}; - presc <= { (DIVIDER+1){1'b0} }; - o_irq <= 1'b0; - end else begin - // Default prescaler behavior - if (DIVIDER != 0) begin - if (counter != 0 && !o_irq) - presc <= presc + 1'b1; - else - presc <= { (DIVIDER+1){1'b0} }; - end - - // Wishbone write: load counter and clear IRQ - if (o_wb_ack && i_wb_we) begin - counter <= i_wb_dat[WIDTH-1:0]; - o_irq <= 1'b0; - - // reset prescaler on (re)start or stop - presc <= { (DIVIDER+1){1'b0} }; - - end else begin - // Countdown when running (counter>0), not already IRQ'd - if (!o_irq && counter != 0) begin - if (tick) begin - if (counter == 1) begin - counter <= {WIDTH{1'b0}}; - o_irq <= 1'b1; // sticky until next write - presc <= { (DIVIDER+1){1'b0} }; - end else begin - counter <= counter - 1'b1; - end - end - end - end - end - end - -endmodule \ No newline at end of file diff --git a/scripts/filter_design/bode_compare_Ks_lpf_iir_q15_k.py b/scripts/filter_design/bode_compare_Ks_lpf_iir_q15_k.py deleted file mode 100644 index c34b51c..0000000 --- a/scripts/filter_design/bode_compare_Ks_lpf_iir_q15_k.py +++ /dev/null @@ -1,42 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -def bode_mag_phase(Fs, K, n=4096): - """Return frequency, magnitude (dB), and phase (deg) for 1-pole IIR.""" - alpha = 2.0 ** (-K) - a = 1.0 - alpha - w = np.linspace(0, np.pi, n) - ejw = np.exp(-1j * w) - H = alpha / (1 - a * ejw) - f = (w / (2 * np.pi)) * Fs - mag_db = 20 * np.log10(np.abs(H) + 1e-20) - phase_deg = np.unwrap(np.angle(H)) * 180 / np.pi - return f, mag_db, phase_deg - -if __name__ == "__main__": - Fs = 15e6 - Ks = [10, 8, 6, 4] - - fig, (ax_mag, ax_phase) = plt.subplots(2, 1, sharex=True, figsize=(8, 6)) - - for K in Ks: - f, mag_db, phase_deg = bode_mag_phase(Fs, K, n=32768) - ax_mag.semilogx(f, mag_db, label=f"K={K}") - ax_phase.semilogx(f, phase_deg, label=f"K={K}") - - # ---- Styling ---- - f_max = 40e3 # 40 kHz - ax_mag.set_xlim(10, f_max) # start at 10 Hz for nicer log scaling - ax_mag.set_ylim(-60, 1) - ax_mag.set_title("Ideal Bode Response vs K") - ax_mag.set_ylabel("Magnitude [dB]") - ax_mag.grid(True, which='both') - ax_mag.legend() - - ax_phase.set_xlabel("Frequency [Hz]") - ax_phase.set_ylabel("Phase [deg]") - ax_phase.grid(True, which='both') - ax_phase.set_xlim(10, f_max) - - plt.tight_layout() - plt.show() \ No newline at end of file diff --git a/scripts/gen_sin_lut.py b/scripts/gen_sin_lut.py deleted file mode 100644 index 2c5fdd9..0000000 --- a/scripts/gen_sin_lut.py +++ /dev/null @@ -1,21 +0,0 @@ -import math - -# for i in range(0, 64, 4): -# for j in range(4): -# val = math.sin((i+j) * math.pi/256) -# val = int(val*256*1.4) -# print(f"6'd{i+j}: dout=8'd{val}; ", end='') -# print('') - - -N = 64 # quarter-wave samples -AMP = 255 # 8-bit max -for i in range(0, N, 4): - line = [] - for j in range(4): - k = i + j - theta = k * math.pi / (2*N) # 0 .. (π/2)*(N-1)/N ; never hits 1.0 - val = int(math.floor(AMP * math.sin(theta) + 0.5)) # rounded, stays <=254 - if val > 255: val = 255 - line.append(f"6'd{k}: dout = 8'd{val};") - print(' '.join(line)) \ No newline at end of file diff --git a/scripts/hex_to_coe.py b/scripts/hex_to_coe.py deleted file mode 100755 index a6c4e63..0000000 --- a/scripts/hex_to_coe.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env python3 -"""Convert a simple .hex image to Xilinx .coe format. - -Supported input: -- One or more hex tokens per line (e.g. "37" or "0x37") -- Optional comments after '#' or '//' - -By default, each token is written as one .coe entry (8-bit style memory init). -Use --word-bytes > 1 to pack byte tokens into wider words. -""" - -from __future__ import annotations - -import argparse -from pathlib import Path - - -def parse_tokens(path: Path) -> list[int]: - values: list[int] = [] - for raw in path.read_text().splitlines(): - line = raw.split("//", 1)[0].split("#", 1)[0].strip() - if not line: - continue - for token in line.replace(",", " ").split(): - token = token.strip() - if not token: - continue - if token.lower().startswith("0x"): - token = token[2:] - values.append(int(token, 16)) - return values - - -def pack_words( - byte_values: list[int], word_bytes: int, little_endian: bool -) -> tuple[list[int], int]: - if word_bytes <= 0: - raise ValueError("word_bytes must be >= 1") - if word_bytes == 1: - return byte_values[:], 2 - - words: list[int] = [] - width = word_bytes * 2 - for i in range(0, len(byte_values), word_bytes): - chunk = byte_values[i : i + word_bytes] - if len(chunk) < word_bytes: - chunk = chunk + [0] * (word_bytes - len(chunk)) - - word = 0 - if little_endian: - for b_idx, b in enumerate(chunk): - word |= (b & 0xFF) << (8 * b_idx) - else: - for b in chunk: - word = (word << 8) | (b & 0xFF) - words.append(word) - - return words, width - - -def main() -> None: - parser = argparse.ArgumentParser(description="Convert .hex to Xilinx .coe") - parser.add_argument("input_hex", type=Path, help="Input .hex file") - parser.add_argument("output_coe", type=Path, help="Output .coe file") - parser.add_argument( - "--word-bytes", - type=int, - default=1, - help="Bytes per output word (default: 1)", - ) - parser.add_argument( - "--little-endian", - action="store_true", - help="Pack bytes little-endian when --word-bytes > 1 (default)", - ) - parser.add_argument( - "--big-endian", - action="store_true", - help="Pack bytes big-endian when --word-bytes > 1", - ) - parser.add_argument( - "--radix", - type=int, - default=16, - choices=[2, 10, 16], - help="COE radix (default: 16)", - ) - parser.add_argument( - "--depth", - type=int, - default=0, - help="Optional output depth (pads with zeros up to this many words)", - ) - args = parser.parse_args() - - if args.little_endian and args.big_endian: - raise SystemExit("Choose only one of --little-endian or --big-endian") - - little_endian = True - if args.big_endian: - little_endian = False - - byte_values = parse_tokens(args.input_hex) - words, hex_digits = pack_words(byte_values, args.word_bytes, little_endian) - - if args.depth > 0 and args.depth < len(words): - raise SystemExit( - f"Requested --depth={args.depth} but image has {len(words)} words" - ) - if args.depth > len(words): - words.extend([0] * (args.depth - len(words))) - - if args.radix == 16: - data = [f"{w:0{hex_digits}X}" for w in words] - elif args.radix == 10: - data = [str(w) for w in words] - else: - width_bits = args.word_bytes * 8 - data = [f"{w:0{width_bits}b}" for w in words] - - out_lines = [ - f"memory_initialization_radix={args.radix};", - "memory_initialization_vector=", - ] - if data: - out_lines.extend( - [f"{v}," for v in data[:-1]] + [f"{data[-1]};"] - ) - else: - out_lines.append("0;") - - args.output_coe.write_text("\n".join(out_lines) + "\n") - - -if __name__ == "__main__": - main() diff --git a/scripts/hex_to_mif.py b/scripts/hex_to_mif.py deleted file mode 100755 index 6f17037..0000000 --- a/scripts/hex_to_mif.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python3 -"""Convert a simple .hex image to a plain .mif-style binary file. - -Default output format is 32-bit words: -- one binary word per line -- no header -""" - -from __future__ import annotations - -import argparse -from pathlib import Path - - -def parse_tokens(path: Path) -> list[int]: - values: list[int] = [] - for raw in path.read_text().splitlines(): - line = raw.split("//", 1)[0].split("#", 1)[0].strip() - if not line: - continue - for token in line.replace(",", " ").split(): - if token.lower().startswith("0x"): - token = token[2:] - values.append(int(token, 16)) - return values - - -def pack_words( - byte_values: list[int], word_bytes: int, little_endian: bool -) -> list[int]: - if word_bytes <= 0: - raise ValueError("word_bytes must be >= 1") - if word_bytes == 1: - return byte_values[:] - - words: list[int] = [] - for i in range(0, len(byte_values), word_bytes): - chunk = byte_values[i : i + word_bytes] - if len(chunk) < word_bytes: - chunk = chunk + [0] * (word_bytes - len(chunk)) - - word = 0 - if little_endian: - for b_idx, b in enumerate(chunk): - word |= (b & 0xFF) << (8 * b_idx) - else: - for b in chunk: - word = (word << 8) | (b & 0xFF) - words.append(word) - return words - - -def main() -> None: - parser = argparse.ArgumentParser(description="Convert .hex to plain .mif") - parser.add_argument("input_hex", type=Path, help="Input .hex file") - parser.add_argument("output_mif", type=Path, help="Output .mif file") - parser.add_argument( - "--word-bytes", - type=int, - default=4, - help="Bytes per output word (default: 4)", - ) - parser.add_argument( - "--little-endian", - action="store_true", - help="Pack bytes little-endian when --word-bytes > 1 (default)", - ) - parser.add_argument( - "--big-endian", - action="store_true", - help="Pack bytes big-endian when --word-bytes > 1", - ) - parser.add_argument( - "--depth", - type=int, - default=0, - help="Optional output depth (pads with zeros up to this many words)", - ) - args = parser.parse_args() - - if args.little_endian and args.big_endian: - raise SystemExit("Choose only one of --little-endian or --big-endian") - - little_endian = True - if args.big_endian: - little_endian = False - - words = pack_words(parse_tokens(args.input_hex), args.word_bytes, little_endian) - width_bits = args.word_bytes * 8 - max_word = (1 << width_bits) - 1 - - if args.depth > 0 and args.depth < len(words): - raise SystemExit( - f"Requested --depth={args.depth} but image has {len(words)} words" - ) - if args.depth > len(words): - words.extend([0] * (args.depth - len(words))) - - lines = [f"{(w & max_word):0{width_bits}b}" for w in words] - args.output_mif.write_text("\n".join(lines) + ("\n" if lines else "")) - - -if __name__ == "__main__": - main() diff --git a/scripts/planahead.sh b/scripts/planahead.sh deleted file mode 100755 index 16c4dd4..0000000 --- a/scripts/planahead.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -cd build -. /opt/Xilinx/14.7/ISE_DS/settings64.sh -Xephyr :1 -screen 1600x900 & -DISPLAY=:1 planAhead -mode batch -source ../scripts/planahead.tcl \ No newline at end of file diff --git a/scripts/planahead.tcl b/scripts/planahead.tcl deleted file mode 100644 index 3d50055..0000000 --- a/scripts/planahead.tcl +++ /dev/null @@ -1,8 +0,0 @@ -create_project project_1 tmpplanahead -part xc6slx9tqg144-2 -force -set_property design_mode GateLvl [current_fileset] -add_files -norecurse ../out/synth/synth.ngc -import_files -force -norecurse -import_files -fileset constrs_1 -force -norecurse ../boards/mimas_v1/constraints.ucf -import_as_run -run impl_1 -twx ../out/synth/timing.twx ../out/synth/synth.ncd -open_run impl_1 -start_gui \ No newline at end of file diff --git a/sim/overrides/clk_gen.v b/sim/overrides/clk_gen.v deleted file mode 100644 index 3087fc4..0000000 --- a/sim/overrides/clk_gen.v +++ /dev/null @@ -1,15 +0,0 @@ -`timescale 1ns/1ps - -// ============================================================================= -// Clock generator/PLL -// Simple direct generation for simulation purposes -// ============================================================================= -module clk_gen( - input wire clk_in, - output wire clk_out_15 -); - reg clk_15; - initial clk_15 <= 1'b0; - always #6.667 clk_15 <= !clk_15; - assign clk_out_15 = clk_15; -endmodule diff --git a/sim/overrides/jtag_if.v b/sim/overrides/jtag_if.v deleted file mode 100644 index 443dcfd..0000000 --- a/sim/overrides/jtag_if.v +++ /dev/null @@ -1,196 +0,0 @@ -`timescale 1ns/1ps - -// ============================================================================= -// JTAG interface (simulation override) -// Behavioral SVF player for simple USER-chain simulation. -// -// Supported SVF commands (line-oriented, uppercase recommended): -// - SIR TDI (); -// - SDR TDI (); -// - RUNTEST TCK; -// - STATE RESET; -// - STATE IDLE; -// Other lines are ignored. -// ============================================================================= -module jtag_if #( - parameter integer chain = 1, - parameter [8*256-1:0] SVF_FILE = "write_jtag.svf", - parameter integer TCK_HALF_PERIOD_NS = 50, - parameter [31:0] USER_IR_OPCODE = 32'h00000002 -)( - input wire i_tdo, - output reg o_tck, - output reg o_tdi, - output reg o_drck, - output reg o_capture, - output reg o_shift, - output reg o_update, - output reg o_runtest, - output reg o_reset, - output reg o_sel -); - integer fd; - integer got; - integer nbits; - integer cycles; - integer i; - integer line_no; - integer scan_bits; - - reg [8*1024-1:0] line; - reg [8*32-1:0] cmd; - reg [8*32-1:0] arg1; - reg [8*256-1:0] svf_file_path; - reg [4095:0] scan_data; - reg [31:0] current_ir; - reg selected; - - // Keep linters quiet: TDO is not consumed by this simple player. - wire _unused_tdo; - assign _unused_tdo = i_tdo; - - task pulse_tck; - begin - #TCK_HALF_PERIOD_NS o_tck = 1'b1; - #TCK_HALF_PERIOD_NS o_tck = 1'b0; - end - endtask - - task pulse_drck_shift; - input bit_in; - begin - o_tdi = bit_in; - o_shift = 1'b1; - #TCK_HALF_PERIOD_NS begin - o_tck = 1'b1; - o_drck = 1'b1; - end - #TCK_HALF_PERIOD_NS begin - o_tck = 1'b0; - o_drck = 1'b0; - end - end - endtask - - task pulse_capture; - begin - o_capture = 1'b1; - #TCK_HALF_PERIOD_NS begin - o_tck = 1'b1; - o_drck = 1'b1; - end - #TCK_HALF_PERIOD_NS begin - o_tck = 1'b0; - o_drck = 1'b0; - o_capture = 1'b0; - end - end - endtask - - task pulse_update; - begin - o_shift = 1'b0; - #TCK_HALF_PERIOD_NS o_update = 1'b1; - #TCK_HALF_PERIOD_NS o_update = 1'b0; - end - endtask - - initial begin - // Default output levels - o_tck = 1'b0; - o_tdi = 1'b0; - o_drck = 1'b0; - o_capture = 1'b0; - o_shift = 1'b0; - o_update = 1'b0; - o_runtest = 1'b0; - o_reset = 1'b0; - o_sel = 1'b0; - selected = 1'b0; - current_ir = 32'h0; - line_no = 0; - svf_file_path = SVF_FILE; - - // Deterministic startup reset pulse before consuming SVF. - o_reset = 1'b1; - #TCK_HALF_PERIOD_NS o_tck = 1'b1; - #TCK_HALF_PERIOD_NS o_tck = 1'b0; - #TCK_HALF_PERIOD_NS o_tck = 1'b1; - #TCK_HALF_PERIOD_NS o_tck = 1'b0; - o_reset = 1'b0; - - fd = $fopen(svf_file_path, "r"); - if (fd == 0) begin - $display("jtag_if(sim): could not open SVF file '%0s'", svf_file_path); - end else begin - while (!$feof(fd)) begin - line = {8*1024{1'b0}}; - got = $fgets(line, fd); - line_no = line_no + 1; - if (got > 0) begin - cmd = {8*32{1'b0}}; - arg1 = {8*32{1'b0}}; - scan_data = {4096{1'b0}}; - nbits = 0; - cycles = 0; - - got = $sscanf(line, "%s", cmd); - if (got < 1) begin - // Empty line - end else if (cmd == "!") begin - // Comment line - end else if (cmd == "SIR") begin - got = $sscanf(line, "SIR %d TDI (%h);", nbits, scan_data); - if (got == 2) begin - current_ir = scan_data[31:0]; - selected = (current_ir == USER_IR_OPCODE); - o_sel = selected; - - // Emit TCK pulses for IR shift activity. - scan_bits = nbits; - if (scan_bits > 4096) scan_bits = 4096; - for (i = 0; i < scan_bits; i = i + 1) begin - o_tdi = scan_data[i]; - pulse_tck; - end - end - end else if (cmd == "SDR") begin - got = $sscanf(line, "SDR %d TDI (%h);", nbits, scan_data); - if (got == 2) begin - if (selected) begin - pulse_capture; - end - scan_bits = nbits; - if (scan_bits > 4096) scan_bits = 4096; - for (i = 0; i < scan_bits; i = i + 1) begin - pulse_drck_shift(scan_data[i]); - end - if (selected) begin - pulse_update; - end - end - end else if (cmd == "RUNTEST") begin - got = $sscanf(line, "RUNTEST %d TCK;", cycles); - if (got == 1) begin - o_runtest = 1'b1; - for (i = 0; i < cycles; i = i + 1) - pulse_tck; - o_runtest = 1'b0; - end - end else if (cmd == "STATE") begin - got = $sscanf(line, "STATE %s", arg1); - if (got == 1) begin - if (arg1 == "RESET;") begin - o_reset = 1'b1; - #TCK_HALF_PERIOD_NS o_reset = 1'b0; - selected = 1'b0; - o_sel = 1'b0; - end - end - end - end - end - $fclose(fd); - end - end -endmodule diff --git a/sim/tb/tb_cdc_strobe_data.v b/sim/tb/tb_cdc_strobe_data.v deleted file mode 100644 index b203937..0000000 --- a/sim/tb/tb_cdc_strobe_data.v +++ /dev/null @@ -1,124 +0,0 @@ -`timescale 1ns/1ps - -module tb_cdc_strobe_data; - - localparam integer WIDTH = 16; - localparam integer NUM_TX = 5; - - // Source domain - reg s_clk; - reg s_rst; - reg s_pulse; - reg [WIDTH-1:0] s_data; - wire s_busy; - wire s_accepted; - - // Destination domain - reg d_clk; - reg d_rst; - wire d_pulse; - wire [WIDTH-1:0] d_data; - - reg [WIDTH-1:0] exp_data [0:NUM_TX-1]; - integer rx_idx; - integer tx_idx; - - cdc_strobe_data #( - .WIDTH(WIDTH), - .STABLE_SAMPLES(2) - ) dut ( - .s_clk(s_clk), - .s_rst(s_rst), - .s_pulse(s_pulse), - .s_data(s_data), - .s_busy(s_busy), - .s_accepted(s_accepted), - .d_clk(d_clk), - .d_rst(d_rst), - .d_pulse(d_pulse), - .d_data(d_data) - ); - - initial s_clk = 1'b0; - always #625 s_clk = ~s_clk; // 800 kHz - - initial d_clk = 1'b0; - always #33.333 d_clk = ~d_clk; // 15 MHz (asynchronous to s_clk) - - task send_word; - input [WIDTH-1:0] value; - begin - @(posedge s_clk); - while (s_busy) - @(posedge s_clk); - - s_data <= value; - s_pulse <= 1'b1; - @(posedge s_clk); - - if (!s_accepted) begin - $display("[%0t] ERROR: expected s_accepted for value 0x%0h", $time, value); - $fatal(1); - end - - s_pulse <= 1'b0; - s_data <= {WIDTH{1'b0}}; - end - endtask - - always @(posedge d_clk) begin - if (!d_rst && d_pulse) begin - if (rx_idx >= NUM_TX) begin - $display("[%0t] ERROR: unexpected extra d_pulse with data=0x%0h", $time, d_data); - $fatal(1); - end - - if (d_data !== exp_data[rx_idx]) begin - $display("[%0t] ERROR: rx[%0d] expected 0x%0h, got 0x%0h", - $time, rx_idx, exp_data[rx_idx], d_data); - $fatal(1); - end - - $display("[%0t] INFO: rx[%0d] = 0x%0h", $time, rx_idx, d_data); - rx_idx <= rx_idx + 1; - end - end - - initial begin - $dumpfile("out.vcd"); - $dumpvars(0, tb_cdc_strobe_data); - - s_rst = 1'b1; - d_rst = 1'b1; - s_pulse = 1'b0; - s_data = {WIDTH{1'b0}}; - rx_idx = 0; - tx_idx = 0; - - exp_data[0] = 16'h1234; - exp_data[1] = 16'h00A5; - exp_data[2] = 16'hBEEF; - exp_data[3] = 16'h5AA5; - exp_data[4] = 16'hCAFE; - - repeat (4) @(posedge s_clk); - s_rst = 1'b0; - repeat (3) @(posedge d_clk); - d_rst = 1'b0; - - for (tx_idx = 0; tx_idx < NUM_TX; tx_idx = tx_idx + 1) - send_word(exp_data[tx_idx]); - - wait (rx_idx == NUM_TX); - $display("[%0t] PASS: received %0d/%0d transfers correctly", $time, rx_idx, NUM_TX); - #20; - $finish; - end - - initial begin - #100000000; - $display("[%0t] ERROR: timeout waiting for transfers", $time); - $fatal(1); - end - -endmodule diff --git a/sim/tb/tb_jtag_wb_bridge.v b/sim/tb/tb_jtag_wb_bridge.v deleted file mode 100644 index 62a4a51..0000000 --- a/sim/tb/tb_jtag_wb_bridge.v +++ /dev/null @@ -1,334 +0,0 @@ -`timescale 1ns/1ps - -module tb_jtag_wb_bridge; - - localparam [7:0] OP_NOP = 8'h00; - localparam [7:0] OP_RESET_ON = 8'h10; - localparam [7:0] OP_RESET_OFF = 8'h11; - localparam [7:0] OP_WRITE8 = 8'h20; - localparam [7:0] OP_READ8 = 8'h21; - localparam [7:0] OP_PING = 8'h30; - - reg i_clk; - reg i_rst; - - wire [31:0] o_wb_adr; - wire [31:0] o_wb_dat; - wire [3:0] o_wb_sel; - wire o_wb_we; - wire o_wb_cyc; - wire o_wb_stb; - reg [31:0] i_wb_rdt; - reg i_wb_ack; - wire o_cmd_reset; - - reg [7:0] mem [0:1023]; - reg wb_req_pending; - reg [31:0] wb_addr_latched; - reg [31:0] wb_dat_latched; - reg [3:0] wb_sel_latched; - reg wb_we_latched; - integer wb_base; - - integer idx; - integer req_accept_count; - - reg saw_write_lane3; - reg saw_read_lane3; - reg saw_cmd_reset_high; - reg [47:0] flush_rx; - - jtag_wb_bridge #( - .chain(1), - .byte_aligned(0) - ) dut ( - .i_clk(i_clk), - .i_rst(i_rst), - .o_wb_adr(o_wb_adr), - .o_wb_dat(o_wb_dat), - .o_wb_sel(o_wb_sel), - .o_wb_we(o_wb_we), - .o_wb_cyc(o_wb_cyc), - .o_wb_stb(o_wb_stb), - .i_wb_rdt(i_wb_rdt), - .i_wb_ack(i_wb_ack), - .o_cmd_reset(o_cmd_reset) - ); - - function [47:0] make_cmd; - input [7:0] op; - input [31:0] addr; - input [7:0] data; - begin - make_cmd = {op, addr, data}; - end - endfunction - - task expect_resp; - input [47:0] resp; - input [7:0] exp_data; - input [7:0] exp_last_op; - begin - if (resp[23:16] !== exp_data) begin - $display("[%0t] ERROR: data exp=0x%0h got=0x%0h", $time, exp_data, resp[23:16]); - $fatal(1); - end - if (resp[7:0] !== exp_last_op) begin - $display("[%0t] ERROR: last_op exp=0x%0h got=0x%0h", $time, exp_last_op, resp[7:0]); - $fatal(1); - end - if (resp[37] !== 1'b1) begin - $display("[%0t] ERROR: status.resp_valid bit not set in response 0x%012h", $time, resp); - $fatal(1); - end - end - endtask - - task send_cmd; - input [47:0] cmd_word; - integer tries; - integer start_accepts; - reg [47:0] dummy_rx; - begin - start_accepts = req_accept_count; - for (tries = 0; tries < 8; tries = tries + 1) begin - do_xfer(cmd_word, dummy_rx); - if (req_accept_count > start_accepts) - tries = 8; - end - if (req_accept_count <= start_accepts) begin - $display("[%0t] ERROR: command 0x%0h was never accepted", $time, cmd_word[47:40]); - $fatal(1); - end - end - endtask - - task expect_eventual_response; - input [7:0] exp_data; - input [7:0] exp_last_op; - integer tries; - reg [47:0] rx_word; - reg found; - begin - found = 1'b0; - for (tries = 0; tries < 8; tries = tries + 1) begin - do_xfer(make_cmd(OP_NOP, 32'h0000_0000, 8'h00), rx_word); - if (rx_word[7:0] == exp_last_op) begin - expect_resp(rx_word, exp_data, exp_last_op); - found = 1'b1; - tries = 8; - end - end - if (!found) begin - $display("[%0t] ERROR: did not observe response for last_op=0x%0h", $time, exp_last_op); - $fatal(1); - end - end - endtask - - task do_xfer; - input [47:0] tx_word; - output [47:0] rx_word; - begin - dut.u_jtag.transceive48(tx_word, rx_word); - repeat (400) @(posedge i_clk); - end - endtask - - initial i_clk = 1'b0; - always #10 i_clk = ~i_clk; // 50 MHz - - always @(posedge i_clk) begin - if (i_rst) begin - i_wb_ack <= 1'b0; - i_wb_rdt <= 32'h0; - wb_req_pending <= 1'b0; - wb_addr_latched <= 32'h0; - wb_dat_latched <= 32'h0; - wb_sel_latched <= 4'h0; - wb_we_latched <= 1'b0; - end else begin - if (o_cmd_reset) - saw_cmd_reset_high <= 1'b1; - - i_wb_ack <= 1'b0; - - if (wb_req_pending) begin - wb_base = {wb_addr_latched[31:2], 2'b00}; - - if (wb_we_latched) begin - if (wb_sel_latched[0]) mem[wb_base + 0] <= wb_dat_latched[7:0]; - if (wb_sel_latched[1]) mem[wb_base + 1] <= wb_dat_latched[15:8]; - if (wb_sel_latched[2]) mem[wb_base + 2] <= wb_dat_latched[23:16]; - if (wb_sel_latched[3]) mem[wb_base + 3] <= wb_dat_latched[31:24]; - end - - i_wb_rdt <= {mem[wb_base + 3], mem[wb_base + 2], mem[wb_base + 1], mem[wb_base + 0]}; - i_wb_ack <= 1'b1; - wb_req_pending <= 1'b0; - end else if (o_wb_cyc && o_wb_stb) begin - wb_addr_latched <= o_wb_adr; - wb_dat_latched <= o_wb_dat; - wb_sel_latched <= o_wb_sel; - wb_we_latched <= o_wb_we; - wb_req_pending <= 1'b1; - - if (o_wb_we && (o_wb_adr == 32'h0000_0013) && (o_wb_sel == 4'b1000) && (o_wb_dat == 32'h5A00_0000)) - saw_write_lane3 <= 1'b1; - if (!o_wb_we && (o_wb_adr == 32'h0000_0013) && (o_wb_sel == 4'b1000)) - saw_read_lane3 <= 1'b1; - end - end - end - - always @(posedge dut.jtag_tck) begin - if (i_rst) - req_accept_count <= 0; - else if (dut.a_req_accepted) - req_accept_count <= req_accept_count + 1; - end - - initial begin - $dumpfile("out.vcd"); - $dumpvars(0, tb_jtag_wb_bridge); - - i_rst = 1'b1; - i_wb_rdt = 32'h0; - i_wb_ack = 1'b0; - wb_req_pending = 1'b0; - wb_addr_latched = 32'h0; - wb_dat_latched = 32'h0; - wb_sel_latched = 4'h0; - wb_we_latched = 1'b0; - saw_write_lane3 = 1'b0; - saw_read_lane3 = 1'b0; - saw_cmd_reset_high = 1'b0; - req_accept_count = 0; - - for (idx = 0; idx < 1024; idx = idx + 1) - mem[idx] = idx[7:0]; - - repeat (10) @(posedge i_clk); - i_rst = 1'b0; - - repeat (10) @(posedge i_clk); - - send_cmd(make_cmd(OP_PING, 32'h0000_0000, 8'h00)); - expect_eventual_response(8'hA5, OP_PING); - - send_cmd(make_cmd(OP_WRITE8, 32'h0000_0013, 8'h5A)); - send_cmd(make_cmd(OP_READ8, 32'h0000_0013, 8'h00)); - send_cmd(make_cmd(OP_RESET_ON, 32'h0000_0000, 8'h00)); - send_cmd(make_cmd(OP_RESET_OFF, 32'h0000_0000, 8'h00)); - - repeat (6) - do_xfer(make_cmd(OP_NOP, 32'h0000_0000, 8'h00), flush_rx); - - if (!saw_write_lane3) begin - $display("[%0t] ERROR: expected WRITE8 lane-3 WB access not observed", $time); - $fatal(1); - end - if (!saw_read_lane3) begin - $display("[%0t] ERROR: expected READ8 lane-3 WB access not observed", $time); - $fatal(1); - end - if (!saw_cmd_reset_high) begin - $display("[%0t] ERROR: expected o_cmd_reset to go high at least once", $time); - $fatal(1); - end - - repeat (50) @(posedge i_clk); - if (o_cmd_reset !== 1'b0) begin - $display("[%0t] ERROR: expected o_cmd_reset low after RESET_OFF, got %0b", $time, o_cmd_reset); - $fatal(1); - end - - $display("[%0t] PASS: jtag_wb_bridge basic command/response path verified", $time); - #100; - $finish; - end - - initial begin - #5_000_000; - $display("[%0t] ERROR: timeout", $time); - $fatal(1); - end - -endmodule - -module jtag_if #( - parameter integer chain = 1 -)( - input wire i_tdo, - output reg o_tck, - output reg o_tdi, - output reg o_drck, - output reg o_capture, - output reg o_shift, - output reg o_update, - output reg o_runtest, - output reg o_reset, - output reg o_sel -); - integer k; - - // Quiet unused parameter warning - wire _unused_chain; - assign _unused_chain = chain[0]; - - task pulse_tck; - begin - #40 o_tck = 1'b1; - #40 o_tck = 1'b0; - end - endtask - - task transceive48; - input [47:0] tx_word; - output [47:0] rx_word; - begin - rx_word = 48'h0; - - // Let CDC response path advance in the TCK domain before CAPTURE. - for (k = 0; k < 32; k = k + 1) - pulse_tck; - - // CAPTURE-DR - o_capture = 1'b1; - pulse_tck; - o_capture = 1'b0; - - // SHIFT-DR (read previous response while shifting next command in) - o_shift = 1'b1; - for (k = 0; k < 48; k = k + 1) begin - o_tdi = tx_word[k]; - rx_word[k] = i_tdo; - o_drck = 1'b1; - pulse_tck; - o_drck = 1'b0; - end - o_shift = 1'b0; - - // UPDATE-DR (request strobe sampled by TCK) - o_update = 1'b1; - pulse_tck; - o_update = 1'b0; - - // Provide a few extra clocks after UPDATE. - for (k = 0; k < 8; k = k + 1) - pulse_tck; - end - endtask - - initial begin - o_tck = 1'b0; - o_tdi = 1'b0; - o_drck = 1'b0; - o_capture = 1'b0; - o_shift = 1'b0; - o_update = 1'b0; - o_runtest = 1'b0; - o_reset = 1'b0; - o_sel = 1'b1; - end -endmodule diff --git a/sim/tb/tb_mul_const.v b/sim/tb/tb_mul_const.v deleted file mode 100644 index 2f9028b..0000000 --- a/sim/tb/tb_mul_const.v +++ /dev/null @@ -1,72 +0,0 @@ -`timescale 1ns/1ps - -module tb_mul_const(); - - // ------------------------------------------------------------------------- - // Parameters - // ------------------------------------------------------------------------- - localparam integer W = 16; - localparam integer C = 16'sh0B3B; // alpha_q15 ≈ 0.08774 - localparam signed [W-1:0] C_S = C[W-1:0]; - - // ------------------------------------------------------------------------- - // DUT I/O - // ------------------------------------------------------------------------- - reg signed [W-1:0] x; - wire signed [(2*W)-1:0] y; - - // Instantiate DUT - mul_const_shiftadd #( - .W(W), - .C(C) - ) dut ( - .x(x), - .y(y) - ); - - // ------------------------------------------------------------------------- - // Reference and verification - // ------------------------------------------------------------------------- - reg signed [(2*W)-1:0] expected; - integer i; - integer errors; - - initial begin - $display("------------------------------------------------------"); - $display(" Testbench: mul_const_shiftadd"); - $display(" W = %0d, C = %0d (0x%0h)", W, $signed(C_S), C_S); - $display("------------------------------------------------------"); - - errors = 0; - - // Exhaustively test all 16-bit signed values - for (i = -(1<<(W-1)); i < (1<<(W-1)); i = i + 1) begin - x = i; - #1; // let combinational logic settle - - expected = $signed(x) * $signed(C_S); - - if (y !== expected) begin - $display("FAIL: x=%6d (0x%04h) * C=%6d -> y=%10d (0x%08h), expected=%10d (0x%08h)", - $signed(x), x, $signed(C_S), - $signed(y), y, $signed(expected), expected); - errors = errors + 1; - // Uncomment next line if you want to stop on first mismatch - // $stop; - end - - // progress message every 4096 iterations - if (((i + (1<<(W-1))) % 4096) == 0) - $display("Progress: %5d / %5d values tested...", - i + (1<<(W-1)), (1< -#include -#include - -static constexpr uint8_t OP_NOP = 0x00; -static constexpr uint8_t OP_RESET_ON = 0x10; -static constexpr uint8_t OP_RESET_OFF = 0x11; -static constexpr uint8_t OP_WRITE8 = 0x20; -static constexpr uint8_t OP_READ8 = 0x21; -static constexpr uint8_t OP_WRITE32 = 0x22; -static constexpr uint8_t OP_READ32 = 0x23; -static constexpr uint8_t OP_PING = 0x30; -static constexpr uint8_t OP_CLEAR_FLAGS = 0x40; - -static void shift72(DigilentJtag &jtag, const uint8_t tx[9], uint8_t rx[9]) { - jtag.shiftData(tx, rx, 72); -} - -static void make_cmd(uint8_t out[9], uint8_t opcode, uint32_t addr, uint32_t data) { - out[0] = (uint8_t)data; - out[1] = (uint8_t)(data >> 8); - out[2] = (uint8_t)(data >> 16); - out[3] = (uint8_t)(data >> 24); - out[4] = (uint8_t)addr; - out[5] = (uint8_t)(addr >> 8); - out[6] = (uint8_t)(addr >> 16); - out[7] = (uint8_t)(addr >> 24); - out[8] = opcode; -} - -static uint32_t get_data32(const uint8_t rx[9]) { - return ((uint32_t)rx[2]) | - ((uint32_t)rx[3] << 8) | - ((uint32_t)rx[4] << 16) | - ((uint32_t)rx[5] << 24); -} - -static uint32_t do_cmd32(DigilentJtag& jtag, uint8_t opcode, uint32_t addr, uint32_t data){ - uint8_t tx[9], rx[9]; - make_cmd(tx, opcode, addr, data); - shift72(jtag, tx, rx); - for(int i=0; i<32; i++){ - make_cmd(tx, OP_NOP, 0, 0); - shift72(jtag, tx, rx); - if(rx[0] == opcode){ - return get_data32(rx); - } - } - printf("Could not do command\r\n"); - return 0; -} - -static inline void write8(DigilentJtag& jtag, uint32_t addr, uint8_t value) { - (void)do_cmd32(jtag, OP_WRITE8, addr, value); -} - -static inline uint8_t read8(DigilentJtag& jtag, uint32_t addr) { - return (uint8_t)do_cmd32(jtag, OP_READ8, addr, 0); -} - -static inline void write32(DigilentJtag& jtag, uint32_t addr, uint32_t value) { - (void)do_cmd32(jtag, OP_WRITE32, addr, value); -} - -static inline uint32_t read32(DigilentJtag& jtag, uint32_t addr) { - return do_cmd32(jtag, OP_READ32, addr, 0); -} - -int main(int argc, char** argv){ - ArgParser parser(argc > 0 ? argv[0] : "test"); - parser.addString("file", "", "File to write", true, "f"); - parser.addFlag("verify", "Verify", "v"); - - std::string parse_error; - if (!parser.parse(argc, argv, &parse_error)) { - if (parse_error == "help") { - std::printf("%s", parser.helpText().c_str()); - return 0; - } - std::printf("Argument error: %s\n\n", parse_error.c_str()); - std::printf("%s", parser.helpText().c_str()); - return -1; - } - - DigilentJtag jtag; - if(!jtag.open()){ - printf("Could not open programmer\r\n"); - return -1; - } - jtag.setChain(1); - - - do_cmd32(jtag, OP_CLEAR_FLAGS, 0, 0); - // Check for ping - if((do_cmd32(jtag, OP_PING, 0, 0) & 0xffu) != 0xa5u){ - printf("PING response was not right\r\n"); - jtag.close(); - return -1; - } - - const std::string file = parser.getString("file"); - FILE* f = fopen(file.c_str(), "rb"); - if(!f){ - printf("Could not open file\r\n"); - jtag.close(); - return -1; - } - - do_cmd32(jtag, OP_RESET_ON, 0, 0); - - int nr = 0; - int addr = 0; - do{ - uint32_t buf[32]; - nr = fread(buf, sizeof(uint32_t), 32, f); - for(int i=0; i 0); - - do_cmd32(jtag, OP_RESET_OFF, 0, 0); - - fclose(f); - jtag.close(); - return 0; -} diff --git a/xilinx_fusesoc.sh b/xilinx_fusesoc.sh new file mode 100755 index 0000000..0e9bfd4 --- /dev/null +++ b/xilinx_fusesoc.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +. /opt/Xilinx/14.7/ISE_DS/settings64.sh /opt/Xilinx/14.7/ISE_DS + +echo fusesoc "$@" +exec fusesoc "$@"