debugging controller
This commit is contained in:
@ -4,382 +4,295 @@ module tb_control;
|
||||
|
||||
localparam int unsigned DAC_DATA_WIDTH = 12;
|
||||
|
||||
|
||||
// Clocks / reset
|
||||
logic eth_clk_in;
|
||||
//------------------------------------------------------------
|
||||
// clocks
|
||||
//------------------------------------------------------------
|
||||
logic ctrl_clk;
|
||||
logic dac_clk_in;
|
||||
logic adc_clk_in;
|
||||
|
||||
initial begin
|
||||
ctrl_clk = 0;
|
||||
forever #4 ctrl_clk = ~ctrl_clk; //125 MHz
|
||||
end
|
||||
|
||||
initial begin
|
||||
dac_clk_in = 0;
|
||||
forever #3.846 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
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// DUT inputs
|
||||
//------------------------------------------------------------
|
||||
logic rst_n;
|
||||
logic rst_soft;
|
||||
|
||||
// axi stream (input)
|
||||
logic [7:0] s_axis_tdata;
|
||||
logic s_axis_tvalid;
|
||||
logic s_axis_tready;
|
||||
logic s_axis_tlast;
|
||||
|
||||
// ADC side input
|
||||
logic finish;
|
||||
|
||||
// DUT outputs
|
||||
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 [127:0] cfg_bus_input;
|
||||
logic cfg_bus_valid;
|
||||
|
||||
logic [31:0] adc_pulse_period;
|
||||
logic [15:0] adc_pulse_num;
|
||||
logic start;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// DUT outputs
|
||||
//------------------------------------------------------------
|
||||
logic busy;
|
||||
|
||||
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 [31:0] adc_pulse_period;
|
||||
logic [15:0] adc_pulse_num;
|
||||
|
||||
logic dac_start;
|
||||
logic adc_start;
|
||||
|
||||
logic dac_rst;
|
||||
logic adc_rst;
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// DUT
|
||||
//------------------------------------------------------------
|
||||
|
||||
control #(
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
) dut (
|
||||
.eth_clk_in (eth_clk_in),
|
||||
.dac_clk_in (dac_clk_in),
|
||||
.adc_clk_in (adc_clk_in),
|
||||
.rst_n (rst_n),
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.dac_clk_in(dac_clk_in),
|
||||
.adc_clk_in(adc_clk_in),
|
||||
|
||||
.s_axis_tdata (s_axis_tdata),
|
||||
.s_axis_tvalid (s_axis_tvalid),
|
||||
.s_axis_tready (s_axis_tready),
|
||||
.s_axis_tlast (s_axis_tlast),
|
||||
.rst_n(rst_n),
|
||||
.rst_soft(rst_soft),
|
||||
|
||||
.finish (finish),
|
||||
.finish(finish),
|
||||
|
||||
.dac_pulse_width (dac_pulse_width),
|
||||
.dac_pulse_period (dac_pulse_period),
|
||||
.dac_pulse_height (dac_pulse_height),
|
||||
.dac_pulse_num (dac_pulse_num),
|
||||
.cfg_bus_input(cfg_bus_input),
|
||||
.cfg_bus_valid(cfg_bus_valid),
|
||||
|
||||
.adc_pulse_period (adc_pulse_period),
|
||||
.adc_pulse_num (adc_pulse_num),
|
||||
.start(start),
|
||||
|
||||
.dac_start (dac_start),
|
||||
.adc_start (adc_start),
|
||||
.dac_rst (dac_rst),
|
||||
.adc_rst (adc_rst)
|
||||
.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),
|
||||
|
||||
.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)
|
||||
);
|
||||
|
||||
|
||||
// Clock generation
|
||||
initial begin
|
||||
eth_clk_in = 1'b0;
|
||||
forever #(1 * 4.000) eth_clk_in = ~eth_clk_in; // 125 MHz
|
||||
end
|
||||
//------------------------------------------------------------
|
||||
// pulse counters
|
||||
//------------------------------------------------------------
|
||||
|
||||
initial begin
|
||||
dac_clk_in = 1'b0;
|
||||
forever #(1 * 3.846153846) dac_clk_in = ~dac_clk_in; // ~130 MHz
|
||||
end
|
||||
|
||||
initial begin
|
||||
adc_clk_in = 1'b0;
|
||||
forever #(1 * 7.692307692) adc_clk_in = ~adc_clk_in; // ~65 MHz
|
||||
end
|
||||
|
||||
|
||||
// pulse counters and monitors for testing
|
||||
int dac_rst_count;
|
||||
int adc_rst_count;
|
||||
int dac_start_count;
|
||||
int adc_start_count;
|
||||
int dac_rst_count;
|
||||
int adc_rst_count;
|
||||
|
||||
always_ff @(posedge dac_clk_in) begin
|
||||
if (!rst_n) begin
|
||||
dac_rst_count <= 0;
|
||||
dac_start_count <= 0;
|
||||
end else begin
|
||||
if (dac_rst) dac_rst_count <= dac_rst_count + 1;
|
||||
if (dac_start) dac_start_count <= dac_start_count + 1;
|
||||
dac_rst_count <= 0;
|
||||
end
|
||||
else begin
|
||||
if (dac_start) dac_start_count++;
|
||||
if (dac_rst) dac_rst_count++;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge adc_clk_in) begin
|
||||
if (!rst_n) begin
|
||||
adc_rst_count <= 0;
|
||||
adc_start_count <= 0;
|
||||
end else begin
|
||||
if (adc_rst) adc_rst_count <= adc_rst_count + 1;
|
||||
if (adc_start) adc_start_count <= adc_start_count + 1;
|
||||
adc_rst_count <= 0;
|
||||
end
|
||||
else begin
|
||||
if (adc_start) adc_start_count++;
|
||||
if (adc_rst) adc_rst_count++;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// some helpers for axi
|
||||
task automatic axis_send_byte(input logic [7:0] data, input logic last);
|
||||
begin
|
||||
@(negedge eth_clk_in);
|
||||
s_axis_tdata <= data;
|
||||
s_axis_tvalid <= 1'b1;
|
||||
s_axis_tlast <= last;
|
||||
//------------------------------------------------------------
|
||||
// tasks
|
||||
//------------------------------------------------------------
|
||||
|
||||
@(posedge eth_clk_in);
|
||||
while (!s_axis_tready) begin
|
||||
@(posedge eth_clk_in);
|
||||
end
|
||||
|
||||
s_axis_tvalid <= 1'b0;
|
||||
s_axis_tlast <= 1'b0;
|
||||
s_axis_tdata <= '0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic send_cmd(input logic [7:0] cmd);
|
||||
begin
|
||||
axis_send_byte(cmd, 1'b1);
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic send_set_data(
|
||||
task automatic send_cfg(
|
||||
input logic [31:0] pulse_width,
|
||||
input logic [31:0] pulse_period,
|
||||
input logic [15:0] pulse_num,
|
||||
input logic [15:0] pulse_height_raw,
|
||||
input logic [31:0] pulse_period_adc
|
||||
input logic [15:0] pulse_height,
|
||||
input logic [31:0] adc_period
|
||||
);
|
||||
logic [127:0] payload;
|
||||
int i;
|
||||
begin
|
||||
// little-endian payload layout:
|
||||
// [31:0] pulse_width
|
||||
// [63:32] pulse_period
|
||||
// [79:64] pulse_num
|
||||
// [95:80] pulse_height_raw
|
||||
// [127:96] pulse_period_ADC
|
||||
|
||||
payload = {pulse_period_adc, pulse_height_raw, pulse_num, pulse_period, pulse_width};
|
||||
begin
|
||||
|
||||
axis_send_byte(8'h88, 1'b0); // CMD_SET_DATA
|
||||
cfg_bus_input = {
|
||||
adc_period,
|
||||
pulse_height,
|
||||
pulse_num,
|
||||
pulse_period,
|
||||
pulse_width
|
||||
};
|
||||
|
||||
for (i = 0; i < 16; i++) begin
|
||||
axis_send_byte(payload[i*8 +: 8], (i == 15));
|
||||
end
|
||||
end
|
||||
@(posedge ctrl_clk);
|
||||
cfg_bus_valid <= 1;
|
||||
|
||||
@(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;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic pulse_finish;
|
||||
begin
|
||||
@(posedge adc_clk_in);
|
||||
finish <= 1'b1;
|
||||
@(posedge adc_clk_in);
|
||||
finish <= 1'b0;
|
||||
end
|
||||
begin
|
||||
@(posedge adc_clk_in);
|
||||
finish <= 1;
|
||||
|
||||
@(posedge adc_clk_in);
|
||||
finish <= 0;
|
||||
end
|
||||
endtask
|
||||
|
||||
|
||||
// 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 eth_clk_in);
|
||||
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 )) begin
|
||||
return;
|
||||
end
|
||||
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;
|
||||
//------------------------------------------------------------
|
||||
// TEST
|
||||
//------------------------------------------------------------
|
||||
|
||||
initial begin
|
||||
// defaults
|
||||
rst_n = 1'b0;
|
||||
s_axis_tdata = '0;
|
||||
s_axis_tvalid = 1'b0;
|
||||
s_axis_tlast = 1'b0;
|
||||
finish = 1'b0;
|
||||
|
||||
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;
|
||||
rst_n = 0;
|
||||
rst_soft = 0;
|
||||
|
||||
repeat (10) @(posedge eth_clk_in);
|
||||
rst_n = 1'b1;
|
||||
finish = 0;
|
||||
|
||||
repeat (10) @(posedge eth_clk_in);
|
||||
start = 0;
|
||||
|
||||
$display("[%0t] TEST 1: soft_reset", $time);
|
||||
send_cmd(8'h0F);
|
||||
cfg_bus_valid = 0;
|
||||
cfg_bus_input = 0;
|
||||
|
||||
wait_dac_rst_count(1);
|
||||
wait_adc_rst_count(1);
|
||||
repeat(10) @(posedge ctrl_clk);
|
||||
|
||||
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
|
||||
rst_n = 1;
|
||||
|
||||
$display("[%0t] TEST 1 passed", $time);
|
||||
repeat(10) @(posedge ctrl_clk);
|
||||
|
||||
$display("[%0t] TEST 2: set_data", $time);
|
||||
send_set_data(
|
||||
test_pulse_width,
|
||||
test_pulse_period,
|
||||
test_pulse_num,
|
||||
test_pulse_height_raw,
|
||||
test_pulse_period_adc
|
||||
//--------------------------------------------------------
|
||||
// TEST 1 RESET
|
||||
//--------------------------------------------------------
|
||||
|
||||
$display("TEST RESET");
|
||||
|
||||
send_soft_reset();
|
||||
|
||||
repeat(20) @(posedge ctrl_clk);
|
||||
|
||||
assert(dac_rst_count==1);
|
||||
assert(adc_rst_count==1);
|
||||
|
||||
//--------------------------------------------------------
|
||||
// TEST 2 CONFIG
|
||||
//--------------------------------------------------------
|
||||
|
||||
$display("TEST CONFIG");
|
||||
|
||||
send_cfg(
|
||||
32'h11223344,
|
||||
32'h55667788,
|
||||
16'hA1B2,
|
||||
16'h0CDE,
|
||||
32'h50607080
|
||||
);
|
||||
|
||||
wait_cfg_applied(
|
||||
test_pulse_width,
|
||||
test_pulse_period,
|
||||
test_pulse_num,
|
||||
test_pulse_height_raw,
|
||||
test_pulse_period_adc
|
||||
);
|
||||
repeat(30) @(posedge ctrl_clk);
|
||||
|
||||
if (dac_pulse_width !== 32'h11223344) begin
|
||||
$fatal(1, "dac_pulse_width mismatch: got %h expected %h", dac_pulse_width, 32'h11223344);
|
||||
end
|
||||
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
|
||||
assert(dac_pulse_width == 32'h11223344);
|
||||
assert(dac_pulse_period == 32'h55667788);
|
||||
assert(dac_pulse_num == 16'hA1B2);
|
||||
assert(dac_pulse_height == 12'hCDE);
|
||||
|
||||
$display("[%0t] TEST 2 passed", $time);
|
||||
|
||||
repeat (20) @(posedge eth_clk_in);
|
||||
assert(adc_pulse_period == 32'h50607080);
|
||||
assert(adc_pulse_num == 16'hA1B2);
|
||||
|
||||
$display("[%0t] TEST 3: start", $time);
|
||||
send_cmd(8'hF0);
|
||||
//--------------------------------------------------------
|
||||
// TEST 3 START
|
||||
//--------------------------------------------------------
|
||||
|
||||
wait_dac_start_count(1);
|
||||
wait_adc_start_count(1);
|
||||
$display("TEST START");
|
||||
|
||||
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
|
||||
send_start();
|
||||
|
||||
$display("[%0t] TEST 3 start pulses passed", $time);
|
||||
repeat(20) @(posedge ctrl_clk);
|
||||
|
||||
assert(busy);
|
||||
|
||||
assert(dac_start_count==1);
|
||||
assert(adc_start_count==1);
|
||||
|
||||
//--------------------------------------------------------
|
||||
// TEST 4 FINISH
|
||||
//--------------------------------------------------------
|
||||
|
||||
$display("TEST FINISH");
|
||||
|
||||
// release busy by finish pulse from ADC domain
|
||||
$display("[%0t] Sending finish pulse", $time);
|
||||
pulse_finish();
|
||||
|
||||
// a bit of wait for finish CDC back to ETH
|
||||
repeat (20) @(posedge eth_clk_in);
|
||||
repeat(20) @(posedge ctrl_clk);
|
||||
|
||||
// sanity check that commands are accepted again after finish
|
||||
$display("[%0t] TEST 4: soft_reset after finish", $time);
|
||||
send_cmd(8'h0F);
|
||||
assert(!busy);
|
||||
|
||||
wait_dac_rst_count(2);
|
||||
wait_adc_rst_count(2);
|
||||
//--------------------------------------------------------
|
||||
// TEST 5 START AGAIN
|
||||
//--------------------------------------------------------
|
||||
|
||||
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
|
||||
send_start();
|
||||
|
||||
$display("[%0t] TEST 4 passed", $time);
|
||||
repeat(20) @(posedge ctrl_clk);
|
||||
|
||||
$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("==============================================");
|
||||
assert(dac_start_count==2);
|
||||
assert(adc_start_count==2);
|
||||
|
||||
//--------------------------------------------------------
|
||||
|
||||
$display("");
|
||||
$display("==============================");
|
||||
$display("ALL TESTS PASSED");
|
||||
$display("==============================");
|
||||
|
||||
#100;
|
||||
$finish;
|
||||
|
||||
end
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user