tests: auto tb for out_axis_fifo

This commit is contained in:
Phil
2026-04-21 19:47:27 +03:00
parent 4eb937e13f
commit dfccc01225

View File

@ -5,6 +5,8 @@ module tb_out_axis_fifo;
localparam int ACCUM_WIDTH = 32; localparam int ACCUM_WIDTH = 32;
localparam int WINDOW_SIZE = 65; localparam int WINDOW_SIZE = 65;
localparam int PACKET_SIZE = 1024; localparam int PACKET_SIZE = 1024;
localparam int BYTES_PER_WORD = ACCUM_WIDTH / 8;
localparam int WORDS_PER_BATCH = PACKET_SIZE / BYTES_PER_WORD; // 1024 / 4 = 256 слов
logic eth_clk_in; logic eth_clk_in;
logic acc_clk_in; logic acc_clk_in;
@ -20,6 +22,9 @@ module tb_out_axis_fifo;
logic [ACCUM_WIDTH-1:0] acc_din; logic [ACCUM_WIDTH-1:0] acc_din;
logic din_valid; logic din_valid;
logic send_req;
logic req_ready;
logic readout_begin; logic readout_begin;
logic batch_req; logic batch_req;
@ -45,38 +50,89 @@ module tb_out_axis_fifo;
.readout_begin (readout_begin), .readout_begin (readout_begin),
.req_ready (req_ready),
.send_req (send_req),
.batch_req (batch_req), .batch_req (batch_req),
.finish (finish) .finish (finish)
); );
// -----------------------------
// clocks // clocks
// -----------------------------
initial begin initial begin
eth_clk_in = 0; eth_clk_in = 0;
forever #4 eth_clk_in = ~eth_clk_in; // 125 MHz forever #6 eth_clk_in = ~eth_clk_in; // 125
end end
initial begin initial begin
acc_clk_in = 0; acc_clk_in = 0;
forever #3 acc_clk_in = ~acc_clk_in; // ~166.7 MHz forever #7.692307692 acc_clk_in = ~acc_clk_in; // 65
end end
// ----------------------------- // scoreboard
// simple AXIS sink byte expected_bytes[$];
// ----------------------------- int unsigned compared_bytes;
initial begin int unsigned mismatch_count;
s_axis_tready = 1'b1; int unsigned total_pushed_words;
task automatic scoreboard_reset();
begin
expected_bytes.delete();
compared_bytes = 0;
mismatch_count = 0;
total_pushed_words = 0;
end
endtask
task automatic push_expected_word(input logic [ACCUM_WIDTH-1:0] word);
begin
// queue push
expected_bytes.push_back(word[7:0]);
expected_bytes.push_back(word[15:8]);
expected_bytes.push_back(word[23:16]);
expected_bytes.push_back(word[31:24]);
total_pushed_words++;
end
endtask
task automatic check_expected_empty(string case_name);
begin
if (expected_bytes.size() != 0) begin
$error("[%0t] %s: expected_bytes is not empty, remaining=%0d",
$time, case_name, expected_bytes.size());
end else begin
$display("[%0t] %s: scoreboard queue empty, all expected bytes were transmitted",
$time, case_name);
end
end
endtask
// axis check
always_ff @(posedge eth_clk_in or posedge rst) begin
byte exp_byte;
if (rst) begin
compared_bytes <= 0;
mismatch_count <= 0;
end else begin
if (s_axis_tvalid && s_axis_tready) begin
if (expected_bytes.size() == 0) begin
$error("[%0t] AXIS produced unexpected byte 0x%02x: expected queue is empty",
$time, s_axis_tdata);
mismatch_count <= mismatch_count + 1;
end else begin
exp_byte = expected_bytes.pop_front();
compared_bytes <= compared_bytes + 1;
if (s_axis_tdata !== exp_byte) begin
$error("[%0t] AXIS mismatch at byte #%0d: got=0x%02x expected=0x%02x",
$time, compared_bytes, s_axis_tdata, exp_byte);
mismatch_count <= mismatch_count + 1;
end
end
end
end
end end
// У DUT нет своей логики rd_en, поэтому для теста подадим её force-ом.
initial begin
force dut.rd_en = dut.s_axis_tvalid && s_axis_tready;
end
// -----------------------------
// helpers // helpers
// -----------------------------
task automatic do_reset(); task automatic do_reset();
begin begin
rst = 1'b1; rst = 1'b1;
@ -85,6 +141,8 @@ module tb_out_axis_fifo;
acc_din = '0; acc_din = '0;
smp_num = '0; smp_num = '0;
scoreboard_reset();
repeat (10) @(posedge acc_clk_in); repeat (10) @(posedge acc_clk_in);
rst = 1'b0; rst = 1'b0;
@ -104,11 +162,17 @@ module tb_out_axis_fifo;
task automatic send_random_words(input int unsigned n_words); task automatic send_random_words(input int unsigned n_words);
int unsigned i; int unsigned i;
logic [ACCUM_WIDTH-1:0] rand_word;
begin begin
for (i = 0; i < n_words; i++) begin for (i = 0; i < n_words; i++) begin
rand_word = $urandom;
@(posedge acc_clk_in); @(posedge acc_clk_in);
din_valid <= 1'b1; din_valid <= 1'b1;
acc_din <= $urandom; acc_din <= rand_word;
// expected result
push_expected_word(rand_word);
end end
@(posedge acc_clk_in); @(posedge acc_clk_in);
@ -117,17 +181,20 @@ module tb_out_axis_fifo;
end end
endtask endtask
// Один запуск:
// 1) задаём smp_num // 1. set smp_num
// 2) даём readout_begin // 2. pulse readout_begon
// 3) каждый раз, когда DUT просит batch_req, отправляем PACKET_SIZE слов // 3. send 1KB (PACKET_SIZE) after each batch_req pulse
// 4) ждём finish // 4. wait for finish
// 5. compare axis result
task automatic run_case(input logic [31:0] smp_num_i); task automatic run_case(input logic [31:0] smp_num_i);
int batch_count; int batch_count;
string case_name;
begin begin
batch_count = 0; batch_count = 0;
case_name = $sformatf("run_case(smp_num=%0d)", smp_num_i);
$display("[%0t] run_case start, smp_num=%0d", $time, smp_num_i); $display("[%0t] %s start", $time, case_name);
pulse_readout_begin(smp_num_i); pulse_readout_begin(smp_num_i);
@ -136,39 +203,57 @@ module tb_out_axis_fifo;
if (batch_req) begin if (batch_req) begin
batch_count++; batch_count++;
$display("[%0t] batch_req #%0d -> send %0d words", $display("[%0t] %s: batch_req #%0d -> send %0d words",
$time, batch_count, PACKET_SIZE / ACCUM_WIDTH * 8); $time, case_name, batch_count, WORDS_PER_BATCH);
// send packets to accomplish 1kb packet. send_random_words(WORDS_PER_BATCH);
send_random_words(PACKET_SIZE / ACCUM_WIDTH * 8);
end end
end end
$display("[%0t] run_case done, smp_num=%0d, batches=%0d, wr_cnt=%0d, wr_total=%0d",
$time, smp_num_i, batch_count, dut.wr_cnt, dut.wr_total); repeat (200) @(posedge eth_clk_in);
$display("[%0t] %s done: batches=%0d, pushed_words=%0d, compared_bytes=%0d, mismatches=%0d, wr_cnt=%0d, wr_total=%0d",
$time, case_name, batch_count, total_pushed_words, compared_bytes, mismatch_count,
dut.wr_cnt, dut.wr_total);
check_expected_empty(case_name);
if (mismatch_count != 0) begin
$fatal(1, "[%0t] %s FAILED: mismatches=%0d", $time, case_name, mismatch_count);
end else begin
$display("[%0t] %s PASSED", $time, case_name);
end
@(posedge acc_clk_in); @(posedge acc_clk_in);
end end
endtask endtask
// ----------------------------- // eth beh simulator
// monitor
// -----------------------------
int axis_byte_count; int axis_byte_count;
always_ff @(posedge eth_clk_in or posedge rst) begin always_ff @(posedge eth_clk_in or posedge rst) begin
if (rst) begin if (rst) begin
axis_byte_count <= 0; axis_byte_count <= 0;
req_ready <= 0;
s_axis_tready <= 1'b0;
end else begin end else begin
req_ready <= 1;
// request send
if (send_req) begin
s_axis_tready <= 1'b1;
req_ready <= 0;
end
if (s_axis_tvalid && s_axis_tready) begin if (s_axis_tvalid && s_axis_tready) begin
axis_byte_count <= axis_byte_count + 1; axis_byte_count <= axis_byte_count + 1;
end end
end end
end end
// -----------------------------
// main // main
// -----------------------------
initial begin initial begin
// init // init
rst = 1'b0; rst = 1'b0;
@ -177,20 +262,27 @@ module tb_out_axis_fifo;
acc_din = '0; acc_din = '0;
smp_num = '0; smp_num = '0;
// 1-й запуск repeat (500) @(posedge acc_clk_in);
do_reset();
run_case(32'd17);
// 2-й запуск // 1
do_reset();
repeat (500) @(posedge acc_clk_in);
run_case(32'd17);
repeat (20) @(posedge acc_clk_in);
// 2
do_reset(); do_reset();
run_case(32'd1024); run_case(32'd1024);
repeat (20) @(posedge acc_clk_in);
// 3-й запуск // 3
do_reset(); do_reset();
run_case(32'd77777); run_case(32'd77777);
repeat (20) @(posedge acc_clk_in);
do_reset(); do_reset();
repeat (50) @(posedge acc_clk_in); repeat (20) @(posedge acc_clk_in);
$display("[%0t] ALL TESTS DONE", $time); $display("[%0t] ALL TESTS DONE", $time);
$finish; $finish;
end end