test: add full testbenches for accum
This commit is contained in:
92
rtl/accum/src/accum_top.sv
Normal file
92
rtl/accum/src/accum_top.sv
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
module accumulator_top
|
||||||
|
#(
|
||||||
|
parameter DATA_WIDTH = 12,
|
||||||
|
parameter ACCUM_WIDTH = 32,
|
||||||
|
parameter N_MAX = 4096,
|
||||||
|
parameter WINDOW_SIZE = 4,
|
||||||
|
parameter PACKET_SIZE = 8,
|
||||||
|
parameter READ_BATCH_SIZE =(PACKET_SIZE*8)/(ACCUM_WIDTH)
|
||||||
|
)
|
||||||
|
(
|
||||||
|
// main clk
|
||||||
|
input clk_in,
|
||||||
|
input rst,
|
||||||
|
|
||||||
|
// input data
|
||||||
|
input [DATA_WIDTH-1:0] s_axis_tdata,
|
||||||
|
input s_axis_tvalid,
|
||||||
|
|
||||||
|
// parameters
|
||||||
|
input start,
|
||||||
|
input [31:0] smp_num,
|
||||||
|
input [15:0] seq_num,
|
||||||
|
|
||||||
|
// eth signals
|
||||||
|
input eth_clk_in,
|
||||||
|
input req_ready,
|
||||||
|
output send_req,
|
||||||
|
|
||||||
|
// output axis
|
||||||
|
output logic [7:0] m_axis_tdata,
|
||||||
|
output logic m_axis_tvalid,
|
||||||
|
input logic m_axis_tready,
|
||||||
|
output logic m_axis_tlast,
|
||||||
|
|
||||||
|
output logic finish
|
||||||
|
);
|
||||||
|
|
||||||
|
wire [ACCUM_WIDTH-1:0] out_data;
|
||||||
|
wire out_valid;
|
||||||
|
wire readout_begin;
|
||||||
|
wire batch_req;
|
||||||
|
|
||||||
|
accumulator #(
|
||||||
|
.DATA_WIDTH(DATA_WIDTH),
|
||||||
|
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||||
|
.N_MAX(N_MAX),
|
||||||
|
.WINDOW_SIZE(WINDOW_SIZE),
|
||||||
|
.PACKET_SIZE(PACKET_SIZE)
|
||||||
|
) accum_main (
|
||||||
|
.clk_in(clk_in),
|
||||||
|
.rst(rst),
|
||||||
|
.s_axis_tdata(s_axis_tdata),
|
||||||
|
.s_axis_tvalid(s_axis_tvalid),
|
||||||
|
.start(start),
|
||||||
|
.smp_num(smp_num),
|
||||||
|
.seq_num(seq_num),
|
||||||
|
.out_data(out_data),
|
||||||
|
.out_valid(out_valid),
|
||||||
|
.readout_begin(readout_begin),
|
||||||
|
.batch_req(batch_req),
|
||||||
|
.finish(finish)
|
||||||
|
);
|
||||||
|
|
||||||
|
out_axis_fifo #(
|
||||||
|
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||||
|
.WINDOW_SIZE(WINDOW_SIZE),
|
||||||
|
.PACKET_SIZE(PACKET_SIZE)
|
||||||
|
) output_async_fifo (
|
||||||
|
.eth_clk_in (eth_clk_in),
|
||||||
|
.acc_clk_in (clk_in),
|
||||||
|
.rst (rst),
|
||||||
|
.smp_num (smp_num),
|
||||||
|
|
||||||
|
.m_axis_tdata (m_axis_tdata),
|
||||||
|
.m_axis_tvalid (m_axis_tvalid),
|
||||||
|
.m_axis_tready (m_axis_tready),
|
||||||
|
.m_axis_tlast (m_axis_tlast),
|
||||||
|
|
||||||
|
.acc_din (out_data),
|
||||||
|
.din_valid (out_valid),
|
||||||
|
|
||||||
|
.readout_begin (readout_begin),
|
||||||
|
|
||||||
|
.req_ready (req_ready),
|
||||||
|
.send_req (send_req),
|
||||||
|
|
||||||
|
.batch_req (batch_req),
|
||||||
|
.finish (finish)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
# FPGA settings
|
# FPGA settings
|
||||||
FPGA_PART = xc7a35tfgg484-1
|
FPGA_PART = xc7a35tfgg484-1
|
||||||
FPGA_TOP = accum
|
FPGA_TOP = accumulator_top
|
||||||
FPGA_ARCH = artix7
|
FPGA_ARCH = artix7
|
||||||
|
|
||||||
RTL_DIR = ../src
|
RTL_DIR = ../src
|
||||||
@ -24,7 +24,8 @@ XDC_FILES += ../../../constraints/ax7a035b.xdc
|
|||||||
XDC_FILES += test_timing.xdc
|
XDC_FILES += test_timing.xdc
|
||||||
|
|
||||||
SYN_FILES += out_axis_fifo_tb.sv
|
SYN_FILES += out_axis_fifo_tb.sv
|
||||||
SIM_TOP = control_tb
|
SYN_FILE += accum_full_tb.sv
|
||||||
|
SIM_TOP = tb_accumulator_top
|
||||||
|
|
||||||
|
|
||||||
program: $(PROJECT).bit
|
program: $(PROJECT).bit
|
||||||
|
|||||||
344
rtl/accum/tests/accum_full_tb.sv
Normal file
344
rtl/accum/tests/accum_full_tb.sv
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
module tb_accumulator_top;
|
||||||
|
|
||||||
|
localparam DATA_WIDTH = 12;
|
||||||
|
localparam ACCUM_WIDTH = 32;
|
||||||
|
localparam N_MAX = 256;
|
||||||
|
localparam WINDOW_SIZE = 4;
|
||||||
|
localparam PACKET_SIZE = 128;
|
||||||
|
localparam READ_BATCH_SIZE = (PACKET_SIZE*8)/ACCUM_WIDTH;
|
||||||
|
localparam MAX_WORDS = N_MAX / WINDOW_SIZE;
|
||||||
|
localparam MAX_SEQ_NUM = 64;
|
||||||
|
|
||||||
|
logic clk_in;
|
||||||
|
logic eth_clk_in;
|
||||||
|
logic rst;
|
||||||
|
|
||||||
|
logic [DATA_WIDTH-1:0] s_axis_tdata;
|
||||||
|
logic s_axis_tvalid;
|
||||||
|
logic start;
|
||||||
|
logic [31:0] smp_num;
|
||||||
|
logic [15:0] seq_num;
|
||||||
|
|
||||||
|
logic req_ready;
|
||||||
|
wire send_req;
|
||||||
|
|
||||||
|
wire [7:0] m_axis_tdata;
|
||||||
|
wire m_axis_tvalid;
|
||||||
|
logic m_axis_tready;
|
||||||
|
wire m_axis_tlast;
|
||||||
|
|
||||||
|
wire finish;
|
||||||
|
|
||||||
|
integer seed;
|
||||||
|
integer total_errors;
|
||||||
|
integer tests_total;
|
||||||
|
integer tests_failed;
|
||||||
|
integer tests_passed;
|
||||||
|
|
||||||
|
integer packets_seen;
|
||||||
|
integer current_packet_byte_count;
|
||||||
|
integer total_words_captured;
|
||||||
|
|
||||||
|
byte packet_bytes [0:PACKET_SIZE-1];
|
||||||
|
logic [ACCUM_WIDTH-1:0] expected_words [0:MAX_WORDS-1];
|
||||||
|
logic [ACCUM_WIDTH-1:0] captured_words_le[0:MAX_WORDS-1];
|
||||||
|
logic [ACCUM_WIDTH-1:0] captured_words_be[0:MAX_WORDS-1];
|
||||||
|
|
||||||
|
accumulator_top #(
|
||||||
|
.DATA_WIDTH(DATA_WIDTH),
|
||||||
|
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||||
|
.N_MAX(N_MAX),
|
||||||
|
.WINDOW_SIZE(WINDOW_SIZE),
|
||||||
|
.PACKET_SIZE(PACKET_SIZE)
|
||||||
|
) dut (
|
||||||
|
.clk_in(clk_in),
|
||||||
|
.rst(rst),
|
||||||
|
.s_axis_tdata(s_axis_tdata),
|
||||||
|
.s_axis_tvalid(s_axis_tvalid),
|
||||||
|
.start(start),
|
||||||
|
.smp_num(smp_num),
|
||||||
|
.seq_num(seq_num),
|
||||||
|
.eth_clk_in(eth_clk_in),
|
||||||
|
.req_ready(req_ready),
|
||||||
|
.send_req(send_req),
|
||||||
|
.m_axis_tdata(m_axis_tdata),
|
||||||
|
.m_axis_tvalid(m_axis_tvalid),
|
||||||
|
.m_axis_tready(m_axis_tready),
|
||||||
|
.m_axis_tlast(m_axis_tlast),
|
||||||
|
.finish(finish)
|
||||||
|
);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
clk_in = 1'b0;
|
||||||
|
forever #5 clk_in = ~clk_in;
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
eth_clk_in = 1'b0;
|
||||||
|
forever #4 eth_clk_in = ~eth_clk_in;
|
||||||
|
end
|
||||||
|
|
||||||
|
task automatic clear_scoreboard;
|
||||||
|
integer i;
|
||||||
|
begin
|
||||||
|
packets_seen = 0;
|
||||||
|
current_packet_byte_count = 0;
|
||||||
|
total_words_captured = 0;
|
||||||
|
for (i = 0; i < MAX_WORDS; i = i + 1) begin
|
||||||
|
expected_words[i] = '0;
|
||||||
|
captured_words_le[i] = '0;
|
||||||
|
captured_words_be[i] = '0;
|
||||||
|
end
|
||||||
|
for (i = 0; i < PACKET_SIZE; i = i + 1)
|
||||||
|
packet_bytes[i] = 8'h00;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task automatic reset_dut;
|
||||||
|
begin
|
||||||
|
rst = 1'b1;
|
||||||
|
start = 1'b0;
|
||||||
|
s_axis_tdata = '0;
|
||||||
|
s_axis_tvalid = 1'b0;
|
||||||
|
smp_num = '0;
|
||||||
|
seq_num = '0;
|
||||||
|
req_ready = 1'b0;
|
||||||
|
m_axis_tready = 1'b1;
|
||||||
|
clear_scoreboard();
|
||||||
|
|
||||||
|
repeat(12) @(posedge clk_in);
|
||||||
|
rst = 1'b0;
|
||||||
|
repeat(8) @(posedge clk_in);
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task automatic pulse_start;
|
||||||
|
begin
|
||||||
|
@(posedge clk_in);
|
||||||
|
start <= 1'b1;
|
||||||
|
@(posedge clk_in);
|
||||||
|
start <= 1'b0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task automatic send_one_sample(input logic [DATA_WIDTH-1:0] val);
|
||||||
|
begin
|
||||||
|
@(posedge clk_in);
|
||||||
|
s_axis_tdata <= val;
|
||||||
|
s_axis_tvalid <= 1'b1;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task automatic stop_stream;
|
||||||
|
begin
|
||||||
|
@(posedge clk_in);
|
||||||
|
s_axis_tdata <= '0;
|
||||||
|
s_axis_tvalid <= 1'b0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task automatic run_test(
|
||||||
|
input integer test_id,
|
||||||
|
input integer seq_num_i,
|
||||||
|
input integer smp_num_i,
|
||||||
|
input bit randomize_data,
|
||||||
|
input integer base_value,
|
||||||
|
input string test_name
|
||||||
|
);
|
||||||
|
logic [DATA_WIDTH-1:0] sample_mem [0:MAX_SEQ_NUM-1][0:N_MAX-1];
|
||||||
|
integer seq_idx;
|
||||||
|
integer sample_idx;
|
||||||
|
integer word_idx;
|
||||||
|
integer k;
|
||||||
|
integer exp_word_count;
|
||||||
|
integer exp_packet_count;
|
||||||
|
integer sample_value;
|
||||||
|
integer local_sum;
|
||||||
|
integer timeout_cnt;
|
||||||
|
bit le_ok;
|
||||||
|
bit be_ok;
|
||||||
|
integer errors_before;
|
||||||
|
integer i;
|
||||||
|
begin
|
||||||
|
tests_total = tests_total + 1;
|
||||||
|
errors_before = total_errors;
|
||||||
|
|
||||||
|
if (smp_num_i <= 0 || smp_num_i > N_MAX || (smp_num_i % WINDOW_SIZE) != 0)
|
||||||
|
$fatal(1, "[%0s] invalid smp_num=%0d", test_name, smp_num_i);
|
||||||
|
if (seq_num_i <= 0 || seq_num_i > MAX_SEQ_NUM)
|
||||||
|
$fatal(1, "[%0s] invalid seq_num=%0d", test_name, seq_num_i);
|
||||||
|
|
||||||
|
$display("\n========================================");
|
||||||
|
$display("TEST %0d: %0s", test_id, test_name);
|
||||||
|
$display("seq_num=%0d smp_num=%0d randomize=%0d", seq_num_i, smp_num_i, randomize_data);
|
||||||
|
$display("========================================");
|
||||||
|
|
||||||
|
reset_dut();
|
||||||
|
smp_num = smp_num_i;
|
||||||
|
seq_num = seq_num_i;
|
||||||
|
req_ready = 1'b1; // приемник готов заранее
|
||||||
|
|
||||||
|
exp_word_count = smp_num_i / WINDOW_SIZE;
|
||||||
|
exp_packet_count = (exp_word_count + READ_BATCH_SIZE - 1) / READ_BATCH_SIZE;
|
||||||
|
|
||||||
|
for (seq_idx = 0; seq_idx < seq_num_i; seq_idx = seq_idx + 1) begin
|
||||||
|
for (sample_idx = 0; sample_idx < smp_num_i; sample_idx = sample_idx + 1) begin
|
||||||
|
if (randomize_data)
|
||||||
|
sample_value = $unsigned($random(seed)) % (1 << DATA_WIDTH);
|
||||||
|
else
|
||||||
|
sample_value = (base_value + seq_idx * smp_num_i + sample_idx) % (1 << DATA_WIDTH);
|
||||||
|
sample_mem[seq_idx][sample_idx] = sample_value[DATA_WIDTH-1:0];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for (word_idx = 0; word_idx < exp_word_count; word_idx = word_idx + 1) begin
|
||||||
|
local_sum = 0;
|
||||||
|
for (seq_idx = 0; seq_idx < seq_num_i; seq_idx = seq_idx + 1) begin
|
||||||
|
for (k = 0; k < WINDOW_SIZE; k = k + 1)
|
||||||
|
local_sum = local_sum + sample_mem[seq_idx][word_idx * WINDOW_SIZE + k];
|
||||||
|
end
|
||||||
|
expected_words[word_idx] = local_sum[ACCUM_WIDTH-1:0];
|
||||||
|
$display(" expected[%0d] = %0d (0x%08x)", word_idx, expected_words[word_idx], expected_words[word_idx]);
|
||||||
|
end
|
||||||
|
|
||||||
|
pulse_start();
|
||||||
|
|
||||||
|
for (seq_idx = 0; seq_idx < seq_num_i; seq_idx = seq_idx + 1) begin
|
||||||
|
for (sample_idx = 0; sample_idx < smp_num_i; sample_idx = sample_idx + 1)
|
||||||
|
send_one_sample(sample_mem[seq_idx][sample_idx]);
|
||||||
|
stop_stream();
|
||||||
|
repeat(2) @(posedge clk_in);
|
||||||
|
end
|
||||||
|
|
||||||
|
timeout_cnt = 0;
|
||||||
|
while (packets_seen < exp_packet_count && timeout_cnt < 30000) begin
|
||||||
|
@(posedge eth_clk_in);
|
||||||
|
timeout_cnt = timeout_cnt + 1;
|
||||||
|
end
|
||||||
|
if (packets_seen < exp_packet_count) begin
|
||||||
|
$display("[%0s] ERROR: timeout waiting packets, got=%0d exp=%0d",
|
||||||
|
test_name, packets_seen, exp_packet_count);
|
||||||
|
total_errors = total_errors + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
timeout_cnt = 0;
|
||||||
|
while (finish !== 1'b1 && timeout_cnt < 30000) begin
|
||||||
|
@(posedge clk_in);
|
||||||
|
timeout_cnt = timeout_cnt + 1;
|
||||||
|
end
|
||||||
|
if (finish !== 1'b1) begin
|
||||||
|
$display("[%0s] ERROR: timeout waiting finish", test_name);
|
||||||
|
total_errors = total_errors + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
le_ok = 1'b1;
|
||||||
|
be_ok = 1'b1;
|
||||||
|
for (i = 0; i < exp_word_count; i = i + 1) begin
|
||||||
|
if (captured_words_le[i] !== expected_words[i]) le_ok = 1'b0;
|
||||||
|
if (captured_words_be[i] !== expected_words[i]) be_ok = 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (!le_ok && !be_ok) begin
|
||||||
|
$display("[%0s] ERROR: payload mismatch", test_name);
|
||||||
|
for (i = 0; i < exp_word_count; i = i + 1)
|
||||||
|
$display(" idx=%0d exp=0x%08x le=0x%08x be=0x%08x",
|
||||||
|
i, expected_words[i], captured_words_le[i], captured_words_be[i]);
|
||||||
|
total_errors = total_errors + 1;
|
||||||
|
end else if (le_ok) begin
|
||||||
|
$display("[%0s] payload check passed in little-endian", test_name);
|
||||||
|
end else begin
|
||||||
|
$display("[%0s] payload check passed in big-endian", test_name);
|
||||||
|
end
|
||||||
|
|
||||||
|
if (total_errors == errors_before) begin
|
||||||
|
tests_passed = tests_passed + 1;
|
||||||
|
$display("TEST %0d PASSED: %0s", test_id, test_name);
|
||||||
|
end else begin
|
||||||
|
tests_failed = tests_failed + 1;
|
||||||
|
$display("TEST %0d FAILED: %0s", test_id, test_name);
|
||||||
|
end
|
||||||
|
|
||||||
|
req_ready = 1'b0;
|
||||||
|
repeat(10) @(posedge clk_in);
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
always @(posedge eth_clk_in) begin : CAPTURE_AXIS
|
||||||
|
integer idx;
|
||||||
|
logic [31:0] tmp_le;
|
||||||
|
logic [31:0] tmp_be;
|
||||||
|
if (rst) begin
|
||||||
|
current_packet_byte_count = 0;
|
||||||
|
end else if (m_axis_tvalid && m_axis_tready) begin
|
||||||
|
if (current_packet_byte_count < PACKET_SIZE)
|
||||||
|
packet_bytes[current_packet_byte_count] = m_axis_tdata;
|
||||||
|
current_packet_byte_count = current_packet_byte_count + 1;
|
||||||
|
|
||||||
|
if (m_axis_tlast) begin
|
||||||
|
packets_seen = packets_seen + 1;
|
||||||
|
|
||||||
|
if (current_packet_byte_count != PACKET_SIZE) begin
|
||||||
|
$display("[packet] ERROR: packet size=%0d expected=%0d", current_packet_byte_count, PACKET_SIZE);
|
||||||
|
total_errors = total_errors + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
for (idx = 0; idx < READ_BATCH_SIZE; idx = idx + 1) begin
|
||||||
|
tmp_le = {
|
||||||
|
packet_bytes[idx*4 + 3],
|
||||||
|
packet_bytes[idx*4 + 2],
|
||||||
|
packet_bytes[idx*4 + 1],
|
||||||
|
packet_bytes[idx*4 + 0]
|
||||||
|
};
|
||||||
|
tmp_be = {
|
||||||
|
packet_bytes[idx*4 + 0],
|
||||||
|
packet_bytes[idx*4 + 1],
|
||||||
|
packet_bytes[idx*4 + 2],
|
||||||
|
packet_bytes[idx*4 + 3]
|
||||||
|
};
|
||||||
|
if (total_words_captured + idx < MAX_WORDS) begin
|
||||||
|
captured_words_le[total_words_captured + idx] = tmp_le;
|
||||||
|
captured_words_be[total_words_captured + idx] = tmp_be;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
total_words_captured = total_words_captured + READ_BATCH_SIZE;
|
||||||
|
current_packet_byte_count = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
seed = 32'h1badf00d;
|
||||||
|
total_errors = 0;
|
||||||
|
tests_total = 0;
|
||||||
|
tests_failed = 0;
|
||||||
|
tests_passed = 0;
|
||||||
|
|
||||||
|
reset_dut();
|
||||||
|
|
||||||
|
run_test(1, 2, 8, 1'b0, 1, "deterministic_small");
|
||||||
|
run_test(2, 3, 8, 1'b1, 0, "random_seq3_smp8");
|
||||||
|
run_test(3, 5, 16, 1'b1, 0, "random_seq5_smp16_multi_packet");
|
||||||
|
// run_test(4, 1, 4, 1'b1, 0, "random_single_window");
|
||||||
|
run_test(5, 7, 12, 1'b1, 0, "random_seq7_smp12");
|
||||||
|
run_test(6, 4, 256, 1'b1, 0, "random_max_smpnum");
|
||||||
|
|
||||||
|
$display("\n========================================");
|
||||||
|
$display("ALL TESTS COMPLETED");
|
||||||
|
$display("tests_total = %0d", tests_total);
|
||||||
|
$display("tests_passed = %0d", tests_passed);
|
||||||
|
$display("tests_failed = %0d", tests_failed);
|
||||||
|
$display("total_errors = %0d", total_errors);
|
||||||
|
$display("========================================");
|
||||||
|
|
||||||
|
if (total_errors != 0)
|
||||||
|
$fatal(1, "TB FAILED with %0d error(s)", total_errors);
|
||||||
|
else
|
||||||
|
$display("TB PASSED");
|
||||||
|
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
183
rtl/accum/tests/accum_tb.sv
Normal file
183
rtl/accum/tests/accum_tb.sv
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
module tb_accumulator;
|
||||||
|
|
||||||
|
localparam DATA_WIDTH = 12;
|
||||||
|
localparam ACCUM_WIDTH = 32;
|
||||||
|
localparam N_MAX = 64;
|
||||||
|
localparam WINDOW_SIZE = 4;
|
||||||
|
localparam PACKET_SIZE = 8; // bytes
|
||||||
|
localparam READ_BATCH_SIZE = (PACKET_SIZE*8)/ACCUM_WIDTH; // = 2
|
||||||
|
|
||||||
|
reg clk_in;
|
||||||
|
reg rst;
|
||||||
|
reg [DATA_WIDTH-1:0] s_axis_tdata;
|
||||||
|
reg s_axis_tvalid;
|
||||||
|
reg start;
|
||||||
|
reg [31:0] smp_num;
|
||||||
|
reg [15:0] seq_num;
|
||||||
|
wire [ACCUM_WIDTH-1:0] out_data;
|
||||||
|
wire out_valid;
|
||||||
|
wire readout_begin;
|
||||||
|
reg batch_req;
|
||||||
|
reg finish;
|
||||||
|
|
||||||
|
integer i;
|
||||||
|
integer out_count;
|
||||||
|
|
||||||
|
reg [ACCUM_WIDTH-1:0] expected [0:READ_BATCH_SIZE-1];
|
||||||
|
reg [ACCUM_WIDTH-1:0] got [0:READ_BATCH_SIZE-1];
|
||||||
|
|
||||||
|
accumulator #(
|
||||||
|
.DATA_WIDTH(DATA_WIDTH),
|
||||||
|
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||||
|
.N_MAX(N_MAX),
|
||||||
|
.WINDOW_SIZE(WINDOW_SIZE),
|
||||||
|
.PACKET_SIZE(PACKET_SIZE)
|
||||||
|
) dut (
|
||||||
|
.clk_in(clk_in),
|
||||||
|
.rst(rst),
|
||||||
|
.s_axis_tdata(s_axis_tdata),
|
||||||
|
.s_axis_tvalid(s_axis_tvalid),
|
||||||
|
.start(start),
|
||||||
|
.smp_num(smp_num),
|
||||||
|
.seq_num(seq_num),
|
||||||
|
.out_data(out_data),
|
||||||
|
.out_valid(out_valid),
|
||||||
|
.readout_begin(readout_begin),
|
||||||
|
.batch_req(batch_req),
|
||||||
|
.finish(finish)
|
||||||
|
);
|
||||||
|
|
||||||
|
// clock 100 MHz
|
||||||
|
initial begin
|
||||||
|
clk_in = 0;
|
||||||
|
forever #5 clk_in = ~clk_in;
|
||||||
|
end
|
||||||
|
|
||||||
|
// send one sample
|
||||||
|
task send_sample(input [DATA_WIDTH-1:0] val);
|
||||||
|
begin
|
||||||
|
@(posedge clk_in);
|
||||||
|
s_axis_tdata <= val;
|
||||||
|
s_axis_tvalid <= 1'b1;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
// one idle cycle after valid stream
|
||||||
|
task end_stream;
|
||||||
|
begin
|
||||||
|
@(posedge clk_in);
|
||||||
|
s_axis_tvalid <= 1'b0;
|
||||||
|
s_axis_tdata <= '0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
// pulse start
|
||||||
|
task pulse_start;
|
||||||
|
begin
|
||||||
|
@(posedge clk_in);
|
||||||
|
start <= 1'b1;
|
||||||
|
@(posedge clk_in);
|
||||||
|
start <= 1'b0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
// pulse batch request
|
||||||
|
task pulse_batch_req;
|
||||||
|
begin
|
||||||
|
@(posedge clk_in);
|
||||||
|
batch_req <= 1'b1;
|
||||||
|
@(posedge clk_in);
|
||||||
|
batch_req <= 1'b0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
repeat(100) @(posedge clk_in);
|
||||||
|
// init
|
||||||
|
rst = 1'b1;
|
||||||
|
s_axis_tdata = '0;
|
||||||
|
s_axis_tvalid= 1'b0;
|
||||||
|
start = 1'b0;
|
||||||
|
smp_num = 32'd8;
|
||||||
|
seq_num = 16'd2;
|
||||||
|
batch_req = 1'b0;
|
||||||
|
finish = 1'b0;
|
||||||
|
|
||||||
|
expected[0] = 32'd60;
|
||||||
|
expected[1] = 32'd92;
|
||||||
|
|
||||||
|
repeat(50) @(posedge clk_in);
|
||||||
|
rst = 1'b0;
|
||||||
|
repeat(50) @(posedge clk_in);
|
||||||
|
|
||||||
|
$display("=== TEST START ===");
|
||||||
|
|
||||||
|
pulse_start();
|
||||||
|
|
||||||
|
// seq 0: [1..8]
|
||||||
|
send_sample(12'd1);
|
||||||
|
send_sample(12'd2);
|
||||||
|
send_sample(12'd3);
|
||||||
|
send_sample(12'd4);
|
||||||
|
send_sample(12'd5);
|
||||||
|
send_sample(12'd6);
|
||||||
|
send_sample(12'd7);
|
||||||
|
send_sample(12'd8);
|
||||||
|
end_stream();
|
||||||
|
|
||||||
|
// небольшой зазор
|
||||||
|
repeat(5) @(posedge clk_in);
|
||||||
|
|
||||||
|
// seq 1: [11..18]
|
||||||
|
send_sample(12'd11);
|
||||||
|
send_sample(12'd12);
|
||||||
|
send_sample(12'd13);
|
||||||
|
send_sample(12'd14);
|
||||||
|
send_sample(12'd15);
|
||||||
|
send_sample(12'd16);
|
||||||
|
send_sample(12'd17);
|
||||||
|
send_sample(12'd18);
|
||||||
|
end_stream();
|
||||||
|
|
||||||
|
$display("[%0t] all input data sent, waiting readout_begin...", $time);
|
||||||
|
|
||||||
|
wait(readout_begin == 1'b1);
|
||||||
|
$display("[%0t] readout_begin asserted", $time);
|
||||||
|
repeat(22) @(posedge clk_in);
|
||||||
|
pulse_batch_req();
|
||||||
|
|
||||||
|
out_count = 0;
|
||||||
|
|
||||||
|
// ждём два слова
|
||||||
|
while (out_count < READ_BATCH_SIZE) begin
|
||||||
|
@(posedge clk_in);
|
||||||
|
if (out_valid) begin
|
||||||
|
got[out_count] = out_data;
|
||||||
|
$display("[%0t] out_valid: got[%0d] = %0d", $time, out_count, out_data);
|
||||||
|
out_count = out_count + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// проверка
|
||||||
|
for (i = 0; i < READ_BATCH_SIZE; i = i + 1) begin
|
||||||
|
if (got[i] !== expected[i]) begin
|
||||||
|
$error("Mismatch at index %0d: got=%0d expected=%0d", i, got[i], expected[i]);
|
||||||
|
end else begin
|
||||||
|
$display("OK index %0d: %0d", i, got[i]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// завершаем readout
|
||||||
|
@(posedge clk_in);
|
||||||
|
finish <= 1'b1;
|
||||||
|
|
||||||
|
|
||||||
|
repeat(10) @(posedge clk_in);
|
||||||
|
|
||||||
|
$display("=== TEST PASSED ===");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
Reference in New Issue
Block a user