1// 2// Copyright 2020 Ettus Research, A National Instruments Brand 3// 4// SPDX-License-Identifier: LGPL-3.0-or-later 5// 6// Module: rfnoc_block_null_src_sink_tb 7// 8 9`default_nettype none 10 11 12module rfnoc_block_null_src_sink_tb #( 13 parameter TEST_NAME = "rfnoc_block_null_src_sink_tb", 14 parameter CHDR_W = 64 15)( 16 /* no IO */ 17); 18 19 // Include macros and time declarations for use with PkgTestExec 20 `define TEST_EXEC_OBJ test 21 `include "test_exec.svh" 22 23 import PkgTestExec::*; 24 import PkgChdrUtils::*; 25 import PkgRfnocBlockCtrlBfm::*; 26 import PkgRfnocItemUtils::*; 27 28 // Parameters 29 localparam NOC_ID = 32'h0000_0001; 30 localparam [9:0] THIS_PORTID = 10'h17; 31 localparam [15:0] THIS_EPID = 16'hDEAD; 32 localparam int ITEM_W = 32; 33 localparam int NIPC = CHDR_W/ITEM_W; // Expected Data generation only works for full words 34 localparam int SPP = 201; 35 localparam int LPP = SPP % NIPC == 0 ? SPP/NIPC : SPP/NIPC+1; 36 localparam int NUM_PKTS = 50; 37 38 localparam int PORT_SRCSNK = 0; 39 localparam int PORT_LOOP = 1; 40 41 // Clock and Reset Definition 42 bit rfnoc_chdr_clk; 43 sim_clock_gen #(2.5) rfnoc_chdr_clk_gen (rfnoc_chdr_clk); // 400 MHz 44 45 // ---------------------------------------- 46 // Instantiate DUT 47 // ---------------------------------------- 48 49 // Connections to DUT as interfaces: 50 RfnocBackendIf backend (rfnoc_chdr_clk, rfnoc_chdr_clk); // Required backend iface 51 AxiStreamIf #(32) m_ctrl (rfnoc_chdr_clk); // Required control iface 52 AxiStreamIf #(32) s_ctrl (rfnoc_chdr_clk); // Required control iface 53 AxiStreamIf #(CHDR_W) m0_chdr (rfnoc_chdr_clk); // Optional data iface 54 AxiStreamIf #(CHDR_W) m1_chdr (rfnoc_chdr_clk); // Optional data iface 55 AxiStreamIf #(CHDR_W) s0_chdr (rfnoc_chdr_clk); // Optional data iface 56 AxiStreamIf #(CHDR_W) s1_chdr (rfnoc_chdr_clk); // Optional data iface 57 58 TestExec test = new(); 59 60 typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t; 61 62 // Bus functional model for a software block controller 63 RfnocBlockCtrlBfm #(.CHDR_W(CHDR_W)) blk_ctrl; 64 65 // DUT 66 rfnoc_block_null_src_sink #( 67 .THIS_PORTID (THIS_PORTID), 68 .CHDR_W (CHDR_W), 69 .ITEM_W (ITEM_W), 70 .NIPC (NIPC), 71 .MTU (10) 72 ) dut ( 73 .rfnoc_chdr_clk (backend.chdr_clk), 74 .rfnoc_ctrl_clk (backend.ctrl_clk), 75 .rfnoc_core_config (backend.cfg), 76 .rfnoc_core_status (backend.sts), 77 .s_rfnoc_chdr_tdata ({m1_chdr.tdata , m0_chdr.tdata }), 78 .s_rfnoc_chdr_tlast ({m1_chdr.tlast , m0_chdr.tlast }), 79 .s_rfnoc_chdr_tvalid({m1_chdr.tvalid , m0_chdr.tvalid }), 80 .s_rfnoc_chdr_tready({m1_chdr.tready , m0_chdr.tready }), 81 .m_rfnoc_chdr_tdata ({s1_chdr.tdata , s0_chdr.tdata }), 82 .m_rfnoc_chdr_tlast ({s1_chdr.tlast , s0_chdr.tlast }), 83 .m_rfnoc_chdr_tvalid({s1_chdr.tvalid, s0_chdr.tvalid}), 84 .m_rfnoc_chdr_tready({s1_chdr.tready, s0_chdr.tready}), 85 .s_rfnoc_ctrl_tdata (m_ctrl.tdata ), 86 .s_rfnoc_ctrl_tlast (m_ctrl.tlast ), 87 .s_rfnoc_ctrl_tvalid(m_ctrl.tvalid ), 88 .s_rfnoc_ctrl_tready(m_ctrl.tready ), 89 .m_rfnoc_ctrl_tdata (s_ctrl.tdata ), 90 .m_rfnoc_ctrl_tlast (s_ctrl.tlast ), 91 .m_rfnoc_ctrl_tvalid(s_ctrl.tvalid), 92 .m_rfnoc_ctrl_tready(s_ctrl.tready) 93 ); 94 95 // ---------------------------------------- 96 // Test Process 97 // ---------------------------------------- 98 99 initial begin 100 // Shared Variables 101 // ---------------------------------------- 102 timeout_t timeout; 103 ctrl_word_t rvalue; 104 105 // Initialize 106 // ---------------------------------------- 107 test.start_tb({TEST_NAME,"rfnoc_block_null_src_sink_tb"}); 108 109 // Start the stream endpoint BFM 110 blk_ctrl = new(backend, m_ctrl, s_ctrl); 111 blk_ctrl.add_master_data_port(m0_chdr); 112 blk_ctrl.add_slave_data_port(s0_chdr); 113 blk_ctrl.add_master_data_port(m1_chdr); 114 blk_ctrl.add_slave_data_port(s1_chdr); 115 blk_ctrl.run(); 116 117 // Startup block (Software initialization) 118 // ---------------------------------------- 119 test.start_test({TEST_NAME,"Flush block then reset it"}); 120 begin 121 test.start_timeout(timeout, 10us, "Waiting for flush_and_reset"); 122 #100; //Wait for GSR to deassert 123 blk_ctrl.flush_and_reset(); 124 test.end_timeout(timeout); 125 end 126 test.end_test(); 127 128 // Run Tests 129 // ---------------------------------------- 130 test.start_test({TEST_NAME,"Read Block Info"}); 131 begin 132 test.start_timeout(timeout, 1us, "Waiting for block info response"); 133 // Get static block info and validate it 134 `ASSERT_ERROR(blk_ctrl.get_noc_id() == NOC_ID, "Incorrect noc_id Value"); 135 `ASSERT_ERROR(blk_ctrl.get_num_data_i() == 2, "Incorrect num_data_i Value"); 136 `ASSERT_ERROR(blk_ctrl.get_num_data_o() == 2, "Incorrect num_data_o Value"); 137 `ASSERT_ERROR(blk_ctrl.get_ctrl_fifosize() == 5, "Incorrect ctrl_fifosize Value"); 138 `ASSERT_ERROR(blk_ctrl.get_mtu() == 10, "Incorrect mtu Value"); 139 140 // Read status register and validate it 141 blk_ctrl.reg_read(dut.REG_CTRL_STATUS, rvalue); 142 `ASSERT_ERROR(rvalue[31:24] == NIPC, "Incorrect NIPC Value"); 143 `ASSERT_ERROR(rvalue[23:16] == ITEM_W, "Incorrect ITEM_W Value"); 144 test.end_timeout(timeout); 145 end 146 test.end_test(); 147 148 test.start_test({TEST_NAME,"Stream Data Through Loopback Port m1->s1"}); 149 begin 150 // Send and receive packets 151 repeat (NUM_PKTS) begin 152 chdr_word_t rx_data[$]; 153 int rx_bytes; 154 automatic ItemDataBuff #(logic[ITEM_W-1:0],CHDR_W) tx_dbuff = new; 155 automatic ItemDataBuff #(logic[ITEM_W-1:0],CHDR_W) rx_dbuff = new; 156 for (int i = 0; i < SPP; i++) 157 tx_dbuff.put($urandom()); 158 test.start_timeout(timeout, 5us, "Waiting for pkt to loop back"); 159 blk_ctrl.send(PORT_LOOP, tx_dbuff.to_chdr_payload(), tx_dbuff.get_bytes()); 160 blk_ctrl.recv(PORT_LOOP, rx_data, rx_bytes); 161 rx_dbuff.from_chdr_payload(rx_data, rx_bytes); 162 `ASSERT_ERROR(rx_dbuff.equal(tx_dbuff), "Data mismatch"); 163 test.end_timeout(timeout); 164 end 165 166 // Read item and packet counts on loopback port 167 blk_ctrl.reg_read(dut.REG_LOOP_LINE_CNT_LO, rvalue); 168 `ASSERT_ERROR(rvalue == (LPP*NUM_PKTS), "Incorrect REG_LOOP_LINE_CNT_LO value"); 169 blk_ctrl.reg_read(dut.REG_LOOP_PKT_CNT_LO, rvalue); 170 `ASSERT_ERROR(rvalue == NUM_PKTS, "Incorrect REG_LOOP_PKT_CNT_LO value"); 171 172 // Read item and packet counts on source port 173 blk_ctrl.reg_read(dut.REG_SRC_LINE_CNT_LO, rvalue); 174 `ASSERT_ERROR(rvalue == 0, "Incorrect REG_SRC_LINE_CNT_LO value"); 175 blk_ctrl.reg_read(dut.REG_SRC_PKT_CNT_LO, rvalue); 176 `ASSERT_ERROR(rvalue == 0, "Incorrect REG_SRC_PKT_CNT_LO value"); 177 178 // Read item and packet counts on sink port 179 blk_ctrl.reg_read(dut.REG_SNK_LINE_CNT_LO, rvalue); 180 `ASSERT_ERROR(rvalue == 0, "Incorrect REG_SNK_LINE_CNT_LO value"); 181 blk_ctrl.reg_read(dut.REG_SNK_PKT_CNT_LO, rvalue); 182 `ASSERT_ERROR(rvalue == 0, "Incorrect REG_SNK_PKT_CNT_LO value"); 183 end 184 test.end_test(); 185 186 test.start_test({TEST_NAME,"Stream Data To Sink Port m0"}); 187 begin 188 // Send packets 189 repeat (NUM_PKTS) begin 190 chdr_word_t rx_data[$]; 191 int rx_bytes; 192 automatic ItemDataBuff #(logic[ITEM_W-1:0],CHDR_W) tx_dbuff = new; 193 for (int i = 0; i < SPP; i++) 194 tx_dbuff.put($urandom()); 195 test.start_timeout(timeout, 5us, "Waiting to send packet"); 196 blk_ctrl.send(PORT_SRCSNK, tx_dbuff.to_chdr_payload(), tx_dbuff.get_bytes()); 197 test.end_timeout(timeout); 198 end 199 repeat (NUM_PKTS * SPP * 2) @(posedge rfnoc_chdr_clk); 200 201 // Read item and packet counts on loopback port 202 blk_ctrl.reg_read(dut.REG_LOOP_LINE_CNT_LO, rvalue); 203 `ASSERT_ERROR(rvalue == (LPP*NUM_PKTS), "Incorrect REG_LOOP_LINE_CNT_LO value"); 204 blk_ctrl.reg_read(dut.REG_LOOP_PKT_CNT_LO, rvalue); 205 `ASSERT_ERROR(rvalue == NUM_PKTS, "Incorrect REG_LOOP_PKT_CNT_LO value"); 206 207 // Read item and packet counts on source port 208 blk_ctrl.reg_read(dut.REG_SRC_LINE_CNT_LO, rvalue); 209 `ASSERT_ERROR(rvalue == 0, "Incorrect REG_SRC_LINE_CNT_LO value"); 210 blk_ctrl.reg_read(dut.REG_SRC_PKT_CNT_LO, rvalue); 211 `ASSERT_ERROR(rvalue == 0, "Incorrect REG_SRC_PKT_CNT_LO value"); 212 213 // Read item and packet counts on sink port 214 blk_ctrl.reg_read(dut.REG_SNK_LINE_CNT_LO, rvalue); 215 `ASSERT_ERROR(rvalue == (LPP*NUM_PKTS), "Incorrect REG_SNK_LINE_CNT_LO value"); 216 blk_ctrl.reg_read(dut.REG_SNK_PKT_CNT_LO, rvalue); 217 `ASSERT_ERROR(rvalue == NUM_PKTS, "Incorrect REG_SNK_PKT_CNT_LO value"); 218 end 219 test.end_test(); 220 221 test.start_test({TEST_NAME,"Stream Data From Source Port s0"}); 222 begin 223 // Turn on the source for some time then stop it 224 blk_ctrl.reg_write(dut.REG_SRC_LINES_PER_PKT, LPP-1); 225 // A line is generated as NIPC Items 226 blk_ctrl.reg_write(dut.REG_SRC_BYTES_PER_PKT, (LPP+1)*ITEM_W/8*NIPC); 227 blk_ctrl.reg_write(dut.REG_CTRL_STATUS, 2'b10); 228 repeat ((NUM_PKTS / 10) * LPP) @(posedge rfnoc_chdr_clk); 229 blk_ctrl.reg_write(dut.REG_CTRL_STATUS, 2'b00); 230 blk_ctrl.reg_read(dut.REG_SRC_PKT_CNT_LO, rvalue); 231 repeat (rvalue * LPP * 2) @(posedge rfnoc_chdr_clk); 232 blk_ctrl.reg_read(dut.REG_SRC_PKT_CNT_LO, rvalue); 233 234 // Gather the accumulated packets and verify contents 235 for (int p = 0; p < rvalue; p++) begin 236 chdr_word_t exp_data[$]; 237 chdr_word_t rx_data[$]; 238 int rx_bytes; 239 test.start_timeout(timeout, 5us, "Waiting for pkt to arrive"); 240 exp_data.delete(); 241 for (int i = p*LPP; i < (p+1)*LPP; i++) 242 exp_data.push_back({NIPC{{~i[ITEM_W/2-1:0], i[ITEM_W/2-1:0]}}}); 243 blk_ctrl.recv(PORT_SRCSNK, rx_data, rx_bytes); 244 `ASSERT_ERROR(blk_ctrl.compare_data(exp_data, rx_data), "Data mismatch"); 245 test.end_timeout(timeout); 246 end 247 end 248 test.end_test(); 249 250 test.start_test({TEST_NAME,"Clear Counts"}); 251 begin 252 test.start_timeout(timeout, 1us, "Waiting for clear and readbacks"); 253 // Clear 254 blk_ctrl.reg_write(dut.REG_CTRL_STATUS, 2'b01); 255 256 // Read item and packet counts on loopback port 257 blk_ctrl.reg_read(dut.REG_LOOP_LINE_CNT_LO, rvalue); 258 `ASSERT_ERROR(rvalue == 0, "Incorrect REG_LOOP_LINE_CNT_LO value"); 259 blk_ctrl.reg_read(dut.REG_LOOP_PKT_CNT_LO, rvalue); 260 `ASSERT_ERROR(rvalue == 0, "Incorrect REG_LOOP_PKT_CNT_LO value"); 261 262 // Read item and packet counts on source port 263 blk_ctrl.reg_read(dut.REG_SRC_LINE_CNT_LO, rvalue); 264 `ASSERT_ERROR(rvalue == 0, "Incorrect REG_SRC_LINE_CNT_LO value"); 265 blk_ctrl.reg_read(dut.REG_SRC_PKT_CNT_LO, rvalue); 266 `ASSERT_ERROR(rvalue == 0, "Incorrect REG_SRC_PKT_CNT_LO value"); 267 268 // Read item and packet counts on sink port 269 blk_ctrl.reg_read(dut.REG_SNK_LINE_CNT_LO, rvalue); 270 `ASSERT_ERROR(rvalue == 0, "Incorrect REG_SNK_LINE_CNT_LO value"); 271 blk_ctrl.reg_read(dut.REG_SNK_PKT_CNT_LO, rvalue); 272 `ASSERT_ERROR(rvalue == 0, "Incorrect REG_SNK_PKT_CNT_LO value"); 273 test.end_timeout(timeout); 274 end 275 test.end_test(); 276 277 // Finish Up 278 // ---------------------------------------- 279 // Display final statistics and results 280 test.end_tb(.finish(0)); 281 end 282 283endmodule 284