diff options
Diffstat (limited to 'fpga/usrp3')
19 files changed, 568 insertions, 389 deletions
diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/Makefile b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/Makefile index 30ce14aec..4d2e33633 100644 --- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/Makefile +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/Makefile @@ -29,10 +29,11 @@ $(RFNOC_OOT_SRCS) \ #------------------------------------------------- # Testbench Specific #------------------------------------------------- -SIM_TOP = rfnoc_block_null_src_sink_tb +SIM_TOP = rfnoc_block_null_src_sink_all_tb SIM_SRCS = \ $(abspath rfnoc_block_null_src_sink_tb.sv) \ +$(abspath rfnoc_block_null_src_sink_all_tb.sv) \ # MODELSIM_USER_DO = $(abspath wave.do) diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/noc_shell_null_src_sink.v b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/noc_shell_null_src_sink.v index cef213920..3676ffbd3 100644 --- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/noc_shell_null_src_sink.v +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/noc_shell_null_src_sink.v @@ -23,6 +23,8 @@ module noc_shell_null_src_sink #( parameter [9:0] THIS_PORTID = 10'd0, parameter CHDR_W = 64, + parameter ITEM_W = 32, + parameter NIPC = 2, parameter [5:0] MTU = 10 ) ( //--------------------- @@ -82,8 +84,8 @@ module noc_shell_null_src_sink #( output wire axis_data_clk, output wire axis_data_rst, // Payload Stream to User Logic: sink - output wire [32*2-1:0] m_sink_payload_tdata, - output wire [2-1:0] m_sink_payload_tkeep, + output wire [ITEM_W*NIPC-1:0] m_sink_payload_tdata, + output wire [NIPC-1:0] m_sink_payload_tkeep, output wire m_sink_payload_tlast, output wire m_sink_payload_tvalid, input wire m_sink_payload_tready, @@ -94,8 +96,8 @@ module noc_shell_null_src_sink #( output wire m_sink_context_tvalid, input wire m_sink_context_tready, // Payload Stream to User Logic: loop - output wire [32*2-1:0] m_loop_payload_tdata, - output wire [2-1:0] m_loop_payload_tkeep, + output wire [ITEM_W*NIPC-1:0] m_loop_payload_tdata, + output wire [NIPC-1:0] m_loop_payload_tkeep, output wire m_loop_payload_tlast, output wire m_loop_payload_tvalid, input wire m_loop_payload_tready, @@ -106,8 +108,8 @@ module noc_shell_null_src_sink #( output wire m_loop_context_tvalid, input wire m_loop_context_tready, // Payload Stream from User Logic: source - input wire [32*2-1:0] s_source_payload_tdata, - input wire [1:0] s_source_payload_tkeep, + input wire [ITEM_W*NIPC-1:0] s_source_payload_tdata, + input wire [NIPC-1:0] s_source_payload_tkeep, input wire s_source_payload_tlast, input wire s_source_payload_tvalid, output wire s_source_payload_tready, @@ -118,8 +120,8 @@ module noc_shell_null_src_sink #( input wire s_source_context_tvalid, output wire s_source_context_tready, // Payload Stream from User Logic: loop - input wire [32*2-1:0] s_loop_payload_tdata, - input wire [1:0] s_loop_payload_tkeep, + input wire [ITEM_W*NIPC-1:0] s_loop_payload_tdata, + input wire [NIPC-1:0] s_loop_payload_tkeep, input wire s_loop_payload_tlast, input wire s_loop_payload_tvalid, output wire s_loop_payload_tready, @@ -233,8 +235,8 @@ module noc_shell_null_src_sink #( chdr_to_axis_pyld_ctxt #( .CHDR_W (CHDR_W), - .ITEM_W (32), - .NIPC (2), + .ITEM_W (ITEM_W), + .NIPC (NIPC), .SYNC_CLKS (1), .CONTEXT_FIFO_SIZE ($clog2(2)), .PAYLOAD_FIFO_SIZE ($clog2(2)), @@ -266,8 +268,8 @@ module noc_shell_null_src_sink #( chdr_to_axis_pyld_ctxt #( .CHDR_W (CHDR_W), - .ITEM_W (32), - .NIPC (2), + .ITEM_W (ITEM_W), + .NIPC (NIPC), .SYNC_CLKS (1), .CONTEXT_FIFO_SIZE ($clog2(2)), .PAYLOAD_FIFO_SIZE ($clog2(2)), @@ -303,8 +305,8 @@ module noc_shell_null_src_sink #( axis_pyld_ctxt_to_chdr #( .CHDR_W (CHDR_W), - .ITEM_W (32), - .NIPC (2), + .ITEM_W (ITEM_W), + .NIPC (NIPC), .SYNC_CLKS (1), .CONTEXT_FIFO_SIZE ($clog2(2)), .PAYLOAD_FIFO_SIZE ($clog2(2)), @@ -338,8 +340,8 @@ module noc_shell_null_src_sink #( axis_pyld_ctxt_to_chdr #( .CHDR_W (CHDR_W), - .ITEM_W (32), - .NIPC (2), + .ITEM_W (ITEM_W), + .NIPC (NIPC), .SYNC_CLKS (1), .CONTEXT_FIFO_SIZE ($clog2(2)), .PAYLOAD_FIFO_SIZE ($clog2(2)), diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink.v b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink.v index 53c764627..9e1cdb117 100644 --- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink.v +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink.v @@ -4,30 +4,46 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // // Module: rfnoc_block_null_src_sink +// // Description: // +// This block can source, sink, or loopback data. Each port is used for a +// specific purpose. The RFNoC CHDR ports are mapped is as follows: +// +// Input Port 0 : Sink +// Input Port 1 : Loopback in +// Output Port 0 : Source +// Output Port 1 : Loopback out +// // Parameters: +// THIS_PORTID : Control crossbar port to which this block is connected +// CHDR_W : AXIS-CHDR data bus width +// MTU : Maximum transmission unit (i.e., maximum packet size in +// CHDR words is 2**MTU). +// ITEM_W : Item width +// NIPC : Items per Clock // // Signals: module rfnoc_block_null_src_sink #( parameter [9:0] THIS_PORTID = 10'd0, parameter CHDR_W = 64, - parameter NIPC = 2, - parameter [5:0] MTU = 10 + parameter [5:0] MTU = 10, + parameter ITEM_W = 32, + parameter NIPC = CHDR_W/ITEM_W )( // RFNoC Framework Clocks and Resets input wire rfnoc_chdr_clk, input wire rfnoc_ctrl_clk, - // RFNoC Backend Interface + // RFNoC Backend Interface input wire [511:0] rfnoc_core_config, output wire [511:0] rfnoc_core_status, - // 2 CHDR Input Ports (from framework) + // 2 CHDR Input Ports (from framework) input wire [(CHDR_W*2)-1:0] s_rfnoc_chdr_tdata, input wire [1:0] s_rfnoc_chdr_tlast, input wire [1:0] s_rfnoc_chdr_tvalid, output wire [1:0] s_rfnoc_chdr_tready, - // 2 CHDR Output Ports (to framework) + // 2 CHDR Output Ports (to framework) output wire [(CHDR_W*2)-1:0] m_rfnoc_chdr_tdata, output wire [1:0] m_rfnoc_chdr_tlast, output wire [1:0] m_rfnoc_chdr_tvalid, @@ -72,22 +88,24 @@ module rfnoc_block_null_src_sink #( reg ctrlport_resp_ack; reg [31:0] ctrlport_resp_data; - wire [(32*NIPC)-1:0] src_pyld_tdata , loop_pyld_tdata ; - wire [NIPC-1:0] src_pyld_tkeep , loop_pyld_tkeep ; - wire src_pyld_tlast , snk_pyld_tlast , loop_pyld_tlast ; - wire src_pyld_tvalid, snk_pyld_tvalid, loop_pyld_tvalid; - wire src_pyld_tready, snk_pyld_tready, loop_pyld_tready; + wire [(ITEM_W*NIPC)-1:0] src_pyld_tdata , loop_pyld_tdata ; + wire [NIPC-1:0] src_pyld_tkeep , loop_pyld_tkeep ; + wire src_pyld_tlast , snk_pyld_tlast , loop_pyld_tlast ; + wire src_pyld_tvalid, snk_pyld_tvalid, loop_pyld_tvalid; + wire src_pyld_tready, snk_pyld_tready, loop_pyld_tready; - wire [CHDR_W-1:0] src_ctxt_tdata , loop_ctxt_tdata ; - wire [3:0] src_ctxt_tuser , loop_ctxt_tuser ; - wire src_ctxt_tlast , loop_ctxt_tlast ; - wire src_ctxt_tvalid, loop_ctxt_tvalid; - wire src_ctxt_tready, snk_ctxt_tready, loop_ctxt_tready; + wire [CHDR_W-1:0] src_ctxt_tdata , loop_ctxt_tdata ; + wire [3:0] src_ctxt_tuser , loop_ctxt_tuser ; + wire src_ctxt_tlast , loop_ctxt_tlast ; + wire src_ctxt_tvalid, loop_ctxt_tvalid; + wire src_ctxt_tready, snk_ctxt_tready, loop_ctxt_tready; // NoC Shell // --------------------------- noc_shell_null_src_sink #( .THIS_PORTID (THIS_PORTID), + .NIPC (NIPC), + .ITEM_W (ITEM_W), .CHDR_W (CHDR_W), .MTU (MTU) ) noc_shell_null_src_sink_i ( @@ -257,18 +275,17 @@ module rfnoc_block_null_src_sink #( end end - assign src_pyld_tdata = {NIPC{{~src_line_cnt[15:0], src_line_cnt[15:0]}}}; + assign src_pyld_tdata = {NIPC{{~src_line_cnt[ITEM_W/2-1:0], src_line_cnt[ITEM_W/2-1:0]}}}; assign src_pyld_tkeep = {NIPC{1'b1}}; assign src_pyld_tlast = (lines_left == 12'd0); assign src_pyld_tvalid = (state == ST_PYLD); assign src_ctxt_tdata = chdr_build_header( 6'd0, 1'b0, 1'b0, CHDR_PKT_TYPE_DATA, CHDR_NO_MDATA, src_pkt_cnt[15:0], reg_src_bpp, 16'd0); - assign src_ctxt_tuser = CONTEXT_FIELD_HDR; + assign src_ctxt_tuser = CHDR_W > 64 ? CONTEXT_FIELD_HDR_TS : CONTEXT_FIELD_HDR; assign src_ctxt_tlast = 1'b1; assign src_ctxt_tvalid = (state == ST_HDR && reg_src_en); - // Register Interface // --------------------------- always @(posedge rfnoc_chdr_clk) begin @@ -294,7 +311,7 @@ module rfnoc_block_null_src_sink #( if (ctrlport_req_rd) begin case(ctrlport_req_addr) REG_CTRL_STATUS: - ctrlport_resp_data <= {NIPC[7:0], 8'd32, state, 12'h0, reg_src_en, reg_clear_cnts}; + ctrlport_resp_data <= {NIPC[7:0],ITEM_W[7:0], state, 12'h0, reg_src_en, reg_clear_cnts}; REG_SRC_LINES_PER_PKT: ctrlport_resp_data <= {20'h0, reg_src_lpp}; REG_SRC_BYTES_PER_PKT: diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink_all_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink_all_tb.sv new file mode 100644 index 000000000..ed5745a44 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink_all_tb.sv @@ -0,0 +1,26 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: chdr_stream_endpoint_all_tb +// +// Description: Testbench for chdr_stream_endpoint that runs multiple widths +// + +module rfnoc_block_null_src_sink_all_tb#( + /* no PARAM */ +)( + /* no IO */ +); + + rfnoc_block_null_src_sink_tb #(.TEST_NAME("64B"),.CHDR_W(64)) CHDR64 (); + rfnoc_block_null_src_sink_tb #(.TEST_NAME("512B"),.CHDR_W(512)) CHDR512 (); + + // Wait for all done + bit clk,rst; + sim_clock_gen #(100.0) clk_gen (clk, rst); + always_ff@(posedge clk) + if (CHDR64.test.done && CHDR512.test.done) $finish(1); + +endmodule diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink_tb.sv index 192a8143b..2ef2e31ea 100644 --- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink_tb.sv +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink_tb.sv @@ -1,5 +1,5 @@ // -// Copyright 2019 Ettus Research, A National Instruments Company +// Copyright 2020 Ettus Research, A National Instruments Brand // // SPDX-License-Identifier: LGPL-3.0-or-later // @@ -9,9 +9,15 @@ `default_nettype none -module rfnoc_block_null_src_sink_tb; +module rfnoc_block_null_src_sink_tb #( + parameter TEST_NAME = "rfnoc_block_null_src_sink_tb", + parameter CHDR_W = 64 +)( + /* no IO */ +); // Include macros and time declarations for use with PkgTestExec + `define TEST_EXEC_OBJ test `include "test_exec.svh" import PkgTestExec::*; @@ -23,10 +29,10 @@ module rfnoc_block_null_src_sink_tb; localparam NOC_ID = 32'h0000_0001; localparam [9:0] THIS_PORTID = 10'h17; localparam [15:0] THIS_EPID = 16'hDEAD; - localparam int CHDR_W = 64; - localparam int ITEM_W = 32; + localparam int ITEM_W = 32; + localparam int NIPC = CHDR_W/ITEM_W; // Expected Data generation only works for full words localparam int SPP = 201; - localparam int LPP = ((SPP+1)/2); + localparam int LPP = SPP % NIPC == 0 ? SPP/NIPC : SPP/NIPC+1; localparam int NUM_PKTS = 50; localparam int PORT_SRCSNK = 0; @@ -49,6 +55,8 @@ module rfnoc_block_null_src_sink_tb; AxiStreamIf #(CHDR_W) s0_chdr (rfnoc_chdr_clk); // Optional data iface AxiStreamIf #(CHDR_W) s1_chdr (rfnoc_chdr_clk); // Optional data iface + TestExec test = new(); + typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t; // Bus functional model for a software block controller @@ -58,29 +66,30 @@ module rfnoc_block_null_src_sink_tb; rfnoc_block_null_src_sink #( .THIS_PORTID (THIS_PORTID), .CHDR_W (CHDR_W), - .NIPC (2), + .ITEM_W (ITEM_W), + .NIPC (NIPC), .MTU (10) ) dut ( .rfnoc_chdr_clk (backend.chdr_clk), .rfnoc_ctrl_clk (backend.ctrl_clk), - .rfnoc_core_config (backend.slave.cfg), - .rfnoc_core_status (backend.slave.sts), - .s_rfnoc_chdr_tdata ({m1_chdr.slave.tdata , m0_chdr.slave.tdata }), - .s_rfnoc_chdr_tlast ({m1_chdr.slave.tlast , m0_chdr.slave.tlast }), - .s_rfnoc_chdr_tvalid({m1_chdr.slave.tvalid , m0_chdr.slave.tvalid }), - .s_rfnoc_chdr_tready({m1_chdr.slave.tready , m0_chdr.slave.tready }), - .m_rfnoc_chdr_tdata ({s1_chdr.master.tdata , s0_chdr.master.tdata }), - .m_rfnoc_chdr_tlast ({s1_chdr.master.tlast , s0_chdr.master.tlast }), - .m_rfnoc_chdr_tvalid({s1_chdr.master.tvalid, s0_chdr.master.tvalid}), - .m_rfnoc_chdr_tready({s1_chdr.master.tready, s0_chdr.master.tready}), - .s_rfnoc_ctrl_tdata (m_ctrl.slave.tdata ), - .s_rfnoc_ctrl_tlast (m_ctrl.slave.tlast ), - .s_rfnoc_ctrl_tvalid(m_ctrl.slave.tvalid ), - .s_rfnoc_ctrl_tready(m_ctrl.slave.tready ), - .m_rfnoc_ctrl_tdata (s_ctrl.master.tdata ), - .m_rfnoc_ctrl_tlast (s_ctrl.master.tlast ), - .m_rfnoc_ctrl_tvalid(s_ctrl.master.tvalid), - .m_rfnoc_ctrl_tready(s_ctrl.master.tready) + .rfnoc_core_config (backend.cfg), + .rfnoc_core_status (backend.sts), + .s_rfnoc_chdr_tdata ({m1_chdr.tdata , m0_chdr.tdata }), + .s_rfnoc_chdr_tlast ({m1_chdr.tlast , m0_chdr.tlast }), + .s_rfnoc_chdr_tvalid({m1_chdr.tvalid , m0_chdr.tvalid }), + .s_rfnoc_chdr_tready({m1_chdr.tready , m0_chdr.tready }), + .m_rfnoc_chdr_tdata ({s1_chdr.tdata , s0_chdr.tdata }), + .m_rfnoc_chdr_tlast ({s1_chdr.tlast , s0_chdr.tlast }), + .m_rfnoc_chdr_tvalid({s1_chdr.tvalid, s0_chdr.tvalid}), + .m_rfnoc_chdr_tready({s1_chdr.tready, s0_chdr.tready}), + .s_rfnoc_ctrl_tdata (m_ctrl.tdata ), + .s_rfnoc_ctrl_tlast (m_ctrl.tlast ), + .s_rfnoc_ctrl_tvalid(m_ctrl.tvalid ), + .s_rfnoc_ctrl_tready(m_ctrl.tready ), + .m_rfnoc_ctrl_tdata (s_ctrl.tdata ), + .m_rfnoc_ctrl_tlast (s_ctrl.tlast ), + .m_rfnoc_ctrl_tvalid(s_ctrl.tvalid), + .m_rfnoc_ctrl_tready(s_ctrl.tready) ); // ---------------------------------------- @@ -95,7 +104,7 @@ module rfnoc_block_null_src_sink_tb; // Initialize // ---------------------------------------- - test.start_tb("rfnoc_block_null_src_sink_tb"); + test.start_tb({TEST_NAME,"rfnoc_block_null_src_sink_tb"}); // Start the stream endpoint BFM blk_ctrl = new(backend, m_ctrl, s_ctrl); @@ -107,7 +116,7 @@ module rfnoc_block_null_src_sink_tb; // Startup block (Software initialization) // ---------------------------------------- - test.start_test("Flush block then reset it"); + test.start_test({TEST_NAME,"Flush block then reset it"}); begin test.start_timeout(timeout, 10us, "Waiting for flush_and_reset"); #100; //Wait for GSR to deassert @@ -118,7 +127,7 @@ module rfnoc_block_null_src_sink_tb; // Run Tests // ---------------------------------------- - test.start_test("Read Block Info"); + test.start_test({TEST_NAME,"Read Block Info"}); begin test.start_timeout(timeout, 1us, "Waiting for block info response"); // Get static block info and validate it @@ -130,19 +139,20 @@ module rfnoc_block_null_src_sink_tb; // Read status register and validate it blk_ctrl.reg_read(dut.REG_CTRL_STATUS, rvalue); - `ASSERT_ERROR(rvalue[31:24] == 2, "Incorrect NIPC Value"); + `ASSERT_ERROR(rvalue[31:24] == NIPC, "Incorrect NIPC Value"); `ASSERT_ERROR(rvalue[23:16] == ITEM_W, "Incorrect ITEM_W Value"); test.end_timeout(timeout); end test.end_test(); - test.start_test("Stream Data Through Loopback Port"); + test.start_test({TEST_NAME,"Stream Data Through Loopback Port m1->s1"}); begin // Send and receive packets repeat (NUM_PKTS) begin chdr_word_t rx_data[$]; int rx_bytes; - automatic ItemDataBuff #(logic[ITEM_W-1:0]) tx_dbuff = new, rx_dbuff = new; + automatic ItemDataBuff #(logic[ITEM_W-1:0],CHDR_W) tx_dbuff = new; + automatic ItemDataBuff #(logic[ITEM_W-1:0],CHDR_W) rx_dbuff = new; for (int i = 0; i < SPP; i++) tx_dbuff.put($urandom()); test.start_timeout(timeout, 5us, "Waiting for pkt to loop back"); @@ -173,16 +183,16 @@ module rfnoc_block_null_src_sink_tb; end test.end_test(); - test.start_test("Stream Data To Sink Port"); + test.start_test({TEST_NAME,"Stream Data To Sink Port m0"}); begin // Send packets repeat (NUM_PKTS) begin chdr_word_t rx_data[$]; int rx_bytes; - automatic ItemDataBuff #(logic[ITEM_W-1:0]) tx_dbuff = new; + automatic ItemDataBuff #(logic[ITEM_W-1:0],CHDR_W) tx_dbuff = new; for (int i = 0; i < SPP; i++) tx_dbuff.put($urandom()); - test.start_timeout(timeout, 5us, "Waiting for pkt to loop back"); + test.start_timeout(timeout, 5us, "Waiting to send packet"); blk_ctrl.send(PORT_SRCSNK, tx_dbuff.to_chdr_payload(), tx_dbuff.get_bytes()); test.end_timeout(timeout); end @@ -208,11 +218,12 @@ module rfnoc_block_null_src_sink_tb; end test.end_test(); - test.start_test("Stream Data From Source Port"); + test.start_test({TEST_NAME,"Stream Data From Source Port s0"}); begin // Turn on the source for some time then stop it blk_ctrl.reg_write(dut.REG_SRC_LINES_PER_PKT, LPP-1); - blk_ctrl.reg_write(dut.REG_SRC_BYTES_PER_PKT, (LPP+1)*8); + // A line is generated as NIPC Items + blk_ctrl.reg_write(dut.REG_SRC_BYTES_PER_PKT, (LPP+1)*ITEM_W/8*NIPC); blk_ctrl.reg_write(dut.REG_CTRL_STATUS, 2'b10); repeat ((NUM_PKTS / 10) * LPP) @(posedge rfnoc_chdr_clk); blk_ctrl.reg_write(dut.REG_CTRL_STATUS, 2'b00); @@ -228,7 +239,7 @@ module rfnoc_block_null_src_sink_tb; test.start_timeout(timeout, 5us, "Waiting for pkt to arrive"); exp_data.delete(); for (int i = p*LPP; i < (p+1)*LPP; i++) - exp_data.push_back({~i[15:0], i[15:0], ~i[15:0], i[15:0]}); + exp_data.push_back({NIPC{{~i[ITEM_W/2-1:0], i[ITEM_W/2-1:0]}}}); blk_ctrl.recv(PORT_SRCSNK, rx_data, rx_bytes); `ASSERT_ERROR(blk_ctrl.compare_data(exp_data, rx_data), "Data mismatch"); test.end_timeout(timeout); @@ -236,7 +247,7 @@ module rfnoc_block_null_src_sink_tb; end test.end_test(); - test.start_test("Clear Counts"); + test.start_test({TEST_NAME,"Clear Counts"}); begin test.start_timeout(timeout, 1us, "Waiting for clear and readbacks"); // Clear @@ -266,7 +277,7 @@ module rfnoc_block_null_src_sink_tb; // Finish Up // ---------------------------------------- // Display final statistics and results - test.end_tb(); + test.end_tb(.finish(0)); end endmodule diff --git a/fpga/usrp3/lib/rfnoc/core/chdr_stream_output.v b/fpga/usrp3/lib/rfnoc/core/chdr_stream_output.v index 271c7fccc..c21649d44 100644 --- a/fpga/usrp3/lib/rfnoc/core/chdr_stream_output.v +++ b/fpga/usrp3/lib/rfnoc/core/chdr_stream_output.v @@ -411,7 +411,7 @@ module chdr_stream_output #( if (CHDR_W < 128) state <= ST_STRC_W1; else - state <= ST_STRC_WAIT; + state <= fc_resync_req ? ST_PASS_DATA : ST_STRC_WAIT; end // ST_STRC_W1 @@ -527,7 +527,7 @@ module chdr_stream_output #( assign msg_o_tready = msg_o_tvalid && (state == ST_PASS_DATA || state == ST_STRC_WAIT); // Acknowledge a flow control resync command - assign fc_resync_ack = fc_resync_req && (state == ST_STRC_W1) && + assign fc_resync_ack = fc_resync_req && (state == ST_STRC_W1 || state == ST_STRC_W0) && chdr_out_tvalid && chdr_out_tready && chdr_out_tlast; // --------------------------------------------------- diff --git a/fpga/usrp3/lib/rfnoc/core/chdr_to_axis_ctrl.v b/fpga/usrp3/lib/rfnoc/core/chdr_to_axis_ctrl.v index 1f9dba2eb..130915de2 100644 --- a/fpga/usrp3/lib/rfnoc/core/chdr_to_axis_ctrl.v +++ b/fpga/usrp3/lib/rfnoc/core/chdr_to_axis_ctrl.v @@ -116,7 +116,7 @@ module chdr_to_axis_ctrl #( ST_CHDR_HDR: begin ch2ct_nmdata <= chdr_get_num_mdata(ch2ct_tdata[63:0]) - 5'd1; if (!ch2ct_tlast) - ch2ct_state <= (chdr_get_num_mdata(ch2ct_tdata[63:0]) == 5'd0) ? + ch2ct_state <= (chdr_get_num_mdata(ch2ct_tdata[63:0]) == 5'd0) ? ST_CTRL_HDR : ST_CHDR_MDATA; else ch2ct_state <= ST_CHDR_HDR; // Premature termination @@ -152,7 +152,7 @@ module chdr_to_axis_ctrl #( ); // Create the first two lines of the Ctrl word (wide) - // using data from CHDR packet + // using data from CHDR packet wire [CHDR_W-1:0] ch2ct_new_ctrl_hdr; assign ch2ct_new_ctrl_hdr[63:0] = { axis_ctrl_build_hdr_hi( @@ -172,7 +172,7 @@ module chdr_to_axis_ctrl #( assign ch2ct_new_ctrl_hdr[CHDR_W-1:64] = ch2ct_tdata[CHDR_W-1:64]; end endgenerate - wire [CHDR_W-1:0] ch2ct_wctrl_tdata = + wire [CHDR_W-1:0] ch2ct_wctrl_tdata = (ch2ct_state == ST_CTRL_HDR) ? ch2ct_new_ctrl_hdr : ch2ct_tdata; axis_width_conv #( @@ -205,7 +205,7 @@ module chdr_to_axis_ctrl #( // - Use the Ctrl RemDstPort as the CHDR DstPort (forward the master's request) // - Use the this_epid as CHDR SrcEPID (return path for the CHDR packet) // - Use the Ctrl SrcPort as the CHDR SrcPort (return path to the master) - // - Ignore the Ctrl DstPort because the packet has already been routed + // - Ignore the Ctrl DstPort because the packet has already been routed wire [CHDR_W-1:0] ct2ch_wctrl_tdata; wire ct2ch_wctrl_tlast, ct2ch_wctrl_tvalid, ct2ch_wctrl_tready; @@ -238,8 +238,7 @@ module chdr_to_axis_ctrl #( end else if (ct2ch_tvalid && ct2ch_tready) begin case (ct2ch_state) ST_CHDR_HDR: begin - if (!ct2ch_tlast) - ct2ch_state <= ST_CTRL_HDR; + ct2ch_state <= ST_CTRL_HDR; end ST_CTRL_HDR: begin if (ct2ch_tlast) @@ -264,56 +263,60 @@ module chdr_to_axis_ctrl #( // Hold the first line to generate info for the outgoing CHDR header assign ct2ch_wctrl_tready = (ct2ch_state == ST_CTRL_HDR || ct2ch_state == ST_CTRL_BODY) ? ct2ch_tready : 1'b0; - wire [7:0] ct2ch_32bit_lines = 8'd3 + // Header + OpWord - (axis_ctrl_get_has_time(ct2ch_wctrl_tdata[31:0]) ? 8'd2 : 8'd0) + // Timestamp - ({4'h0, axis_ctrl_get_num_data(ct2ch_wctrl_tdata[31:0])}); // Data words + wire [7:0] ct2ch_num_data = {4'h0, axis_ctrl_get_num_data(ct2ch_wctrl_tdata[31:0])}; + wire [7:0] ct2ch_timestamp = axis_ctrl_get_has_time(ct2ch_wctrl_tdata[31:0]) ? 8'd2 : 8'd0; + wire [7:0] ct2ch_32bit_lines = CHDR_W/32 + // CHDR header + 8'd3 + // CTL Header + OpWord + ct2ch_timestamp + // Timestamp + ct2ch_num_data; // Data words - wire [15:0] ct2ch_chdr_lines = 16'd1 + // CHDR header - ct2ch_32bit_lines[7:$clog2(CHDR_W/32)] + // Convert 32-bit lines to CHDR_W - (|ct2ch_32bit_lines[$clog2(CHDR_W/32)-1:0]); // Residue + reg [CHDR_W-1:0] ct2ch_sm_tdata,ct2ch_chdr_hdr; + reg [63:0] ct2ch_ctrl_hdr; - reg [63:0] ct2ch_chdr_tdata; + always @(*) begin + ct2ch_chdr_hdr = 0; + ct2ch_chdr_hdr = chdr_build_header( + 6'd0, /* VC */ + 1'b0, 1'b0, /* eob, eov */ + CHDR_PKT_TYPE_CTRL, + CHDR_NO_MDATA, + ct2ch_seqnum, + (ct2ch_32bit_lines << $clog2(32/8)), /* length in bytes */ + axis_ctrl_get_rem_dst_epid(ct2ch_wctrl_tdata[63:32])); + ct2ch_ctrl_hdr = { + axis_ctrl_build_hdr_hi( + 10'd0, /* Unused in CHDR Control payload */ + this_epid /* This is the SrcEPID */ + ), + axis_ctrl_build_hdr_lo( + axis_ctrl_get_is_ack (ct2ch_wctrl_tdata[31:0]), + axis_ctrl_get_has_time(ct2ch_wctrl_tdata[31:0]), + axis_ctrl_get_seq_num (ct2ch_wctrl_tdata[31:0]), + axis_ctrl_get_num_data(ct2ch_wctrl_tdata[31:0]), + axis_ctrl_get_src_port(ct2ch_wctrl_tdata[31:0]), + axis_ctrl_get_rem_dst_port(ct2ch_wctrl_tdata[63:32]) + ) + }; + end always @(*) begin case (ct2ch_state) ST_CHDR_HDR: begin - ct2ch_chdr_tdata = chdr_build_header( - 6'd0, /* VC */ - 1'b0, 1'b0, /* eob, eov */ - CHDR_PKT_TYPE_CTRL, - CHDR_NO_MDATA, - ct2ch_seqnum, - (ct2ch_chdr_lines << $clog2(CHDR_W/8)), /* length in bytes */ - axis_ctrl_get_rem_dst_epid(ct2ch_wctrl_tdata[63:32]) - ); + // regardless of width CHDR is always a full word + ct2ch_sm_tdata = ct2ch_chdr_hdr; end ST_CTRL_HDR: begin - ct2ch_chdr_tdata = { - axis_ctrl_build_hdr_hi( - 10'd0, /* Unused in CHDR Control payload */ - this_epid /* This is the SrcEPID */ - ), - axis_ctrl_build_hdr_lo( - axis_ctrl_get_is_ack (ct2ch_wctrl_tdata[31:0]), - axis_ctrl_get_has_time(ct2ch_wctrl_tdata[31:0]), - axis_ctrl_get_seq_num (ct2ch_wctrl_tdata[31:0]), - axis_ctrl_get_num_data(ct2ch_wctrl_tdata[31:0]), - axis_ctrl_get_src_port(ct2ch_wctrl_tdata[31:0]), - axis_ctrl_get_rem_dst_port(ct2ch_wctrl_tdata[63:32]) - ) - }; + ct2ch_sm_tdata = ct2ch_wctrl_tdata; + ct2ch_sm_tdata[63:0] = ct2ch_ctrl_hdr; end default: begin - ct2ch_chdr_tdata = ct2ch_wctrl_tdata[63:0]; + ct2ch_sm_tdata = ct2ch_wctrl_tdata; end endcase end // Output signals - assign ct2ch_tdata[63:0] = ct2ch_chdr_tdata; - assign ct2ch_tlast = ct2ch_wctrl_tlast; + assign ct2ch_tdata = ct2ch_sm_tdata; + assign ct2ch_tlast = ct2ch_wctrl_tlast && (ct2ch_state != ST_CHDR_HDR); assign ct2ch_tvalid = ct2ch_wctrl_tvalid; - generate if (CHDR_W > 64) begin - assign ct2ch_tdata[CHDR_W-1:64] = ct2ch_wctrl_tdata[CHDR_W-1:64]; - end endgenerate endmodule // chdr_to_axis_ctrl diff --git a/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_crossbar_nxn_tb/Makefile b/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_crossbar_nxn_tb/Makefile index 399515640..cbeacc387 100644 --- a/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_crossbar_nxn_tb/Makefile +++ b/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_crossbar_nxn_tb/Makefile @@ -34,9 +34,10 @@ $(RFNOC_CORE_SRCS) \ # Testbench Specific #------------------------------------------------- # Define only one toplevel module -SIM_TOP = chdr_crossbar_nxn_tb +SIM_TOP = chdr_crossbar_nxn_all_tb SIM_SRCS = \ +$(abspath chdr_crossbar_nxn_all_tb.sv) \ $(abspath chdr_crossbar_nxn_tb.sv) \ $(abspath ../crossbar_tb.sv) \ $(abspath ../chdr_traffic_source_sim.sv) \ diff --git a/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_crossbar_nxn_tb/chdr_crossbar_nxn_all_tb.sv b/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_crossbar_nxn_tb/chdr_crossbar_nxn_all_tb.sv new file mode 100644 index 000000000..9dbaa2568 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_crossbar_nxn_tb/chdr_crossbar_nxn_all_tb.sv @@ -0,0 +1,26 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: chdr_crossbar_nxn +// +// Description: Testbench for chdr_crossbar_nxn that runs multiple widths +// + +module chdr_crossbar_nxn_all_tb#( + /* no PARAM */ +)( + /* no IO */ +); + + chdr_crossbar_nxn_tb #(.TEST_NAME("64B"),.CHDR_W(64)) CHDR64 (); + chdr_crossbar_nxn_tb #(.TEST_NAME("512B"),.CHDR_W(512)) CHDR512 (); + + // Wait for all done + bit clk,rst; + sim_clock_gen #(100.0) clk_gen (clk, rst); + always_ff@(posedge clk) + if (CHDR64.impl.done && CHDR512.impl.done) $finish(1); + +endmodule diff --git a/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_crossbar_nxn_tb/chdr_crossbar_nxn_tb.sv b/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_crossbar_nxn_tb/chdr_crossbar_nxn_tb.sv index 1c5cace63..f5217c66f 100644 --- a/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_crossbar_nxn_tb/chdr_crossbar_nxn_tb.sv +++ b/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_crossbar_nxn_tb/chdr_crossbar_nxn_tb.sv @@ -6,12 +6,17 @@ `timescale 1ns/1ps -module chdr_crossbar_nxn_tb(); +module chdr_crossbar_nxn_tb#( + parameter TEST_NAME = "chdr_crossbar_nxn_tb", + parameter CHDR_W = 64 +)( + /* no IO */ +); crossbar_tb #( - .TEST_NAME ("chdr_crossbar_nxn_tb"), + .TEST_NAME (TEST_NAME ), .ROUTER_IMPL ("chdr_crossbar_nxn" ), // Router implementation .ROUTER_PORTS (10 ), // Number of ports - .ROUTER_DWIDTH (64 ), // Router datapath width + .ROUTER_DWIDTH (CHDR_W ), // Router datapath width .MTU_LOG2 (7 ), // log2 of max packet size for router .NUM_MASTERS (10 ), // Number of data generators in test .TEST_MAX_PACKETS (100 ), // How many packets to stream per test case? diff --git a/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_traffic_sink_sim.sv b/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_traffic_sink_sim.sv index a9fe3ba27..c6af03582 100644 --- a/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_traffic_sink_sim.sv +++ b/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_traffic_sink_sim.sv @@ -88,7 +88,7 @@ module chdr_traffic_sink_sim #( s_chdr.reset(); while (1) begin // A session begins on the posedge of start_stb - while (~start_stb) @(posedge clk); + while (start_stb !== 1) @(posedge clk); session = session + 1; $sformat(filename, "%s/pkts_node%05d_inj%03d_lpp%05d_traffic%c_sess%04d.csv", FILE_PATH, NODE_ID, injection_rate, lines_per_pkt, traffic_patt, session); diff --git a/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_traffic_source_sim.sv b/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_traffic_source_sim.sv index e6cb7c5d9..8f8e2665d 100644 --- a/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_traffic_source_sim.sv +++ b/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/chdr_traffic_source_sim.sv @@ -107,7 +107,7 @@ module chdr_traffic_source_sim #( m_chdr.reset(); while (1) begin // A generation session begins on the posedge of start_stb - while (~start_stb) @(posedge clk); + while (start_stb !== 1) @(posedge clk); curr_pkt_num = 'd0; m_chdr.reset(); num_samps_xferd = 'd0; diff --git a/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/crossbar_tb.sv b/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/crossbar_tb.sv index fc9d53fe7..33b09dfd5 100644 --- a/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/crossbar_tb.sv +++ b/fpga/usrp3/lib/rfnoc/crossbar/crossbar_tb/crossbar_tb.sv @@ -58,12 +58,18 @@ module crossbar_tb #( //---------------------------------------------------- // Instantiate traffic generators, checkers, buses //---------------------------------------------------- - localparam FILE_PATH = {`WORKING_DIR, "/data/", ROUTER_IMPL}; + `ifndef WORKING_DIR + // For XSim + localparam FILE_PATH = {`WORKING_DIR, "/data/", ROUTER_IMPL}; + `else + // For ModelSim + localparam FILE_PATH = {"./work", "/data/", ROUTER_IMPL}; + `endif // Data buses axis_t #(.DWIDTH(ROUTER_DWIDTH), .NUM_STREAMS(ROUTER_PORTS)) src2rtr_axis (.clk(clk)); axis_t #(.DWIDTH(ROUTER_DWIDTH), .NUM_STREAMS(ROUTER_PORTS)) rtr2snk_axis (.clk(clk)); - + // Control buses settings_bus_master #(.SR_AWIDTH(16), .SR_DWIDTH(32)) rtr_sb (.clk(clk)); wire rtr_sb_ack; @@ -75,6 +81,7 @@ module crossbar_tb #( logic [31:0] set_num_pkts_to_send; logic snk_start_stb = 0; logic src_start_stb = 0; + bit done = 0; wire [63:0] session_duration [0:ROUTER_PORTS-1]; wire [ROUTER_PORTS-1:0] src_active; @@ -99,7 +106,7 @@ module crossbar_tb #( .MTU (MTU_LOG2), .NODE_ID (i), .NUM_NODES (ROUTER_PORTS) - ) traffic_src ( + ) traffic_src ( .clk (clk), .rst (rst), .current_time (timestamp), @@ -117,14 +124,14 @@ module crossbar_tb #( .xfer_count (src_xfer_count[i]), .pkt_count (src_pkt_count[i]) ); - + chdr_traffic_sink_sim #( .WIDTH (ROUTER_DWIDTH), .MTU (MTU_LOG2), .NODE_ID (i), .NUM_NODES (ROUTER_PORTS), .FILE_PATH (TEST_GEN_LL_FILES==1 ? FILE_PATH : "") - ) traffic_sink ( + ) traffic_sink ( .clk (clk), .rst (rst), .current_time (timestamp), @@ -152,8 +159,8 @@ module crossbar_tb #( axi_fifo #( .WIDTH(ROUTER_DWIDTH+1), .SIZE(0) ) fifo_i ( - .clk (clk), - .reset (rst), + .clk (clk), + .reset (rst), .clear (1'b0), .i_tdata ({src2rtr_axis.tlast[i], src2rtr_axis.tdata[((i+1)*ROUTER_DWIDTH)-1:i*ROUTER_DWIDTH]}), .i_tvalid (src2rtr_axis.tvalid[i]), @@ -178,7 +185,7 @@ module crossbar_tb #( .reset (rst), .clear (1'b0), .local_addr (8'd0), - // Inputs + // Inputs .i_tdata (src2rtr_axis.tdata), .i_tlast (src2rtr_axis.tlast), .i_tvalid (src2rtr_axis.tvalid), @@ -210,7 +217,7 @@ module crossbar_tb #( .NPORTS_MGMT (0), .EXT_RTCFG_PORT (1) ) router_dut_i ( - // General + // General .clk (clk), .reset (rst), // Inputs @@ -242,12 +249,12 @@ module crossbar_tb #( // General .clk (clk), .reset (rst), - // Inputs + // Inputs .s_axis_tdata (src2rtr_axis.tdata), .s_axis_tlast (src2rtr_axis.tlast), .s_axis_tvalid (src2rtr_axis.tvalid), .s_axis_tready (src2rtr_axis.tready), - // Output + // Output .m_axis_tdata (rtr2snk_axis.tdata), .m_axis_tlast (rtr2snk_axis.tlast), .m_axis_tvalid (rtr2snk_axis.tvalid), @@ -313,7 +320,7 @@ module crossbar_tb #( @(posedge clk); if (deadlock_re) $display("WARNING: Deadlock detected"); if (deadlock_fe) $display("Recovered from deadlock"); - end + end // Wait for sink blocks to finish consuming $display("All packets transmitted. Waiting to flush..."); while (|snk_active) @(posedge clk); @@ -423,6 +430,7 @@ module crossbar_tb #( `TEST_CASE_DONE(1) `TEST_BENCH_DONE + done = 1; end // initial begin endmodule diff --git a/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/Makefile b/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/Makefile index b2773db02..d7152134d 100644 --- a/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/Makefile +++ b/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/Makefile @@ -29,11 +29,12 @@ $(RFNOC_XBAR_SRCS) \ #------------------------------------------------- # Testbench Specific #------------------------------------------------- -SIM_TOP = chdr_stream_endpoint_tb +SIM_TOP = chdr_stream_endpoint_all_tb SIM_SRCS = \ $(abspath lossy_xport_model.v) \ $(abspath chdr_stream_endpoint_tb.sv) \ +$(abspath chdr_stream_endpoint_all_tb.sv) \ #------------------------------------------------- # Bottom-of-Makefile diff --git a/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/chdr_stream_endpoint_all_tb.sv b/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/chdr_stream_endpoint_all_tb.sv new file mode 100644 index 000000000..c382be654 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/chdr_stream_endpoint_all_tb.sv @@ -0,0 +1,26 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: chdr_stream_endpoint_all_tb +// +// Description: Testbench for chdr_stream_endpoint that runs multiple widths +// + +module chdr_stream_endpoint_all_tb#( + /* no PARAM */ +)( + /* no IO */ +); + + chdr_stream_endpoint_tb #(.TEST_NAME("64B"),.CHDR_W(64)) CHDR64 (); + chdr_stream_endpoint_tb #(.TEST_NAME("512B"),.CHDR_W(512)) CHDR512 (); + + // Wait for all done + bit clk,rst; + sim_clock_gen #(100.0) clk_gen (clk, rst); + always_ff@(posedge clk) + if (CHDR64.test.done && CHDR512.test.done) $finish(1); + +endmodule diff --git a/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/chdr_stream_endpoint_tb.sv b/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/chdr_stream_endpoint_tb.sv index 34bf10707..daa7bf522 100644 --- a/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/chdr_stream_endpoint_tb.sv +++ b/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/chdr_stream_endpoint_tb.sv @@ -1,5 +1,5 @@ // -// Copyright 2019 Ettus Research, A National Instruments Company +// Copyright 2020 Ettus Research, A National Instruments Brand // // SPDX-License-Identifier: LGPL-3.0-or-later // @@ -8,14 +8,18 @@ `default_nettype none - -module chdr_stream_endpoint_tb; - +module chdr_stream_endpoint_tb#( + parameter TEST_NAME = "chdr_stream_endpoint_tb", + parameter CHDR_W = 64 +)( + /* no IO */ +); // ---------------------------------------- // Global settings // ---------------------------------------- - + // Include macros and time declarations for use with PkgTestExec + `define TEST_EXEC_OBJ test `include "test_exec.svh" import PkgTestExec::*; @@ -34,7 +38,6 @@ module chdr_stream_endpoint_tb; localparam int FAST_STALL_PROB = 0; localparam int SLOW_STALL_PROB = 35; - localparam int CHDR_W = 64; localparam int MTU = 7; localparam [15:0] PROTOVER = {8'd1, 8'd0}; localparam [15:0] DEV_ID = 16'hBEEF; @@ -108,14 +111,14 @@ module chdr_stream_endpoint_tb; .m_axis_chdr_tlast (a2c_chdr_tlast ), .m_axis_chdr_tvalid (a2c_chdr_tvalid ), .m_axis_chdr_tready (a2c_chdr_tready ), - .s_axis_data_tdata ({m_a1_data.slave.tdata , m_a0_data.slave.tdata }), - .s_axis_data_tlast ({m_a1_data.slave.tlast , m_a0_data.slave.tlast }), - .s_axis_data_tvalid ({m_a1_data.slave.tvalid , m_a0_data.slave.tvalid }), - .s_axis_data_tready ({m_a1_data.slave.tready , m_a0_data.slave.tready }), - .m_axis_data_tdata ({s_a1_data.master.tdata , s_a0_data.master.tdata }), - .m_axis_data_tlast ({s_a1_data.master.tlast , s_a0_data.master.tlast }), - .m_axis_data_tvalid ({s_a1_data.master.tvalid, s_a0_data.master.tvalid}), - .m_axis_data_tready ({s_a1_data.master.tready, s_a0_data.master.tready}), + .s_axis_data_tdata ({m_a1_data.tdata , m_a0_data.tdata }), + .s_axis_data_tlast ({m_a1_data.tlast , m_a0_data.tlast }), + .s_axis_data_tvalid ({m_a1_data.tvalid , m_a0_data.tvalid }), + .s_axis_data_tready ({m_a1_data.tready , m_a0_data.tready }), + .m_axis_data_tdata ({s_a1_data.tdata , s_a0_data.tdata }), + .m_axis_data_tlast ({s_a1_data.tlast , s_a0_data.tlast }), + .m_axis_data_tvalid ({s_a1_data.tvalid, s_a0_data.tvalid}), + .m_axis_data_tready ({s_a1_data.tready, s_a0_data.tready}), .s_axis_ctrl_tdata (a_ctrl_out_tdata ), .s_axis_ctrl_tlast (a_ctrl_loop_tlast ), .s_axis_ctrl_tvalid (a_ctrl_loop_tvalid ), @@ -157,14 +160,14 @@ module chdr_stream_endpoint_tb; .m_axis_chdr_tlast (b2c_chdr_tlast ), .m_axis_chdr_tvalid (b2c_chdr_tvalid ), .m_axis_chdr_tready (b2c_chdr_tready ), - .s_axis_data_tdata ({m_b1_data.slave.tdata , m_b0_data.slave.tdata }), - .s_axis_data_tlast ({m_b1_data.slave.tlast , m_b0_data.slave.tlast }), - .s_axis_data_tvalid ({m_b1_data.slave.tvalid , m_b0_data.slave.tvalid }), - .s_axis_data_tready ({m_b1_data.slave.tready , m_b0_data.slave.tready }), - .m_axis_data_tdata ({s_b1_data.master.tdata , s_b0_data.master.tdata }), - .m_axis_data_tlast ({s_b1_data.master.tlast , s_b0_data.master.tlast }), - .m_axis_data_tvalid ({s_b1_data.master.tvalid, s_b0_data.master.tvalid}), - .m_axis_data_tready ({s_b1_data.master.tready, s_b0_data.master.tready}), + .s_axis_data_tdata ({m_b1_data.tdata , m_b0_data.tdata }), + .s_axis_data_tlast ({m_b1_data.tlast , m_b0_data.tlast }), + .s_axis_data_tvalid ({m_b1_data.tvalid , m_b0_data.tvalid }), + .s_axis_data_tready ({m_b1_data.tready , m_b0_data.tready }), + .m_axis_data_tdata ({s_b1_data.tdata , s_b0_data.tdata }), + .m_axis_data_tlast ({s_b1_data.tlast , s_b0_data.tlast }), + .m_axis_data_tvalid ({s_b1_data.tvalid, s_b0_data.tvalid}), + .m_axis_data_tready ({s_b1_data.tready, s_b0_data.tready}), .s_axis_ctrl_tdata (b_ctrl_out_tdata ), .s_axis_ctrl_tlast (b_ctrl_loop_tlast ), .s_axis_ctrl_tvalid (b_ctrl_loop_tvalid ), @@ -194,14 +197,14 @@ module chdr_stream_endpoint_tb; .clk (rfnoc_chdr_clk), .reset (rfnoc_chdr_rst), .device_id (DEV_ID), - .s_axis_tdata ({b2c_chdr_tdata, a2c_chdr_tdata, m_tb_chdr.slave.tdata }), - .s_axis_tlast ({b2c_chdr_tlast, a2c_chdr_tlast, m_tb_chdr.slave.tlast }), - .s_axis_tvalid ({b2c_chdr_tvalid, a2c_chdr_tvalid, m_tb_chdr.slave.tvalid }), - .s_axis_tready ({b2c_chdr_tready, a2c_chdr_tready, m_tb_chdr.slave.tready }), - .m_axis_tdata ({c2bx_chdr_tdata, c2ax_chdr_tdata, s_tb_chdr.master.tdata }), - .m_axis_tlast ({c2bx_chdr_tlast, c2ax_chdr_tlast, s_tb_chdr.master.tlast }), - .m_axis_tvalid ({c2bx_chdr_tvalid, c2ax_chdr_tvalid, s_tb_chdr.master.tvalid}), - .m_axis_tready ({c2bx_chdr_tready, c2ax_chdr_tready, s_tb_chdr.master.tready}), + .s_axis_tdata ({b2c_chdr_tdata, a2c_chdr_tdata, m_tb_chdr.tdata }), + .s_axis_tlast ({b2c_chdr_tlast, a2c_chdr_tlast, m_tb_chdr.tlast }), + .s_axis_tvalid ({b2c_chdr_tvalid, a2c_chdr_tvalid, m_tb_chdr.tvalid }), + .s_axis_tready ({b2c_chdr_tready, a2c_chdr_tready, m_tb_chdr.tready }), + .m_axis_tdata ({c2bx_chdr_tdata, c2ax_chdr_tdata, s_tb_chdr.tdata }), + .m_axis_tlast ({c2bx_chdr_tlast, c2ax_chdr_tlast, s_tb_chdr.tlast }), + .m_axis_tvalid ({c2bx_chdr_tvalid, c2ax_chdr_tvalid, s_tb_chdr.tvalid}), + .m_axis_tready ({c2bx_chdr_tready, c2ax_chdr_tready, s_tb_chdr.tready}), .ext_rtcfg_stb ('0), .ext_rtcfg_addr ('0), .ext_rtcfg_data ('0), @@ -264,14 +267,15 @@ module chdr_stream_endpoint_tb; end end // Respond with an ACK and the source and destination ports swapped - assign a_ctrl_out_tdata = + assign a_ctrl_out_tdata = a_first ? {1'b1, a_ctrl_in_tdata[30:20], a_ctrl_in_tdata[9:0], a_ctrl_in_tdata[19:10]} : a_ctrl_in_tdata; - assign b_ctrl_out_tdata = + assign b_ctrl_out_tdata = b_first ? {1'b1, b_ctrl_in_tdata[30:20], b_ctrl_in_tdata[9:0], b_ctrl_in_tdata[19:10]} : b_ctrl_in_tdata; // ---------------------------------------- // Test Utilities // ---------------------------------------- + TestExec test = new(); integer cached_mgmt_seqnum = 0; integer cached_ctrl_seqnum = 0; integer cached_data_seqnum = 0; @@ -320,7 +324,7 @@ module chdr_stream_endpoint_tb; op_payload:{32'h0, sep_a.REG_OSTRM_DATA_ERR_CNT}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd2}; tx_mgmt_pl.ops[3] = '{ // Hop 2: Read status op_payload:{32'h0, sep_a.REG_OSTRM_ROUTE_ERR_CNT}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd1}; - tx_mgmt_pl.ops[4] = '{ // Hop 2: Stream Endpoint: Return + tx_mgmt_pl.ops[4] = '{ // Hop 2: Stream Endpoint: Return op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0}; tx_mgmt_pl.ops[5] = '{ // Hop 3: Nop for return op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0}; @@ -357,7 +361,7 @@ module chdr_stream_endpoint_tb; automatic ctrl_op_word_t ctrl_op; automatic ctrl_word_t ctrl_data[$]; automatic chdr_word_t ctrl_ts; - + ctrl_data.delete(); for (int i = 0; i < $urandom_range(15,1); i++) ctrl_data[i] = $urandom(); @@ -406,6 +410,7 @@ module chdr_stream_endpoint_tb; if (VERBOSE) begin $write("ExpRx"); exp_chdr.print(); end // Validate contents + exp_chdr.disable_comparing_beyond_length = 1; `ASSERT_ERROR(exp_chdr.equal(rx_chdr), "Received CHDR control packet was incorrect"); end @@ -527,12 +532,12 @@ module chdr_stream_endpoint_tb; // Shared Variables // ---------------------------------------- - timeout_t timeout; - string tc_label; - bit stop_responder = 0; - logic [31:0] seq_err_count; - logic [31:0] route_err_count; - logic [31:0] data_err_count; + timeout_t timeout; + string tc_label; + automatic bit stop_responder = 0; + logic [31:0] seq_err_count; + logic [31:0] route_err_count; + logic [31:0] data_err_count; a_signal_data_err = 0; b_signal_data_err = 0; @@ -543,9 +548,10 @@ module chdr_stream_endpoint_tb; b_rterr_prob = 0; b_lossy_input = 0; + // Initialize // ---------------------------------------- - test.start_tb("chdr_stream_endpoint_tb"); + test.start_tb({TEST_NAME,"chdr_stream_endpoint_tb"}); // Start the BFMs a0_data_bfm.run(); @@ -562,7 +568,7 @@ module chdr_stream_endpoint_tb; rfnoc_ctrl_clk_gen.reset(); rfnoc_chdr_clk_gen.reset(); - test.start_test("Wait for reset"); + test.start_test({TEST_NAME,"Wait for reset"}); test.start_timeout(timeout, 1us, "Waiting for reset"); while (rfnoc_ctrl_rst) @(posedge rfnoc_ctrl_clk); while (rfnoc_chdr_rst) @(posedge rfnoc_chdr_clk); @@ -572,7 +578,7 @@ module chdr_stream_endpoint_tb; // Discover Topology // ---------------------------------------- - test.start_test("Discover Topology"); + test.start_test({TEST_NAME,"Discover Topology"}); begin automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr; automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl; @@ -587,9 +593,9 @@ module chdr_stream_endpoint_tb; // Send a node info request to the crossbar tx_mgmt_pl.header.num_hops = 2; tx_mgmt_pl.ops.delete(); - tx_mgmt_pl.ops[0] = '{ // Hop 1: Send node info + tx_mgmt_pl.ops[0] = '{ // Hop 1: Send node info op_payload:48'h0, op_code:MGMT_OP_INFO_REQ, ops_pending:8'd1}; - tx_mgmt_pl.ops[1] = '{ // Hop 1: Return + tx_mgmt_pl.ops[1] = '{ // Hop 1: Return op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0}; tx_mgmt_pl.ops[2] = '{ // Hop 2: Nop for return op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0}; @@ -605,7 +611,7 @@ module chdr_stream_endpoint_tb; `ASSERT_ERROR(rx_mgmt_pl.ops[1] == exp_mgmt_op, "Discover XB: Mgmt response ops were incorrect"); - // *Status* We just discovered a crossbar with 3 ports! + // *Status* We just discovered a crossbar with 3 ports! // Configure the crossbar routing table with our (TB) address // then send node info request on the other two ports @@ -613,11 +619,11 @@ module chdr_stream_endpoint_tb; tx_mgmt_pl.ops.delete(); tx_mgmt_pl.ops[0] = '{ // Hop 1: Crossbar: Config router to return packet to dest op_payload:{22'h0, PORT_TB, EPID_TB}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd1}; - tx_mgmt_pl.ops[1] = '{ // Hop 1: Crossbar: Config router + tx_mgmt_pl.ops[1] = '{ // Hop 1: Crossbar: Config router op_payload:{38'h0, PORT_A}, op_code:MGMT_OP_SEL_DEST, ops_pending:8'd0}; - tx_mgmt_pl.ops[2] = '{ // Hop 2: Stream Endpoint: Send node info + tx_mgmt_pl.ops[2] = '{ // Hop 2: Stream Endpoint: Send node info op_payload:48'h0, op_code:MGMT_OP_INFO_REQ, ops_pending:8'd1}; - tx_mgmt_pl.ops[3] = '{ // Hop 2: Return + tx_mgmt_pl.ops[3] = '{ // Hop 2: Return op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0}; tx_mgmt_pl.ops[4] = '{ // Hop 3: TB: Nop for return op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0}; @@ -638,11 +644,11 @@ module chdr_stream_endpoint_tb; // Send node info request on the last port tx_mgmt_pl.header.num_hops = 3; tx_mgmt_pl.ops.delete(); - tx_mgmt_pl.ops[0] = '{ // Hop 1: Crossbar: Config router + tx_mgmt_pl.ops[0] = '{ // Hop 1: Crossbar: Config router op_payload:{38'h0, PORT_B}, op_code:MGMT_OP_SEL_DEST, ops_pending:8'd0}; - tx_mgmt_pl.ops[1] = '{ // Hop 2: Stream Endpoint: Send node info + tx_mgmt_pl.ops[1] = '{ // Hop 2: Stream Endpoint: Send node info op_payload:48'h0, op_code:MGMT_OP_INFO_REQ, ops_pending:8'd1}; - tx_mgmt_pl.ops[2] = '{ // Hop 2: Return + tx_mgmt_pl.ops[2] = '{ // Hop 2: Return op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0}; tx_mgmt_pl.ops[3] = '{ // Hop 3: TB: Nop for return op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0}; @@ -664,7 +670,7 @@ module chdr_stream_endpoint_tb; // Configure Routes to Stream Endpoints A and B // ---------------------------------------- - test.start_test("Configure Routes"); + test.start_test({TEST_NAME,"Configure Routes"}); begin automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr; automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl; @@ -680,9 +686,9 @@ module chdr_stream_endpoint_tb; tx_mgmt_pl.ops[0] = '{ // Hop 1: Crossbar: Config path to EP A op_payload:{22'h0, PORT_A, EPID_A}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd2}; - tx_mgmt_pl.ops[1] = '{ // Hop 1: Crossbar: Config path to EP B + tx_mgmt_pl.ops[1] = '{ // Hop 1: Crossbar: Config path to EP B op_payload:{22'h0, PORT_B, EPID_B}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd1}; - tx_mgmt_pl.ops[2] = '{ // Hop 1: Request node info to make the packet come back + tx_mgmt_pl.ops[2] = '{ // Hop 1: Request node info to make the packet come back op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0}; tx_mgmt_pl.ops[3] = '{ // Hop 2: Nop for return op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0}; @@ -701,13 +707,13 @@ module chdr_stream_endpoint_tb; // Configure Stream Endpoints // ---------------------------------------- - test.start_test("Configure Stream Endpoints"); + test.start_test({TEST_NAME,"Configure Stream Endpoints"}); begin automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr; automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl; automatic chdr_mgmt_op_t exp_mgmt_op; - logic [15:0] epids[2] = {EPID_A, EPID_B}; + automatic logic [15:0] epids[2] = {EPID_A, EPID_B}; foreach (epids[i]) begin // Generic management header tx_mgmt_pl.header = '{ @@ -727,13 +733,13 @@ module chdr_stream_endpoint_tb; op_payload:{32'h0, sep_a.REG_EPID_SELF}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd2}; tx_mgmt_pl.ops[4] = '{ // Hop 2: Read EPID op_payload:{32'h0, sep_a.REG_OSTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd1}; - tx_mgmt_pl.ops[5] = '{ // Hop 2: Stream Endpoint: Return + tx_mgmt_pl.ops[5] = '{ // Hop 2: Stream Endpoint: Return op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0}; tx_mgmt_pl.ops[6] = '{ // Hop 3: Nop for return op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0}; tx_mgmt_hdr = '{ pkt_type:CHDR_MANAGEMENT, seq_num:cached_mgmt_seqnum++, dst_epid:epids[i], default:'0}; - + // Send the packet and check the response send_recv_mgmt_packet(tx_mgmt_hdr, tx_mgmt_pl, rx_mgmt_hdr, rx_mgmt_pl); `ASSERT_ERROR(rx_mgmt_pl.header.num_hops == 1, @@ -752,13 +758,13 @@ module chdr_stream_endpoint_tb; // Setup a stream between Endpoint A and B // ---------------------------------------- - test.start_test("Setup bidirectional stream between endpoints A and B"); + test.start_test({TEST_NAME,"Setup bidirectional stream between endpoints A and B"}); begin automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr; automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl; automatic chdr_mgmt_op_t exp_mgmt_op; - logic [15:0] epids[2] = {EPID_A, EPID_B}; + automatic logic [15:0] epids[2] = {EPID_A, EPID_B}; foreach (epids[i]) begin // Generic management header tx_mgmt_pl.header = '{ @@ -784,7 +790,7 @@ module chdr_stream_endpoint_tb; op_payload:{32'h44, sep_a.REG_ISTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd2}; // Swap 32-bit words, endianness tx_mgmt_pl.ops[7] = '{ // Hop 2: Configure lossy and start config op_payload:{32'h47, sep_a.REG_OSTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd1}; // Swap 32-bit words, endianness, lossy and reset - tx_mgmt_pl.ops[8] = '{ // Hop 2: Stream Endpoint: Return + tx_mgmt_pl.ops[8] = '{ // Hop 2: Stream Endpoint: Return op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0}; tx_mgmt_pl.ops[9] = '{ // Hop 3: Nop for return op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0}; @@ -818,7 +824,7 @@ module chdr_stream_endpoint_tb; op_payload:{32'h0, sep_a.REG_OSTRM_DATA_ERR_CNT}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd2}; tx_mgmt_pl.ops[7] = '{ // Hop 2: Read status op_payload:{32'h0, sep_a.REG_OSTRM_ROUTE_ERR_CNT}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd1}; - tx_mgmt_pl.ops[8] = '{ // Hop 2: Stream Endpoint: Return + tx_mgmt_pl.ops[8] = '{ // Hop 2: Stream Endpoint: Return op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0}; tx_mgmt_pl.ops[9] = '{ // Hop 3: Nop for return op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0}; @@ -859,7 +865,7 @@ module chdr_stream_endpoint_tb; cached_ctrl_seqnum = 0; for (int cfg = 0; cfg < 2; cfg++) begin $sformat(tc_label, "Control Xact to A (%s)", (cfg?"Slow":"Fast")); - test.start_test(tc_label); + test.start_test({TEST_NAME,tc_label}); begin tb_chdr_bfm.set_master_stall_prob(cfg?SLOW_STALL_PROB:FAST_STALL_PROB); tb_chdr_bfm.set_slave_stall_prob(cfg?SLOW_STALL_PROB:FAST_STALL_PROB); @@ -874,7 +880,7 @@ module chdr_stream_endpoint_tb; cached_ctrl_seqnum = 0; for (int cfg = 0; cfg < 2; cfg++) begin $sformat(tc_label, "Control Xact to B (%s)", (cfg?"Slow":"Fast")); - test.start_test(tc_label); + test.start_test({TEST_NAME,tc_label}); begin tb_chdr_bfm.set_master_stall_prob(cfg?SLOW_STALL_PROB:FAST_STALL_PROB); tb_chdr_bfm.set_slave_stall_prob(cfg?SLOW_STALL_PROB:FAST_STALL_PROB); @@ -892,7 +898,7 @@ module chdr_stream_endpoint_tb; automatic logic slv_cfg = cfg[1]; $sformat(tc_label, "Stream Data from A to B (%s Mst, %s Slv)", (mst_cfg?"Slow":"Fast"), (slv_cfg?"Slow":"Fast")); - test.start_test(tc_label); + test.start_test({TEST_NAME,tc_label}); begin set_unidir_stall_prob(EPID_A, EPID_B, mst_cfg?SLOW_STALL_PROB:FAST_STALL_PROB, @@ -911,7 +917,7 @@ module chdr_stream_endpoint_tb; automatic logic slv_cfg = cfg[1]; $sformat(tc_label, "Stream Data from B to A (%s Mst, %s Slv)", (mst_cfg?"Slow":"Fast"), (slv_cfg?"Slow":"Fast")); - test.start_test(tc_label); + test.start_test({TEST_NAME,tc_label}); begin set_unidir_stall_prob(EPID_B, EPID_A, mst_cfg?SLOW_STALL_PROB:FAST_STALL_PROB, @@ -929,7 +935,7 @@ module chdr_stream_endpoint_tb; automatic logic slv_cfg = cfg[1]; $sformat(tc_label, "Stream Data between A <=> B simultaneously (%s Mst, %s Slv)", (mst_cfg?"Slow":"Fast"), (slv_cfg?"Slow":"Fast")); - test.start_test(tc_label); + test.start_test({TEST_NAME,tc_label}); begin set_bidir_stall_prob( mst_cfg?SLOW_STALL_PROB:FAST_STALL_PROB, @@ -950,7 +956,7 @@ module chdr_stream_endpoint_tb; automatic logic slv_cfg = cfg[1]; $sformat(tc_label, "Stream Data and Control between A <=> B (%s Mst, %s Slv)", (mst_cfg?"Slow":"Fast"), (slv_cfg?"Slow":"Fast")); - test.start_test(tc_label); + test.start_test({TEST_NAME,tc_label}); begin tb_chdr_bfm.set_master_stall_prob(mst_cfg?SLOW_STALL_PROB:FAST_STALL_PROB); tb_chdr_bfm.set_slave_stall_prob(slv_cfg?SLOW_STALL_PROB:FAST_STALL_PROB); @@ -976,9 +982,9 @@ module chdr_stream_endpoint_tb; // Check zero sequence errors after streaming // ---------------------------------------- - test.start_test("Check zero sequence errors after streaming"); + test.start_test({TEST_NAME,"Check zero sequence errors after streaming"}); begin - logic [15:0] epids[2] = {EPID_A, EPID_B}; + automatic logic [15:0] epids[2] = {EPID_A, EPID_B}; foreach (epids[i]) begin mgmt_read_err_counts(epids[i], seq_err_count, route_err_count, data_err_count); `ASSERT_ERROR(seq_err_count == 32'd0, "Check NoErrs: Incorrect seq error count"); @@ -988,9 +994,13 @@ module chdr_stream_endpoint_tb; end test.end_test(); + // Force sequence error + // Note: Occasional StreamCommand to resynch occur, which + // can cause the count to be greater than just the number data packets + // that are sent, so the comparisons are to > instead of == // ---------------------------------------- - test.start_test("Force sequence error"); + test.start_test({TEST_NAME,"Force sequence error"}); begin // First sequence error send_recv_data_packets(EPID_A, EPID_B, 1, cached_data_seqnum++, 1); @@ -999,7 +1009,7 @@ module chdr_stream_endpoint_tb; b_seqerr_prob = 0; repeat (100) @(posedge rfnoc_chdr_clk); // Wait for sequence error to reach the upstream port mgmt_read_err_counts(EPID_A, seq_err_count, route_err_count, data_err_count); - `ASSERT_ERROR(seq_err_count == 32'd1, "Force SeqErr: Incorrect seq error count"); + `ASSERT_ERROR(seq_err_count > 32'd0, "Force SeqErr: Incorrect seq error count"); `ASSERT_ERROR(route_err_count == 32'd0, "Force SeqErr: Incorrect route error count"); `ASSERT_ERROR(data_err_count == 32'd0, "Force SeqErr: Incorrect data error count"); @@ -1010,7 +1020,7 @@ module chdr_stream_endpoint_tb; b_seqerr_prob = 0; repeat (100) @(posedge rfnoc_chdr_clk); // Wait for sequence error to reach the upstream port mgmt_read_err_counts(EPID_A, seq_err_count, route_err_count, data_err_count); - `ASSERT_ERROR(seq_err_count > 32'd1, "Force SeqErr: Incorrect seq error count"); + `ASSERT_ERROR(seq_err_count > 32'd2, "Force SeqErr: Incorrect seq error count"); `ASSERT_ERROR(route_err_count == 32'd0, "Force SeqErr: Incorrect route error count"); `ASSERT_ERROR(data_err_count == 32'd0, "Force SeqErr: Incorrect data error count"); end @@ -1018,7 +1028,7 @@ module chdr_stream_endpoint_tb; // Force routing error // ---------------------------------------- - test.start_test("Force routing error"); + test.start_test({TEST_NAME,"Force routing error"}); begin logic [31:0] old_route_err_count; // First sequence error @@ -1048,13 +1058,13 @@ module chdr_stream_endpoint_tb; // Setup a stream between Endpoint A and B // ---------------------------------------- - test.start_test("Reconfigure flow control (reset state)"); + test.start_test({TEST_NAME,"Reconfigure flow control (reset state)"}); begin automatic chdr_header_t tx_mgmt_hdr, rx_mgmt_hdr; automatic chdr_mgmt_t tx_mgmt_pl, rx_mgmt_pl; automatic chdr_mgmt_op_t exp_mgmt_op; - logic [15:0] epids[2] = {EPID_A, EPID_B}; + automatic logic [15:0] epids[2] = {EPID_A, EPID_B}; foreach (epids[i]) begin // Generic management header tx_mgmt_pl.header = '{ @@ -1070,7 +1080,7 @@ module chdr_stream_endpoint_tb; op_payload:{32'd0, sep_a.REG_ISTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd2}; tx_mgmt_pl.ops[2] = '{ // Hop 2: Configure lossy and start config op_payload:{32'd3, sep_a.REG_OSTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_WR_REQ, ops_pending:8'd1}; - tx_mgmt_pl.ops[3] = '{ // Hop 2: Stream Endpoint: Return + tx_mgmt_pl.ops[3] = '{ // Hop 2: Stream Endpoint: Return op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0}; tx_mgmt_pl.ops[4] = '{ // Hop 3: Nop for return op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0}; @@ -1092,7 +1102,7 @@ module chdr_stream_endpoint_tb; op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0}; tx_mgmt_pl.ops[1] = '{ // Hop 2: Read status op_payload:{32'h0, sep_a.REG_OSTRM_CTRL_STATUS}, op_code:MGMT_OP_CFG_RD_REQ, ops_pending:8'd1}; - tx_mgmt_pl.ops[2] = '{ // Hop 2: Stream Endpoint: Return + tx_mgmt_pl.ops[2] = '{ // Hop 2: Stream Endpoint: Return op_payload:48'h0, op_code:MGMT_OP_RETURN, ops_pending:8'd0}; tx_mgmt_pl.ops[3] = '{ // Hop 3: Nop for return op_payload:48'h0, op_code:MGMT_OP_NOP, ops_pending:8'd0}; @@ -1112,9 +1122,9 @@ module chdr_stream_endpoint_tb; // Check zero errors after reinit // ---------------------------------------- - test.start_test("Check zero errors after reinit"); + test.start_test({TEST_NAME,"Check zero errors after reinit"}); begin - logic [15:0] epids[2] = {EPID_A, EPID_B}; + automatic logic [15:0] epids[2] = {EPID_A, EPID_B}; foreach (epids[i]) begin mgmt_read_err_counts(epids[i], seq_err_count, route_err_count, data_err_count); `ASSERT_ERROR(seq_err_count == 32'd0, "Check NoErrs: Incorrect seq error count"); @@ -1126,7 +1136,7 @@ module chdr_stream_endpoint_tb; // Stream data between A <=> B simultaneously // ---------------------------------------- - test.start_test("Stream Data between A <=> B with a lossy link"); + test.start_test({TEST_NAME,"Stream Data between A <=> B with a lossy link"}); begin cached_data_seqnum = 0; set_bidir_stall_prob(FAST_STALL_PROB, SLOW_STALL_PROB); @@ -1145,7 +1155,8 @@ module chdr_stream_endpoint_tb; // Finish Up // ---------------------------------------- // Display final statistics and results - test.end_tb(); + test.end_tb(.finish(0)); end endmodule +`default_nettype wire
\ No newline at end of file diff --git a/fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv b/fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv index 96bfbd3a7..08b61712f 100644 --- a/fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv +++ b/fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv @@ -1,16 +1,15 @@ // -// Copyright 2019 Ettus Research, A National Instruments Company +// Copyright 2020 Ettus Research, A National Instruments Brand // // SPDX-License-Identifier: LGPL-3.0-or-later // // Module: PkgChdrBfm // -// Description: Package for a bi-directional CHDR bus functional model (BFM), +// Description: Package for a bi-directional CHDR bus functional model (BFM), // which consists primarily of the ChdrPacket and ChdrBfm classes. // - package PkgChdrBfm; import PkgChdrUtils::*; @@ -21,10 +20,13 @@ package PkgChdrBfm; // CHDR Packet Class //--------------------------------------------------------------------------- - class ChdrPacket #(int CHDR_W = 64); + class ChdrPacket #(parameter int CHDR_W = 64, + parameter int USER_WIDTH = 1); - typedef ChdrPacket #(CHDR_W) ChdrPacket_t; + typedef ChdrPacket #(CHDR_W,USER_WIDTH) ChdrPacket_t; + typedef AxiStreamPacket #(CHDR_W, USER_WIDTH) AxisPacket_t; typedef ChdrData #(CHDR_W)::chdr_word_t chdr_word_t; + typedef AxisPacket_t::data_t data_t; const int BYTES_PER_CHDR_W = CHDR_W / 8; @@ -33,6 +35,8 @@ package PkgChdrBfm; chdr_word_t metadata[$]; chdr_word_t data[$]; + bit disable_comparing_beyond_length = 1; + extern function ChdrPacket_t copy(); extern function bit equal(ChdrPacket_t packet); extern function string sprint(bit pretty = 1); @@ -44,22 +48,22 @@ package PkgChdrBfm; input chdr_word_t metadata[$] = {}, input chdr_timestamp_t timestamp = 0, input int data_byte_length = -1); - extern function void read_raw (output chdr_header_t header, + extern function void read_raw (output chdr_header_t header, output chdr_word_t data[$], output chdr_word_t metadata[$], output chdr_timestamp_t timestamp, output int data_byte_length); - extern function void write_stream_status(ref chdr_header_t header, + extern function void write_stream_status(ref chdr_header_t header, ref chdr_str_status_t status); - extern function void read_stream_status (output chdr_header_t header, + extern function void read_stream_status (output chdr_header_t header, output chdr_str_status_t status); - extern function void write_stream_cmd (ref chdr_header_t header, + extern function void write_stream_cmd (ref chdr_header_t header, ref chdr_str_command_t command); - extern function void read_stream_cmd (output chdr_header_t header, + extern function void read_stream_cmd (output chdr_header_t header, output chdr_str_command_t command); - extern function void write_mgmt (ref chdr_header_t header, + extern function void write_mgmt (ref chdr_header_t header, ref chdr_mgmt_t mgmt); - extern function void read_mgmt (output chdr_header_t header, + extern function void read_mgmt (output chdr_header_t header, output chdr_mgmt_t mgmt); extern function void write_ctrl (ref chdr_header_t header, ref chdr_ctrl_header_t ctrl_header, @@ -72,17 +76,22 @@ package PkgChdrBfm; output ctrl_word_t ctrl_data[$], output chdr_timestamp_t ctrl_timestamp); - // Helper methods extern function int header_bytes(); extern function int mdata_bytes(); extern function int data_bytes(); - extern function void update_lengths(); + extern function void update_lengths(int payload_bytes = 0); extern function string sprint_raw(); extern function string sprint_pretty(); - extern function bit chdr_word_queues_equal(ref chdr_word_t a[$], ref chdr_word_t b[$]); + extern function bit chdr_word_queues_equal(ref chdr_word_t a[$], + ref chdr_word_t b[$], + input int data_byte_length = -1); + + // AXI-Stream/CHDR Conversion Functions + extern function void axis_to_chdr (AxisPacket_t axis_packet); + extern function AxisPacket_t chdr_to_axis (); endclass : ChdrPacket; @@ -123,12 +132,6 @@ package PkgChdrBfm; extern function bit try_get_chdr(output ChdrPacket_t chdr_packet); extern task peek_chdr(output ChdrPacket_t chdr_packet); extern function bit try_peek_chdr(output ChdrPacket_t chdr_packet); - - - // AXI-Stream/CHDR Conversion Functions - extern function ChdrPacket_t axis_to_chdr (AxisPacket_t axis_packet); - extern function AxisPacket_t chdr_to_axis (ChdrPacket_t chdr_packet); - endclass : ChdrBfm @@ -151,8 +154,17 @@ package PkgChdrBfm; // Return true if this packet equals that of the argument function bit ChdrPacket::equal(ChdrPacket_t packet); + int payload_length; + payload_length = header.length; + payload_length -= BYTES_PER_CHDR_W; // subtract header bytes + if (CHDR_W == 64) begin // subtract TS bytes if not in header word + if (header.pkt_type == CHDR_DATA_WITH_TS) begin + payload_length -= BYTES_PER_CHDR_W; + end + end + payload_length -= packet.metadata.size() * BYTES_PER_CHDR_W; // subtract metadata length if (header != packet.header) return 0; - if (!chdr_word_queues_equal(data, packet.data)) return 0; + if (!chdr_word_queues_equal(data, packet.data,payload_length)) return 0; if (!chdr_word_queues_equal(metadata, packet.metadata)) return 0; if (header.pkt_type == CHDR_DATA_WITH_TS && timestamp !== packet.timestamp) return 0; return 1; @@ -176,6 +188,7 @@ package PkgChdrBfm; return str; endfunction : sprint_raw + // Format the contents of the packet into a string (dissect contents) function string ChdrPacket::sprint_pretty(); string str; @@ -236,6 +249,7 @@ package PkgChdrBfm; return str; endfunction : sprint_pretty + function string ChdrPacket::sprint(bit pretty = 1); if (pretty) return sprint_pretty(); @@ -243,6 +257,7 @@ package PkgChdrBfm; return sprint_raw(); endfunction: sprint + // Print the contents of the packet function void ChdrPacket::print(bit pretty = 1); $display(sprint(pretty)); @@ -284,7 +299,7 @@ package PkgChdrBfm; // Read the contents of this packet function void ChdrPacket::read_raw ( - output chdr_header_t header, + output chdr_header_t header, output chdr_word_t data[$], output chdr_word_t metadata[$], output chdr_timestamp_t timestamp, @@ -315,7 +330,7 @@ package PkgChdrBfm; // Read this packet as a status packet function void ChdrPacket::read_stream_status ( - output chdr_header_t header, + output chdr_header_t header, output chdr_str_status_t status ); // Make sure it's a stream status packet @@ -383,7 +398,7 @@ package PkgChdrBfm; // Insert the header data.push_back( mgmt.header ); - + // Insert the ops foreach (mgmt.ops[i]) begin data.push_back( mgmt.ops[i] ); @@ -433,6 +448,7 @@ package PkgChdrBfm; input chdr_timestamp_t ctrl_timestamp = 0 ); bit partial_word; + int byte_count = 0; ctrl_word_t mandatory_data; ChdrData #(CHDR_W, 64)::item_queue_t data64; @@ -442,10 +458,12 @@ package PkgChdrBfm; // Insert word 0 of control payload data64.push_back(ctrl_header); + byte_count+=8; // Insert word 1 of control payload, if timestamp is used if (ctrl_header.has_time) begin data64.push_back(ctrl_timestamp); + byte_count+=8; end // Make sure the amount of data passed matches the header @@ -457,6 +475,7 @@ package PkgChdrBfm; // and first word of control data. mandatory_data = (ctrl_header.num_data > 0) ? ctrl_data[0] : '0; data64.push_back({mandatory_data, ctrl_op_word[31:0]}); + byte_count+=8; // We have a half CHDR word if num_data is even partial_word = (ctrl_header.num_data[0] == '0); @@ -465,15 +484,17 @@ package PkgChdrBfm; if (i == ctrl_data.size()-1) begin // num_data must be even in this case, so last word is half filled data64.push_back({ 32'b0, ctrl_data[i] }); + byte_count+=4; end else begin data64.push_back({ ctrl_data[i+1], ctrl_data[i] }); + byte_count+=8; end end // Convert from 64-bit words to CHDR_W-bit words data = ChdrData #(CHDR_W, 64)::item_to_chdr(data64); - update_lengths(); + update_lengths(.payload_bytes(byte_count)); endfunction : write_ctrl @@ -530,7 +551,6 @@ package PkgChdrBfm; while (dptr < data32.size()) begin ctrl_data.push_back(data32[dptr++]); end - endfunction : read_ctrl @@ -557,21 +577,30 @@ package PkgChdrBfm; endfunction : data_bytes; - // Update the length and num_mdata header fields of the packet based on the + // Update the length and num_mdata header fields of the packet based on the // size of the metadata queue and the data queue. - function void ChdrPacket::update_lengths(); + function void ChdrPacket::update_lengths(int payload_bytes = 0); int num_bytes; int num_mdata; + int my_payload_bytes; // Calculate NumMData based on the size of metadata queue num_mdata = metadata.size(); assert(num_mdata < 2**$bits(chdr_num_mdata_t)) else $fatal(1, "ChdrPacket::update_lengths(): Calculated NumMData exceeds maximum size"); + if (payload_bytes == 0) begin + // Calculate if optional argument not provided + my_payload_bytes = data.size() * BYTES_PER_CHDR_W; + end else begin + // Use optional argument if provided + my_payload_bytes = payload_bytes; + end + // Calculate the Length field num_bytes = header_bytes() + // Header num_mdata * BYTES_PER_CHDR_W + // Metadata - data.size() * BYTES_PER_CHDR_W; // Payload + my_payload_bytes; // Payload assert(num_bytes < 2**$bits(chdr_length_t)) else $fatal(1, "ChdrPacket::update_lengths(): Calculated Length exceeds maximum size"); @@ -581,100 +610,37 @@ package PkgChdrBfm; endfunction : update_lengths - // Returns 1 if the queues have the same contents, otherwise returns 0. This - // function is equivalent to (a == b), but this doesn't work correctly yet in - // Vivado 2018.3. - function automatic bit ChdrPacket::chdr_word_queues_equal(ref chdr_word_t a[$], ref chdr_word_t b[$]); + // Returns 1 if the queues have the same contents, up to the + // data_byte_length, if present. + function automatic bit ChdrPacket::chdr_word_queues_equal( + ref chdr_word_t a[$], + ref chdr_word_t b[$], + input int data_byte_length = -1 + ); chdr_word_t x, y; + int bytes_remaining = data_byte_length; if (a.size() != b.size()) return 0; foreach (a[i]) begin x = a[i]; y = b[i]; - if (x !== y) return 0; + if(data_byte_length > 0 && // only if optional argument is valid + disable_comparing_beyond_length && // only if optional feature is enabled + bytes_remaining < BYTES_PER_CHDR_W) begin // only compare bytes on last word + for (int b = 0; b < bytes_remaining*8; b += 8) begin + if (x[b+:8] !== y[b+:8]) return 0; + end + end else begin + if (x !== y) return 0; + end + bytes_remaining -= BYTES_PER_CHDR_W; end return 1; endfunction : chdr_word_queues_equal - - //--------------------------------------------------------------------------- - // CHDR BFM Class Methods - //--------------------------------------------------------------------------- - - - // Class constructor. This must be given an interface for the master - // connection and an interface for the slave connection. - function ChdrBfm::new ( - virtual AxiStreamIf #(CHDR_W, USER_WIDTH).master master, - virtual AxiStreamIf #(CHDR_W, USER_WIDTH).slave slave - ); - super.new(master, slave); - assert(CHDR_W % 64 == 0) else begin - $fatal(1, "ChdrBfm::new: CHDR bus width must be a multiple of 64 bits"); - end - endfunction : new - - - // Queue the provided packet for transmission - task ChdrBfm::put_chdr (ChdrPacket_t chdr_packet); - AxisPacket_t axis_packet; - - axis_packet = chdr_to_axis(chdr_packet); - super.put(axis_packet); - endtask : put_chdr - - - // Attempt to queue the provided packet for transmission. Return 1 if - // successful, return 0 if the queue is full. - function bit ChdrBfm::try_put_chdr (ChdrPacket_t chdr_packet); - AxisPacket_t axis_packet; - bit status; - - axis_packet = chdr_to_axis(chdr_packet); - return super.try_put(axis_packet); - endfunction : try_put_chdr - - - // Get the next packet when it becomes available (wait if necessary) - task ChdrBfm::get_chdr (output ChdrPacket_t chdr_packet); - AxisPacket_t axis_packet; - super.get(axis_packet); - chdr_packet = axis_to_chdr(axis_packet); - endtask : get_chdr - - - // Get the next packet if there's one available and return 1. Return 0 if - // there's no packet available. - function bit ChdrBfm::try_get_chdr (output ChdrPacket_t chdr_packet); - AxisPacket_t axis_packet; - if (!super.try_get(axis_packet)) return 0; - chdr_packet = axis_to_chdr(axis_packet); - return 1; - endfunction : try_get_chdr - - - // Get the next packet when it becomes available (wait if necessary), but - // don't remove it from the receive queue. - task ChdrBfm::peek_chdr (output ChdrPacket_t chdr_packet); - AxisPacket_t axis_packet; - super.peek(axis_packet); - chdr_packet = axis_to_chdr(axis_packet); - endtask : peek_chdr - - - // Get the next packet if there's one available and return 1, but don't - // remove it from the receive queue. Return 0 if there's no packet available. - function bit ChdrBfm::try_peek_chdr (output ChdrPacket_t chdr_packet); - AxisPacket_t axis_packet; - if (!super.try_get(axis_packet)) return 0; - chdr_packet = axis_to_chdr(axis_packet); - return 1; - endfunction : try_peek_chdr - - - // Convert the data payload of an AXI Stream packet data structure to a CHDR + // Convert the data payload of an AXI Stream packet data structure to a CHDR // packet data structure. - function ChdrBfm::ChdrPacket_t ChdrBfm::axis_to_chdr (AxisPacket_t axis_packet); + function void ChdrPacket::axis_to_chdr (AxisPacket_t axis_packet); enum int { ST_HEADER, ST_TIMESTAMP, ST_METADATA, ST_PAYLOAD } rx_state; data_t word; int num_rx_mdata; @@ -685,17 +651,17 @@ package PkgChdrBfm; for(int i = 0; i < axis_packet.data.size(); i++) begin word = axis_packet.data[i]; - + case (rx_state) ST_HEADER : begin num_rx_bytes += BYTES_PER_CHDR_W; - chdr_packet.header = word[63:0]; + header = word[63:0]; - // Depending on the size of the word, we could have just the header + // Depending on the size of the word, we could have just the header // or both the header and the timestamp in this word. - if (chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS) begin + if (header.pkt_type == CHDR_DATA_WITH_TS) begin if (CHDR_W >= 128) begin - chdr_packet.timestamp = word[127:64]; + timestamp = word[127:64]; rx_state = ST_METADATA; end else begin rx_state = ST_TIMESTAMP; @@ -705,104 +671,178 @@ package PkgChdrBfm; end // Check if there's no metadata, in which case we can skip it - if (rx_state == ST_METADATA && chdr_packet.header.num_mdata == 0) begin + if (rx_state == ST_METADATA && header.num_mdata == 0) begin rx_state = ST_PAYLOAD; end end ST_TIMESTAMP : begin num_rx_bytes += BYTES_PER_CHDR_W; - chdr_packet.timestamp = word; - rx_state = (chdr_packet.header.num_mdata > 0) ? ST_METADATA : ST_PAYLOAD; + timestamp = word; + rx_state = (header.num_mdata > 0) ? ST_METADATA : ST_PAYLOAD; end ST_METADATA : begin - chdr_packet.metadata.push_back(word); + metadata.push_back(word); num_rx_mdata++; num_rx_bytes += BYTES_PER_CHDR_W; - if (num_rx_mdata == chdr_packet.header.num_mdata) rx_state = ST_PAYLOAD; + if (num_rx_mdata == header.num_mdata) rx_state = ST_PAYLOAD; end ST_PAYLOAD : begin - chdr_packet.data.push_back(word); + data.push_back(word); num_rx_bytes += BYTES_PER_CHDR_W; end endcase end assert (rx_state == ST_PAYLOAD) else begin - $error("ChdrBfm::axis_to_chdr: Malformed CHDR packet"); + $error("ChdrPacket::axis_to_chdr: Malformed CHDR packet"); end // Check length field, noting that the last word may be partially filled - assert (chdr_packet.header.length >= num_rx_bytes-(BYTES_PER_CHDR_W-1) && - chdr_packet.header.length <= num_rx_bytes) else begin - $error("ChdrBfm::axis_to_chdr: Incorrect CHDR length"); + assert (header.length >= num_rx_bytes-(BYTES_PER_CHDR_W-1) && + header.length <= num_rx_bytes) else begin + $error("ChdrPacket::axis_to_chdr: Incorrect CHDR length"); end - - return chdr_packet; - endfunction : axis_to_chdr - // Convert a CHDR packet data structure to a an AXI-Stream packet data + // Convert a CHDR packet data structure to a an AXI-Stream packet data // structure. - function ChdrBfm::AxisPacket_t ChdrBfm::chdr_to_axis (ChdrPacket_t chdr_packet); + function ChdrPacket::AxisPacket_t ChdrPacket::chdr_to_axis (); int num_words, expected_words; data_t bus_word = 0; AxisPacket_t axis_packet = new(); // Check that we have the right number of metadata words - assert (chdr_packet.metadata.size() == chdr_packet.header.num_mdata) else begin - $error("ChdrBfm::chdr_to_axis: Packet metadata size doesn't match header NumMData field"); + assert (metadata.size() == header.num_mdata) else begin + $error("ChdrPacket::chdr_to_axis: Packet metadata size doesn't match header NumMData field"); end // Calculate the number of words needed to represent this packet - num_words = chdr_packet.data.size() + chdr_packet.metadata.size(); - if (chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS && CHDR_W == 64) begin + num_words = data.size() + metadata.size(); + if (header.pkt_type == CHDR_DATA_WITH_TS && CHDR_W == 64) begin // Add two words, one for header and one for timestamp num_words += 2; end else begin // Add one word only for header (which may or may not include a timestamp) num_words += 1; end - + // Calculate the number of words represented by the Length field - expected_words = chdr_packet.header.length / BYTES_PER_CHDR_W; - if (chdr_packet.header.length % BYTES_PER_CHDR_W != 0) expected_words++; + expected_words = header.length / BYTES_PER_CHDR_W; + if (header.length % BYTES_PER_CHDR_W != 0) expected_words++; // Make sure length field matches actual packet length assert (num_words == expected_words) else begin - $error("ChdrBfm::chdr_to_axis: Packet size doesn't match header Length field"); + $error("ChdrPacket::chdr_to_axis: Packet size doesn't match header Length field"); end // Insert header - bus_word[63:0] = chdr_packet.header; + bus_word[63:0] = header; if (CHDR_W == 64) begin axis_packet.data.push_back(bus_word); - if (chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS) begin + if (header.pkt_type == CHDR_DATA_WITH_TS) begin // Insert timestamp - axis_packet.data.push_back(chdr_packet.timestamp); + axis_packet.data.push_back(timestamp); end end else begin - // Copy the timestamp word from the header, regardless of whether or not + // Copy the timestamp word from the header, regardless of whether or not // this packet uses the timestamp field. - bus_word[127:64] = chdr_packet.timestamp; + bus_word[127:64] = timestamp; axis_packet.data.push_back(bus_word); end // Insert metadata - foreach (chdr_packet.metadata[i]) begin - bus_word = chdr_packet.metadata[i]; + foreach (metadata[i]) begin + bus_word = metadata[i]; axis_packet.data.push_back(bus_word); end // Insert payload - foreach (chdr_packet.data[i]) begin - bus_word = chdr_packet.data[i]; + foreach (data[i]) begin + bus_word = data[i]; axis_packet.data.push_back(bus_word); end return axis_packet; - endfunction : chdr_to_axis - + + + + //--------------------------------------------------------------------------- + // CHDR BFM Class Methods + //--------------------------------------------------------------------------- + + // Class constructor. This must be given an interface for the master + // connection and an interface for the slave connection. + function ChdrBfm::new ( + virtual AxiStreamIf #(CHDR_W, USER_WIDTH).master master, + virtual AxiStreamIf #(CHDR_W, USER_WIDTH).slave slave + ); + super.new(master, slave); + assert(CHDR_W % 64 == 0) else begin + $fatal(1, "ChdrBfm::new: CHDR bus width must be a multiple of 64 bits"); + end + endfunction : new + + + // Queue the provided packet for transmission + task ChdrBfm::put_chdr (ChdrPacket_t chdr_packet); + AxisPacket_t axis_packet; + + axis_packet = chdr_packet.chdr_to_axis(); + super.put(axis_packet); + endtask : put_chdr + + + // Attempt to queue the provided packet for transmission. Return 1 if + // successful, return 0 if the queue is full. + function bit ChdrBfm::try_put_chdr (ChdrPacket_t chdr_packet); + AxisPacket_t axis_packet; + bit status; + + axis_packet = chdr_packet.chdr_to_axis(); + return super.try_put(axis_packet); + endfunction : try_put_chdr + + + // Get the next packet when it becomes available (wait if necessary) + task ChdrBfm::get_chdr (output ChdrPacket_t chdr_packet); + AxisPacket_t axis_packet; + super.get(axis_packet); + chdr_packet = new(); + chdr_packet.axis_to_chdr(axis_packet); + endtask : get_chdr + + + // Get the next packet if there's one available and return 1. Return 0 if + // there's no packet available. + function bit ChdrBfm::try_get_chdr (output ChdrPacket_t chdr_packet); + AxisPacket_t axis_packet; + if (!super.try_get(axis_packet)) return 0; + chdr_packet = new(); + chdr_packet.axis_to_chdr(axis_packet); + return 1; + endfunction : try_get_chdr + + + // Get the next packet when it becomes available (wait if necessary), but + // don't remove it from the receive queue. + task ChdrBfm::peek_chdr (output ChdrPacket_t chdr_packet); + AxisPacket_t axis_packet; + super.peek(axis_packet); + chdr_packet = new(); + chdr_packet.axis_to_chdr(axis_packet); + endtask : peek_chdr + + + // Get the next packet if there's one available and return 1, but don't + // remove it from the receive queue. Return 0 if there's no packet available. + function bit ChdrBfm::try_peek_chdr (output ChdrPacket_t chdr_packet); + AxisPacket_t axis_packet; + if (!super.try_get(axis_packet)) return 0; + chdr_packet = new(); + chdr_packet.axis_to_chdr(axis_packet); + return 1; + endfunction : try_peek_chdr endpackage : PkgChdrBfm diff --git a/fpga/usrp3/sim/rfnoc/PkgRfnocItemUtils.sv b/fpga/usrp3/sim/rfnoc/PkgRfnocItemUtils.sv index f827d2363..64d39e63f 100644 --- a/fpga/usrp3/sim/rfnoc/PkgRfnocItemUtils.sv +++ b/fpga/usrp3/sim/rfnoc/PkgRfnocItemUtils.sv @@ -134,7 +134,7 @@ package PkgRfnocItemUtils; // Check if the contents of two buffers is equal function bit equal( - ItemDataBuff #(item_t) rhs + ItemDataBuff #(item_t,CHDR_W) rhs ); if (this.size() != rhs.size()) return 0; for (int i = 0; i < this.size(); i++) begin diff --git a/fpga/usrp3/sim/rfnoc/PkgTestExec.sv b/fpga/usrp3/sim/rfnoc/PkgTestExec.sv index ba4455912..4138fca86 100644 --- a/fpga/usrp3/sim/rfnoc/PkgTestExec.sv +++ b/fpga/usrp3/sim/rfnoc/PkgTestExec.sv @@ -5,7 +5,7 @@ // // Module: PkgTestExec // -// Description: This package provides infrastructure for tracking the state of +// Description: This package provides infrastructure for tracking the state of // testbench execution and the results of each test. // @@ -29,6 +29,7 @@ package PkgTestExec; int num_assertions; // Number of assertions checked for the current test time start_time, end_time; // Start and end time of the testbench bit stop_on_error = 1; // Configuration option to stop when an error occurs + bit done = 0; // Flag that sets when tb is finished bit test_status[$]; // Pass/fail status of each test timeout_t tb_timeout; // Handle to timeout for the overall testbench @@ -54,7 +55,7 @@ package PkgTestExec; // Get the sempahore, to prevent multiple overlapping instances of the // same testbench. test_sem.get(); - + done = 0; $display("========================================================"); $display("TESTBENCH STARTED: %s", tb_name); $display("========================================================"); @@ -65,8 +66,8 @@ package PkgTestExec; num_finished = 0; num_passed = 0; start_timeout( - tb_timeout, - time_limit, + tb_timeout, + time_limit, $sformatf("Testbench \"%s\" time limit exceeded", tb_name), SEV_FATAL ); @@ -75,7 +76,7 @@ package PkgTestExec; // Call end_tb() at the end of a testbench to report final statistics and, // optionally, end simulation. - // + // // finish: Set to 1 (default) to cause $finish() to be called at the // end of simulation, cuasing the simulator to close. // @@ -83,7 +84,6 @@ package PkgTestExec; assert (num_started == num_finished) else begin $fatal(1, "Testbench ended before test completed"); end - end_time = $time; $display("========================================================"); $display("TESTBENCH FINISHED: %s", tb_name); @@ -98,6 +98,7 @@ package PkgTestExec; end_timeout(tb_timeout); + done = 1; if (finish) $finish(); // Release the semaphore to allow new instances of the testbench to run @@ -118,8 +119,8 @@ package PkgTestExec; // Create a timeout for this test if (time_limit > 0) begin start_timeout( - test_timeout, - time_limit, + test_timeout, + time_limit, $sformatf("Test \"%s\" time limit exceeded", test_name), SEV_FATAL ); @@ -133,7 +134,7 @@ package PkgTestExec; endtask : start_test - // Call end_test() at the end of each test. + // Call end_test() at the end of each test. // // test_result: Optional value to indicate the overall pass/fail result // of the test. Use non-zero for pass, 0 for fail. @@ -149,7 +150,7 @@ package PkgTestExec; passed = test_status[num_started-1] && test_result; num_finished++; - $display("[TEST CASE %3d] (t = %t) DONE... %s", + $display("[TEST CASE %3d] (t = %t) DONE... %s", num_started, $time, passed ? "Passed" : "FAILED"); if (passed) num_passed++; @@ -163,7 +164,7 @@ package PkgTestExec; // // expr: The expression value to be asserted // message: String to report if the assertion fails - // + // function void assert_error(int expr, string message = ""); num_assertions++; assert (expr) else begin @@ -178,7 +179,7 @@ package PkgTestExec; // // expr: The expression value to be asserted // message: String to report if the assertion fails - // + // function void assert_fatal(int expr, string message = ""); num_assertions++; assert (expr) else begin @@ -192,7 +193,7 @@ package PkgTestExec; // // expr: The expression value to be asserted // message: String to report if the assertion fails - // + // function void assert_warning(int expr, string message = ""); num_assertions++; assert (expr) else begin @@ -209,7 +210,7 @@ package PkgTestExec; // severity: Indicates the type of severity task that should be used if // the assertion fails ($info, $warning, $error, $fatal). // Default value is SEV_ERROR. - // + // function void assert_sev( int expr, string message = "", @@ -249,8 +250,8 @@ package PkgTestExec; // used if the timeout expires. Default is SEV_ERROR. // task start_timeout( - output timeout_t handle, - input realtime timeout_delay, + output timeout_t handle, + input realtime timeout_delay, input string message = "Timeout", input severity_t severity = SEV_ERROR ); |