tests: add simple tb for accum output fifo

This commit is contained in:
Phil
2026-04-17 21:51:00 +03:00
parent 4786d2d7f6
commit 7f9ad95e68
2 changed files with 250 additions and 0 deletions

52
rtl/accum/tests/Makefile Normal file
View File

@ -0,0 +1,52 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xc7a35tfgg484-1
FPGA_TOP = control
FPGA_ARCH = artix7
RTL_DIR = ../src
include ../../../scripts/vivado.mk
SYN_FILES += $(sort $(shell find ../src -type f \( -name '*.v' -o -name '*.sv' \)))
XCI_FILES = $(sort $(shell find ../src -type f -name '*.xci'))
XDC_FILES += ../../../constraints/ax7a035b.xdc
# XDC_FILES += test_timing.xdc
# SYN_FILES += controller_tb.sv
# SIM_TOP = control_tb
program: $(PROJECT).bit
echo "open_hw_manager" > program.tcl
echo "connect_hw_server" >> program.tcl
echo "open_hw_target" >> program.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl
echo "set_property PROGRAM.FILE {$(PROJECT).bit} [current_hw_device]" >> program.tcl
echo "program_hw_devices [current_hw_device]" >> program.tcl
echo "exit" >> program.tcl
vivado -nojournal -nolog -mode batch -source program.tcl
$(PROJECT).mcs $(PROJECT).prm: $(PROJECT).bit
echo "write_cfgmem -force -format mcs -size 16 -interface SPIx4 -loadbit {up 0x0000000 $*.bit} -checksum -file $*.mcs" > generate_mcs.tcl
echo "exit" >> generate_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;

View File

@ -0,0 +1,198 @@
`timescale 1ns/1ps
module tb_out_axis_fifo;
localparam int ACCUM_WIDTH = 32;
localparam int WINDOW_SIZE = 65;
localparam int PACKET_SIZE = 1024;
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 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),
.batch_req (batch_req),
.finish (finish)
);
// -----------------------------
// clocks
// -----------------------------
initial begin
eth_clk_in = 0;
forever #4 eth_clk_in = ~eth_clk_in; // 125 MHz
end
initial begin
acc_clk_in = 0;
forever #3 acc_clk_in = ~acc_clk_in; // ~166.7 MHz
end
// -----------------------------
// simple AXIS sink
// -----------------------------
initial begin
s_axis_tready = 1'b1;
end
// У DUT нет своей логики rd_en, поэтому для теста подадим её force-ом.
initial begin
force dut.rd_en = dut.s_axis_tvalid && s_axis_tready;
end
// -----------------------------
// helpers
// -----------------------------
task automatic do_reset();
begin
rst = 1'b1;
readout_begin = 1'b0;
din_valid = 1'b0;
acc_din = '0;
smp_num = '0;
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;
begin
for (i = 0; i < n_words; i++) begin
@(posedge acc_clk_in);
din_valid <= 1'b1;
acc_din <= $urandom;
end
@(posedge acc_clk_in);
din_valid <= 1'b0;
acc_din <= '0;
end
endtask
// Один запуск:
// 1) задаём smp_num
// 2) даём readout_begin
// 3) каждый раз, когда DUT просит batch_req, отправляем PACKET_SIZE слов
// 4) ждём finish
task automatic run_case(input logic [31:0] smp_num_i);
int batch_count;
begin
batch_count = 0;
$display("[%0t] run_case start, smp_num=%0d", $time, smp_num_i);
pulse_readout_begin(smp_num_i);
while (finish !== 1'b1) begin
@(posedge acc_clk_in);
if (batch_req) begin
batch_count++;
$display("[%0t] batch_req #%0d -> send %0d words",
$time, batch_count, PACKET_SIZE / ACCUM_WIDTH * 8);
// send packets to accomplish 1kb packet.
send_random_words(PACKET_SIZE / ACCUM_WIDTH * 8);
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);
@(posedge acc_clk_in);
end
endtask
// -----------------------------
// monitor
// -----------------------------
int axis_byte_count;
always_ff @(posedge eth_clk_in or posedge rst) begin
if (rst) begin
axis_byte_count <= 0;
end else begin
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;
// 1-й запуск
do_reset();
run_case(32'd17);
// 2-й запуск
do_reset();
run_case(32'd1024);
// 3-й запуск
do_reset();
run_case(32'd77777);
do_reset();
repeat (50) @(posedge acc_clk_in);
$display("[%0t] ALL TESTS DONE", $time);
$finish;
end
endmodule