debugged controller

This commit is contained in:
otroubi
2026-07-10 13:13:18 +03:00
parent 99a344d534
commit 061f8fe12b
3 changed files with 553 additions and 150 deletions

View File

@ -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

View File

@ -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,6 +43,7 @@ module tb_control;
//------------------------------------------------------------
// DUT outputs
//------------------------------------------------------------
logic busy;
logic [31:0] dac_pulse_width;
@ -54,7 +56,6 @@ module tb_control;
logic dac_start;
logic adc_start;
logic dac_rst;
logic adc_rst;
@ -96,201 +97,608 @@ module tb_control;
);
//------------------------------------------------------------
// 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
);
logic [127:0] payload;
begin
cfg_bus_input = {
adc_period,
pulse_height,
payload = {
pulse_period_adc,
pulse_height_raw,
pulse_num,
pulse_period,
pulse_width
};
@(posedge ctrl_clk);
cfg_bus_valid <= 1;
@(negedge ctrl_clk);
cfg_bus_input <= payload;
cfg_bus_valid <= 1'b1;
@(posedge ctrl_clk);
cfg_bus_valid <= 0;
end
endtask
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;
cfg_bus_valid <= 1'b0;
cfg_bus_input <= '0;
end
endtask
task automatic pulse_finish;
begin
@(posedge adc_clk_in);
finish <= 1;
finish <= 1'b1;
@(posedge adc_clk_in);
finish <= 0;
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;
cfg_bus_valid = 0;
cfg_bus_input = 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;
repeat (10) @(posedge ctrl_clk);
rst_n = 1;
rst_n = 1'b1;
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
//--------------------------------------------------------
// TEST 3 START
//--------------------------------------------------------
if (dac_pulse_num !== 16'hA1B2) begin
$fatal(1,
"dac_pulse_num mismatch: got %h expected %h",
dac_pulse_num,
16'hA1B2
);
end
$display("TEST START");
if (dac_pulse_height !== 12'hCDE) begin
$fatal(1,
"dac_pulse_height mismatch: got %h expected %h",
dac_pulse_height,
12'hCDE
);
end
send_start();
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);
assert(busy);
assert(dac_start_count==1);
assert(adc_start_count==1);
//--------------------------------------------------------
// TEST 4 FINISH
// TEST 3: start
//--------------------------------------------------------
$display("TEST FINISH");
$display("[%0t] TEST 3: 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 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);
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);
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 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("==============================================");
#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);
assert(dac_start_count==2);
assert(adc_start_count==2);
//--------------------------------------------------------
// 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("==============================");
$display("ALL TESTS PASSED");
$display("==============================");
#100;
$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

View File

@ -12,14 +12,14 @@
</db_ref_list>
<zoom_setting>
<ZoomStartTime time="0.000 ns"></ZoomStartTime>
<ZoomEndTime time="575.529 ns"></ZoomEndTime>
<Cursor1Time time="391.616 ns"></Cursor1Time>
<ZoomEndTime time="1,269.181 ns"></ZoomEndTime>
<Cursor1Time time="580.000 ns"></Cursor1Time>
</zoom_setting>
<column_width_setting>
<NameColumnWidth column_width="495"></NameColumnWidth>
<NameColumnWidth column_width="487"></NameColumnWidth>
<ValueColumnWidth column_width="116"></ValueColumnWidth>
</column_width_setting>
<WVObjectSize size="35" />
<WVObjectSize size="34" />
<wvobject fp_name="/tb_control/dac_clk_in" type="logic">
<obj_property name="ElementShortName">dac_clk_in</obj_property>
<obj_property name="ObjectShortName">dac_clk_in</obj_property>
@ -235,8 +235,4 @@
<obj_property name="CustomSignalColor">#DCDCDC</obj_property>
<obj_property name="UseCustomSignalColor">true</obj_property>
</wvobject>
<wvobject fp_name="/tb_control/dut/busy" type="logic">
<obj_property name="ElementShortName">busy</obj_property>
<obj_property name="ObjectShortName">busy</obj_property>
</wvobject>
</wave_config>