290 lines
7.9 KiB
Systemverilog
290 lines
7.9 KiB
Systemverilog
`timescale 1ns/1ps
|
|
|
|
module tb_out_axis_fifo;
|
|
|
|
localparam int ACCUM_WIDTH = 32;
|
|
localparam int WINDOW_SIZE = 65;
|
|
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 acc_clk_in;
|
|
logic rst;
|
|
|
|
logic [31:0] smp_num;
|
|
|
|
logic [7:0] s_axis_tdata;
|
|
logic s_axis_tvalid;
|
|
logic s_axis_tready;
|
|
logic s_axis_tlast;
|
|
|
|
logic [ACCUM_WIDTH-1:0] acc_din;
|
|
logic din_valid;
|
|
|
|
logic send_req;
|
|
logic req_ready;
|
|
|
|
logic readout_begin;
|
|
|
|
logic batch_req;
|
|
logic finish;
|
|
|
|
out_axis_fifo #(
|
|
.ACCUM_WIDTH(ACCUM_WIDTH),
|
|
.WINDOW_SIZE(WINDOW_SIZE),
|
|
.PACKET_SIZE(PACKET_SIZE)
|
|
) dut (
|
|
.eth_clk_in (eth_clk_in),
|
|
.acc_clk_in (acc_clk_in),
|
|
.rst (rst),
|
|
.smp_num (smp_num),
|
|
|
|
.s_axis_tdata (s_axis_tdata),
|
|
.s_axis_tvalid (s_axis_tvalid),
|
|
.s_axis_tready (s_axis_tready),
|
|
.s_axis_tlast (s_axis_tlast),
|
|
|
|
.acc_din (acc_din),
|
|
.din_valid (din_valid),
|
|
|
|
.readout_begin (readout_begin),
|
|
|
|
.req_ready (req_ready),
|
|
.send_req (send_req),
|
|
|
|
.batch_req (batch_req),
|
|
.finish (finish)
|
|
);
|
|
|
|
// clocks
|
|
initial begin
|
|
eth_clk_in = 0;
|
|
forever #6 eth_clk_in = ~eth_clk_in; // 125
|
|
end
|
|
|
|
initial begin
|
|
acc_clk_in = 0;
|
|
forever #7.692307692 acc_clk_in = ~acc_clk_in; // 65
|
|
end
|
|
|
|
// scoreboard
|
|
byte expected_bytes[$];
|
|
int unsigned compared_bytes;
|
|
int unsigned mismatch_count;
|
|
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
|
|
|
|
// helpers
|
|
task automatic do_reset();
|
|
begin
|
|
rst = 1'b1;
|
|
readout_begin = 1'b0;
|
|
din_valid = 1'b0;
|
|
acc_din = '0;
|
|
smp_num = '0;
|
|
|
|
scoreboard_reset();
|
|
|
|
repeat (10) @(posedge acc_clk_in);
|
|
rst = 1'b0;
|
|
|
|
repeat (10) @(posedge acc_clk_in);
|
|
end
|
|
endtask
|
|
|
|
task automatic pulse_readout_begin(input logic [31:0] smp_num_i);
|
|
begin
|
|
smp_num = smp_num_i;
|
|
@(posedge acc_clk_in);
|
|
readout_begin <= 1'b1;
|
|
@(posedge acc_clk_in);
|
|
readout_begin <= 1'b0;
|
|
end
|
|
endtask
|
|
|
|
task automatic send_random_words(input int unsigned n_words);
|
|
int unsigned i;
|
|
logic [ACCUM_WIDTH-1:0] rand_word;
|
|
begin
|
|
for (i = 0; i < n_words; i++) begin
|
|
rand_word = $urandom;
|
|
|
|
@(posedge acc_clk_in);
|
|
din_valid <= 1'b1;
|
|
acc_din <= rand_word;
|
|
|
|
// expected result
|
|
push_expected_word(rand_word);
|
|
end
|
|
|
|
@(posedge acc_clk_in);
|
|
din_valid <= 1'b0;
|
|
acc_din <= '0;
|
|
end
|
|
endtask
|
|
|
|
|
|
// 1. set smp_num
|
|
// 2. pulse readout_begon
|
|
// 3. send 1KB (PACKET_SIZE) after each batch_req pulse
|
|
// 4. wait for finish
|
|
// 5. compare axis result
|
|
task automatic run_case(input logic [31:0] smp_num_i);
|
|
int batch_count;
|
|
string case_name;
|
|
begin
|
|
batch_count = 0;
|
|
case_name = $sformatf("run_case(smp_num=%0d)", smp_num_i);
|
|
|
|
$display("[%0t] %s start", $time, case_name);
|
|
|
|
pulse_readout_begin(smp_num_i);
|
|
|
|
while (finish !== 1'b1) begin
|
|
@(posedge acc_clk_in);
|
|
|
|
if (batch_req) begin
|
|
batch_count++;
|
|
$display("[%0t] %s: batch_req #%0d -> send %0d words",
|
|
$time, case_name, batch_count, WORDS_PER_BATCH);
|
|
|
|
send_random_words(WORDS_PER_BATCH);
|
|
end
|
|
end
|
|
|
|
|
|
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);
|
|
end
|
|
endtask
|
|
|
|
// eth beh simulator
|
|
int axis_byte_count;
|
|
|
|
always_ff @(posedge eth_clk_in or posedge rst) begin
|
|
if (rst) begin
|
|
axis_byte_count <= 0;
|
|
req_ready <= 0;
|
|
s_axis_tready <= 1'b0;
|
|
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
|
|
axis_byte_count <= axis_byte_count + 1;
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
// main
|
|
initial begin
|
|
// init
|
|
rst = 1'b0;
|
|
readout_begin = 1'b0;
|
|
din_valid = 1'b0;
|
|
acc_din = '0;
|
|
smp_num = '0;
|
|
|
|
repeat (500) @(posedge acc_clk_in);
|
|
|
|
// 1
|
|
do_reset();
|
|
repeat (500) @(posedge acc_clk_in);
|
|
run_case(32'd17);
|
|
repeat (20) @(posedge acc_clk_in);
|
|
|
|
// 2
|
|
do_reset();
|
|
run_case(32'd1024);
|
|
repeat (20) @(posedge acc_clk_in);
|
|
|
|
// 3
|
|
do_reset();
|
|
run_case(32'd77777);
|
|
repeat (20) @(posedge acc_clk_in);
|
|
|
|
do_reset();
|
|
repeat (20) @(posedge acc_clk_in);
|
|
|
|
$display("[%0t] ALL TESTS DONE", $time);
|
|
$finish;
|
|
end
|
|
|
|
endmodule |