tests: auto tb for out_axis_fifo
This commit is contained in:
@ -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,45 +50,98 @@ 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;
|
||||||
readout_begin = 1'b0;
|
readout_begin = 1'b0;
|
||||||
din_valid = 1'b0;
|
din_valid = 1'b0;
|
||||||
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
|
||||||
|
|||||||
Reference in New Issue
Block a user