diff --git a/rtl/controller/src/controller.sv b/rtl/controller/src/controller.sv index 5bbd52c..c79ffa0 100644 --- a/rtl/controller/src/controller.sv +++ b/rtl/controller/src/controller.sv @@ -90,7 +90,6 @@ module control #( // Pending ACKs for config delivery logic cfg_wait_dac_ack; logic cfg_wait_adc_ack; - wire cfg_busy = cfg_wait_dac_ack || cfg_wait_adc_ack; // Event toggles cntrl -> DAC/ADC logic start_toggle; @@ -182,7 +181,7 @@ module control #( cfg_wait_adc_ack <= 1'b0; end - if (cfg_bus_valid && !busy && !cfg_busy) begin + if (cfg_bus_valid && !busy && !cfg_wait_dac_ack && !cfg_wait_adc_ack) begin cfg_bus <= cfg_bus_input; cfg_req_toggle_dac <= ~cfg_req_toggle_dac; @@ -192,7 +191,7 @@ module control #( cfg_wait_adc_ack <= 1; end - if (start && !busy && !cfg_busy) begin + if (start && !busy && !cfg_wait_dac_ack && !cfg_wait_adc_ack) begin start_toggle <= ~start_toggle; busy <= 1; end diff --git a/rtl/controller/tests/controller_tb.sv b/rtl/controller/tests/controller_tb.sv index 2beb3b8..56fb55b 100644 --- a/rtl/controller/tests/controller_tb.sv +++ b/rtl/controller/tests/controller_tb.sv @@ -5,31 +5,32 @@ module tb_control; localparam int unsigned DAC_DATA_WIDTH = 12; //------------------------------------------------------------ - // clocks + // Clocks / reset //------------------------------------------------------------ logic ctrl_clk; logic dac_clk_in; logic adc_clk_in; + logic rst_n; initial begin - ctrl_clk = 0; - forever #4 ctrl_clk = ~ctrl_clk; //125 MHz + ctrl_clk = 1'b0; + forever #(1 * 4.000) ctrl_clk = ~ctrl_clk; // 125 MHz end initial begin - dac_clk_in = 0; - forever #3.846 dac_clk_in = ~dac_clk_in; //~130 MHz + dac_clk_in = 1'b0; + forever #(1 * 3.846153846) dac_clk_in = ~dac_clk_in; // ~130 MHz end initial begin - adc_clk_in = 0; - forever #7.692 adc_clk_in = ~adc_clk_in; //~65 MHz + adc_clk_in = 1'b0; + forever #(1 * 7.692307692) adc_clk_in = ~adc_clk_in; // ~65 MHz end //------------------------------------------------------------ // DUT inputs //------------------------------------------------------------ - logic rst_n; + logic rst_soft; logic finish; @@ -42,19 +43,19 @@ module tb_control; //------------------------------------------------------------ // DUT outputs //------------------------------------------------------------ + logic busy; - logic [31:0] dac_pulse_width; - logic [31:0] dac_pulse_period; + logic [31:0] dac_pulse_width; + logic [31:0] dac_pulse_period; logic [DAC_DATA_WIDTH-1:0] dac_pulse_height; - logic [15:0] dac_pulse_num; + logic [15:0] dac_pulse_num; - logic [31:0] adc_pulse_period; - logic [15:0] adc_pulse_num; + logic [31:0] adc_pulse_period; + logic [15:0] adc_pulse_num; logic dac_start; logic adc_start; - logic dac_rst; logic adc_rst; @@ -65,232 +66,639 @@ module tb_control; control #( .DAC_DATA_WIDTH(DAC_DATA_WIDTH) ) dut ( - .ctrl_clk(ctrl_clk), - .dac_clk_in(dac_clk_in), - .adc_clk_in(adc_clk_in), + .ctrl_clk (ctrl_clk), + .dac_clk_in (dac_clk_in), + .adc_clk_in (adc_clk_in), - .rst_n(rst_n), - .rst_soft(rst_soft), + .rst_n (rst_n), + .rst_soft (rst_soft), - .finish(finish), + .finish (finish), - .cfg_bus_input(cfg_bus_input), - .cfg_bus_valid(cfg_bus_valid), + .cfg_bus_input (cfg_bus_input), + .cfg_bus_valid (cfg_bus_valid), - .start(start), + .start (start), - .busy(busy), + .busy (busy), - .dac_pulse_width(dac_pulse_width), - .dac_pulse_period(dac_pulse_period), - .dac_pulse_height(dac_pulse_height), - .dac_pulse_num(dac_pulse_num), + .dac_pulse_width (dac_pulse_width), + .dac_pulse_period (dac_pulse_period), + .dac_pulse_height (dac_pulse_height), + .dac_pulse_num (dac_pulse_num), - .adc_pulse_period(adc_pulse_period), - .adc_pulse_num(adc_pulse_num), + .adc_pulse_period (adc_pulse_period), + .adc_pulse_num (adc_pulse_num), - .dac_start(dac_start), - .adc_start(adc_start), - .dac_rst(dac_rst), - .adc_rst(adc_rst) + .dac_start (dac_start), + .adc_start (adc_start), + .dac_rst (dac_rst), + .adc_rst (adc_rst) ); //------------------------------------------------------------ - // pulse counters + // pulse counters and monitors for testing //------------------------------------------------------------ - int dac_start_count; - int adc_start_count; int dac_rst_count; int adc_rst_count; + int dac_start_count; + int adc_start_count; always_ff @(posedge dac_clk_in) begin if (!rst_n) begin - dac_start_count <= 0; dac_rst_count <= 0; + dac_start_count <= 0; end else begin - if (dac_start) dac_start_count++; - if (dac_rst) dac_rst_count++; + if (dac_rst) + dac_rst_count <= dac_rst_count + 1; + + if (dac_start) + dac_start_count <= dac_start_count + 1; end end always_ff @(posedge adc_clk_in) begin if (!rst_n) begin - adc_start_count <= 0; adc_rst_count <= 0; + adc_start_count <= 0; end else begin - if (adc_start) adc_start_count++; - if (adc_rst) adc_rst_count++; + if (adc_rst) + adc_rst_count <= adc_rst_count + 1; + + if (adc_start) + adc_start_count <= adc_start_count + 1; end end //------------------------------------------------------------ - // tasks + // helpers //------------------------------------------------------------ - task automatic send_cfg( + task automatic send_cmd(input logic [7:0] cmd); + begin + @(negedge ctrl_clk); + + case (cmd) + + 8'h0F: begin + rst_soft <= 1'b1; + + @(posedge ctrl_clk); + + rst_soft <= 1'b0; + end + + 8'hF0: begin + start <= 1'b1; + + @(posedge ctrl_clk); + + start <= 1'b0; + end + + default: + $fatal(1, "Unsupported command %h", cmd); + + endcase + end + endtask + + task automatic send_set_data( input logic [31:0] pulse_width, input logic [31:0] pulse_period, input logic [15:0] pulse_num, - input logic [15:0] pulse_height, - input logic [31:0] adc_period + input logic [15:0] pulse_height_raw, + input logic [31:0] pulse_period_adc ); - begin + logic [127:0] payload; + begin - cfg_bus_input = { - adc_period, - pulse_height, - pulse_num, - pulse_period, - pulse_width - }; + payload = { + pulse_period_adc, + pulse_height_raw, + pulse_num, + pulse_period, + pulse_width + }; - @(posedge ctrl_clk); - cfg_bus_valid <= 1; + @(negedge ctrl_clk); - @(posedge ctrl_clk); - cfg_bus_valid <= 0; + cfg_bus_input <= payload; + cfg_bus_valid <= 1'b1; - end - endtask + @(posedge ctrl_clk); - task automatic send_start; - begin - @(posedge ctrl_clk); - start <= 1; - - @(posedge ctrl_clk); - start <= 0; - end - endtask - - task automatic send_soft_reset; - begin - @(posedge ctrl_clk); - rst_soft <= 1; - - @(posedge ctrl_clk); - rst_soft <= 0; - end + cfg_bus_valid <= 1'b0; + cfg_bus_input <= '0; + end endtask task automatic pulse_finish; - begin - @(posedge adc_clk_in); - finish <= 1; + begin + @(posedge adc_clk_in); + finish <= 1'b1; - @(posedge adc_clk_in); - finish <= 0; - end + @(posedge adc_clk_in); + finish <= 1'b0; + end endtask //------------------------------------------------------------ - // TEST + // waiters //------------------------------------------------------------ + task automatic wait_dac_rst_count(input int expected, input int max_cycles = 100); + int i; + begin + for (i = 0; i < max_cycles; i++) begin + @(posedge dac_clk_in); + + if (dac_rst_count >= expected) + return; + end + + $fatal(1, + "Timeout waiting for dac_rst_count >= %0d, current=%0d", + expected, + dac_rst_count + ); + end + endtask + + task automatic wait_adc_rst_count(input int expected, input int max_cycles = 100); + int i; + begin + for (i = 0; i < max_cycles; i++) begin + @(posedge adc_clk_in); + + if (adc_rst_count >= expected) + return; + end + + $fatal(1, + "Timeout waiting for adc_rst_count >= %0d, current=%0d", + expected, + adc_rst_count + ); + end + endtask + + task automatic wait_dac_start_count(input int expected, input int max_cycles = 100); + int i; + begin + for (i = 0; i < max_cycles; i++) begin + @(posedge dac_clk_in); + + if (dac_start_count >= expected) + return; + end + + $fatal(1, + "Timeout waiting for dac_start_count >= %0d, current=%0d", + expected, + dac_start_count + ); + end + endtask + + task automatic wait_adc_start_count(input int expected, input int max_cycles = 100); + int i; + begin + for (i = 0; i < max_cycles; i++) begin + @(posedge adc_clk_in); + + if (adc_start_count >= expected) + return; + end + + $fatal(1, + "Timeout waiting for adc_start_count >= %0d, current=%0d", + expected, + adc_start_count + ); + end + endtask + + task automatic wait_cfg_applied( + input logic [31:0] exp_pulse_width, + input logic [31:0] exp_pulse_period, + input logic [15:0] exp_pulse_num, + input logic [15:0] exp_pulse_height_raw, + input logic [31:0] exp_pulse_period_adc, + input int max_cycles = 200 + ); + logic [DAC_DATA_WIDTH-1:0] exp_dac_height; + int i; + + begin + + exp_dac_height = exp_pulse_height_raw[DAC_DATA_WIDTH-1:0]; + + for (i = 0; i < max_cycles; i++) begin + @(posedge ctrl_clk); + + if ((dac_pulse_width === exp_pulse_width) && + (dac_pulse_period === exp_pulse_period) && + (dac_pulse_num === exp_pulse_num) && + (dac_pulse_height === exp_dac_height) && + (adc_pulse_period === exp_pulse_period_adc) && + (adc_pulse_num === exp_pulse_num)) + return; + end + + $fatal(1, + "Timeout waiting config outputs. Got: dac_width=%h dac_period=%h dac_num=%h dac_height=%h adc_period=%h adc_num=%h", + dac_pulse_width, + dac_pulse_period, + dac_pulse_num, + dac_pulse_height, + adc_pulse_period, + adc_pulse_num + ); + end + endtask + + //------------------------------------------------------------ + // Test sequence + //------------------------------------------------------------ + + logic [31:0] test_pulse_width; + logic [31:0] test_pulse_period; + logic [15:0] test_pulse_num; + logic [15:0] test_pulse_height_raw; + logic [31:0] test_pulse_period_adc; + initial begin + // defaults + rst_n = 1'b0; + rst_soft = 1'b0; - rst_n = 0; - rst_soft = 0; + start = 1'b0; + finish = 1'b0; - finish = 0; + cfg_bus_input = '0; + cfg_bus_valid = 1'b0; - start = 0; + test_pulse_width = 32'h11223344; + test_pulse_period = 32'h55667788; + test_pulse_num = 16'hA1B2; + test_pulse_height_raw = 16'h0CDE; // for DAC_DATA_WIDTH=12 => 12'hCDE + test_pulse_period_adc = 32'h50607080; - cfg_bus_valid = 0; - cfg_bus_input = 0; + repeat (10) @(posedge ctrl_clk); + rst_n = 1'b1; - repeat(10) @(posedge ctrl_clk); - - rst_n = 1; - - repeat(10) @(posedge ctrl_clk); + repeat (10) @(posedge ctrl_clk); //-------------------------------------------------------- - // TEST 1 RESET + // TEST 1: soft_reset //-------------------------------------------------------- - $display("TEST RESET"); + $display("[%0t] TEST 1: soft_reset", $time); - send_soft_reset(); + send_cmd(8'h0F); - repeat(20) @(posedge ctrl_clk); + wait_dac_rst_count(1); + wait_adc_rst_count(1); - assert(dac_rst_count==1); - assert(adc_rst_count==1); + if (dac_rst_count != 1) begin + $fatal(1, + "Expected exactly one dac_rst pulse after first soft_reset, got %0d", + dac_rst_count + ); + end + + if (adc_rst_count != 1) begin + $fatal(1, + "Expected exactly one adc_rst pulse after first soft_reset, got %0d", + adc_rst_count + ); + end + + $display("[%0t] TEST 1 passed", $time); //-------------------------------------------------------- - // TEST 2 CONFIG + // TEST 2: set_data //-------------------------------------------------------- - $display("TEST CONFIG"); + $display("[%0t] TEST 2: set_data", $time); - send_cfg( - 32'h11223344, - 32'h55667788, - 16'hA1B2, - 16'h0CDE, - 32'h50607080 + send_set_data( + test_pulse_width, + test_pulse_period, + test_pulse_num, + test_pulse_height_raw, + test_pulse_period_adc ); - repeat(30) @(posedge ctrl_clk); + wait_cfg_applied( + test_pulse_width, + test_pulse_period, + test_pulse_num, + test_pulse_height_raw, + test_pulse_period_adc + ); - assert(dac_pulse_width == 32'h11223344); - assert(dac_pulse_period == 32'h55667788); - assert(dac_pulse_num == 16'hA1B2); - assert(dac_pulse_height == 12'hCDE); + if (dac_pulse_width !== 32'h11223344) begin + $fatal(1, + "dac_pulse_width mismatch: got %h expected %h", + dac_pulse_width, + 32'h11223344 + ); + end - assert(adc_pulse_period == 32'h50607080); - assert(adc_pulse_num == 16'hA1B2); + if (dac_pulse_period !== 32'h55667788) begin + $fatal(1, + "dac_pulse_period mismatch: got %h expected %h", + dac_pulse_period, + 32'h55667788 + ); + end + + if (dac_pulse_num !== 16'hA1B2) begin + $fatal(1, + "dac_pulse_num mismatch: got %h expected %h", + dac_pulse_num, + 16'hA1B2 + ); + end + + if (dac_pulse_height !== 12'hCDE) begin + $fatal(1, + "dac_pulse_height mismatch: got %h expected %h", + dac_pulse_height, + 12'hCDE + ); + end + + if (adc_pulse_period !== 32'h50607080) begin + $fatal(1, + "adc_pulse_period mismatch: got %h expected %h", + adc_pulse_period, + 32'h50607080 + ); + end + + if (adc_pulse_num !== 16'hA1B2) begin + $fatal(1, + "adc_pulse_num mismatch: got %h expected %h", + adc_pulse_num, + 16'hA1B2 + ); + end + + $display("[%0t] TEST 2 passed", $time); + + repeat (20) @(posedge ctrl_clk); //-------------------------------------------------------- - // TEST 3 START + // TEST 3: start //-------------------------------------------------------- - $display("TEST START"); + $display("[%0t] TEST 3: start", $time); - send_start(); + send_cmd(8'hF0); - repeat(20) @(posedge ctrl_clk); + wait_dac_start_count(1); + wait_adc_start_count(1); - assert(busy); + if (dac_start_count != 1) begin + $fatal(1, + "Expected exactly one dac_start pulse after first start, got %0d", + dac_start_count + ); + end - assert(dac_start_count==1); - assert(adc_start_count==1); + if (adc_start_count != 1) begin + $fatal(1, + "Expected exactly one adc_start pulse after first start, got %0d", + adc_start_count + ); + end + + if (!busy) begin + $fatal(1, + "busy must be asserted after start" + ); + end + + $display("[%0t] TEST 3 start pulses passed", $time); //-------------------------------------------------------- - // TEST 4 FINISH + // release busy by finish pulse from ADC domain //-------------------------------------------------------- - $display("TEST FINISH"); + $display("[%0t] Sending finish pulse", $time); pulse_finish(); - repeat(20) @(posedge ctrl_clk); + repeat (20) @(posedge ctrl_clk); - assert(!busy); + if (busy) begin + $fatal(1, + "busy was not cleared after finish pulse" + ); + end //-------------------------------------------------------- - // TEST 5 START AGAIN + // sanity check that commands are accepted again after finish //-------------------------------------------------------- - send_start(); + $display("[%0t] TEST 4: soft_reset after finish", $time); - repeat(20) @(posedge ctrl_clk); + send_cmd(8'h0F); - assert(dac_start_count==2); - assert(adc_start_count==2); + wait_dac_rst_count(2); + wait_adc_rst_count(2); + + if (dac_rst_count != 2) begin + $fatal(1, + "Expected exactly two dac_rst pulses total, got %0d", + dac_rst_count + ); + end + + if (adc_rst_count != 2) begin + $fatal(1, + "Expected exactly two adc_rst pulses total, got %0d", + adc_rst_count + ); + end + + $display("[%0t] TEST 4 passed", $time); //-------------------------------------------------------- - $display(""); - $display("=============================="); - $display("ALL TESTS PASSED"); - $display("=============================="); + $display("=============================================="); + $display("ALL BASIC TESTS PASSED"); + $display("dac_rst_count = %0d", dac_rst_count); + $display("adc_rst_count = %0d", adc_rst_count); + $display("dac_start_count = %0d", dac_start_count); + $display("adc_start_count = %0d", adc_start_count); + $display("=============================================="); - #100; + #50; + + //-------------------------------------------------------- + // TEST 2.1: set_data + //-------------------------------------------------------- + + test_pulse_width = 32'h12121212; + test_pulse_period = 32'h34343434; + test_pulse_num = 16'h1A2B; + test_pulse_height_raw = 16'hC0ED; // for DAC_DATA_WIDTH=12 => 12'hCDE + test_pulse_period_adc = 32'h56565656; + + $display("[%0t] TEST 2.1: set_data", $time); + + send_set_data( + test_pulse_width, + test_pulse_period, + test_pulse_num, + test_pulse_height_raw, + test_pulse_period_adc + ); + + wait_cfg_applied( + test_pulse_width, + test_pulse_period, + test_pulse_num, + test_pulse_height_raw, + test_pulse_period_adc + ); + + if (dac_pulse_width !== 32'h12121212) begin + $fatal(1, + "dac_pulse_width mismatch: got %h expected %h", + dac_pulse_width, + 32'h12121212 + ); + end + + if (dac_pulse_period !== 32'h34343434) begin + $fatal(1, + "dac_pulse_period mismatch: got %h expected %h", + dac_pulse_period, + 32'h34343434 + ); + end + + if (dac_pulse_num !== 16'h1A2B) begin + $fatal(1, + "dac_pulse_num mismatch: got %h expected %h", + dac_pulse_num, + 16'h1A2B + ); + end + + if (dac_pulse_height !== 12'hC0ED) begin + $fatal(1, + "dac_pulse_height mismatch: got %h expected %h", + dac_pulse_height, + 12'hC0ED + ); + end + + if (adc_pulse_period !== 32'h56565656) begin + $fatal(1, + "adc_pulse_period mismatch: got %h expected %h", + adc_pulse_period, + 32'h56565656 + ); + end + + $display("[%0t] TEST 2.1 passed", $time); + + repeat (20) @(posedge ctrl_clk); + + //-------------------------------------------------------- + // TEST 3.1: start + //-------------------------------------------------------- + + $display("[%0t] TEST 3.1: start", $time); + + send_cmd(8'hF0); + + wait_dac_start_count(1); + wait_adc_start_count(1); + + if (dac_start_count != 1) begin + $fatal(1, + "Expected exactly one dac_start pulse after first start, got %0d", + dac_start_count + ); + end + + if (adc_start_count != 1) begin + $fatal(1, + "Expected exactly one adc_start pulse after first start, got %0d", + adc_start_count + ); + end + + if (!busy) begin + $fatal(1, + "busy must be asserted after start" + ); + end + + $display("[%0t] TEST 3.1 start pulses passed", $time); + + //-------------------------------------------------------- + // release busy by finish pulse from ADC domain + //-------------------------------------------------------- + + $display("[%0t] Sending finish pulse", $time); + + pulse_finish(); + + repeat (20) @(posedge ctrl_clk); + + if (busy) begin + $fatal(1, + "busy was not cleared after finish pulse" + ); + end + + //-------------------------------------------------------- + // sanity check that commands are accepted again after finish + //-------------------------------------------------------- + + $display("[%0t] TEST 4.1: soft_reset after finish", $time); + + send_cmd(8'h0F); + + wait_dac_rst_count(2); + wait_adc_rst_count(2); + + if (dac_rst_count != 2) begin + $fatal(1, + "Expected exactly two dac_rst pulses total, got %0d", + dac_rst_count + ); + end + + if (adc_rst_count != 2) begin + $fatal(1, + "Expected exactly two adc_rst pulses total, got %0d", + adc_rst_count + ); + end + + $display("[%0t] TEST 4.1 passed", $time); + + //-------------------------------------------------------- + + $display("=============================================="); + $display("ALL BASIC TESTS PASSED"); + $display("dac_rst_count = %0d", dac_rst_count); + $display("adc_rst_count = %0d", adc_rst_count); + $display("dac_start_count = %0d", dac_start_count); + $display("adc_start_count = %0d", adc_start_count); + $display("=============================================="); $finish; end diff --git a/rtl/controller/tests/tb_control_behav.wcfg b/rtl/controller/tests/tb_control_behav.wcfg index 334f2bc..656c219 100644 --- a/rtl/controller/tests/tb_control_behav.wcfg +++ b/rtl/controller/tests/tb_control_behav.wcfg @@ -12,14 +12,14 @@ - - + + - + - + dac_clk_in dac_clk_in @@ -235,8 +235,4 @@ #DCDCDC true - - busy - busy -