`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