diff options
author | Wade Fife <wade.fife@ettus.com> | 2020-02-24 13:41:20 -0600 |
---|---|---|
committer | Wade Fife <wade.fife@ettus.com> | 2020-03-09 13:43:05 -0500 |
commit | 6f42ab7c1c962bfc425b6790fe41b2c14769e561 (patch) | |
tree | 5e278cc8bb3aba7898ed3ae4bb100e69fe17a7a5 /fpga/usrp3/sim | |
parent | bb6293bc60ccaf13632f9367617e3dfb4a057f9a (diff) | |
download | uhd-6f42ab7c1c962bfc425b6790fe41b2c14769e561.tar.gz uhd-6f42ab7c1c962bfc425b6790fe41b2c14769e561.tar.bz2 uhd-6f42ab7c1c962bfc425b6790fe41b2c14769e561.zip |
sim: Add ChdrIfaceBfm test
Diffstat (limited to 'fpga/usrp3/sim')
-rw-r--r-- | fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv | 5 | ||||
-rw-r--r-- | fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv | 11 | ||||
-rw-r--r-- | fpga/usrp3/sim/rfnoc/test/ChdrIfaceBfm/ChdrIfaceBfm_all_tb.sv | 53 | ||||
-rw-r--r-- | fpga/usrp3/sim/rfnoc/test/ChdrIfaceBfm/ChdrIfaceBfm_tb.sv | 579 | ||||
-rw-r--r-- | fpga/usrp3/sim/rfnoc/test/ChdrIfaceBfm/Makefile | 32 |
5 files changed, 675 insertions, 5 deletions
diff --git a/fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv b/fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv index 5863bb598..908447806 100644 --- a/fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv +++ b/fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv @@ -569,8 +569,9 @@ package PkgChdrBfm; $fatal(1, "ChdrPacket::update_lengths(): Calculated NumMData exceeds maximum size"); // Calculate the Length field - num_bytes = data.size() * BYTES_PER_CHDR_W; // Payload length - num_bytes = num_bytes + header_bytes() + mdata_bytes(); // Payload + header length + num_bytes = header_bytes() + // Header + num_mdata * BYTES_PER_CHDR_W + // Metadata + data.size() * BYTES_PER_CHDR_W; // Payload assert(num_bytes < 2**$bits(chdr_length_t)) else $fatal(1, "ChdrPacket::update_lengths(): Calculated Length exceeds maximum size"); diff --git a/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv b/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv index 243987d68..a25f29d18 100644 --- a/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv +++ b/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv @@ -50,10 +50,15 @@ package PkgChdrIfaceBfm; virtual AxiStreamIf #(CHDR_W).master m_chdr, virtual AxiStreamIf #(CHDR_W).slave s_chdr, input int max_payload_length = 2**$bits(chdr_length_t), - input int ticks_per_word = CHDR_W/32 + input int ticks_per_word = CHDR_W/ITEM_W ); super.new(m_chdr, s_chdr); this.seq_num = 0; + + assert (CHDR_W % ITEM_W == 0) else begin + $fatal(1, "ChdrIfaceBfm::new: CHDR_W must be a multiple of ITEM_W"); + end + set_max_payload_length(max_payload_length); set_ticks_per_word(ticks_per_word); endfunction : new @@ -189,7 +194,7 @@ package PkgChdrIfaceBfm; if (data_bytes < 0) data_bytes = data.size() * BYTES_PER_CHDR_W; // Make sure there's not too much metadata for this number of packets - assert(metadata.size()*$bits(chdr_word_t) < num_pkts * 2**$bits(chdr_num_mdata_t) * CHDR_W) else + assert(metadata.size() <= num_pkts * (2**$bits(chdr_num_mdata_t)-1)) else $fatal(1, "ChdrIfaceBfm::send: Too much metadata for this send request"); // Send the data, one packet at a time. @@ -204,7 +209,7 @@ package PkgChdrIfaceBfm; payload_length = data_bytes - (num_pkts-1) * max_payload_length; first_dword = i*max_payload_length/BYTES_PER_CHDR_W; last_dword = data.size()-1; - first_mword = i*(2**$bits(chdr_num_mdata_t) * CHDR_W / $bits(chdr_word_t)); + first_mword = i*(2**$bits(chdr_num_mdata_t)-1); last_mword = metadata.size()-1; end else begin // A full-sized packet, not the last diff --git a/fpga/usrp3/sim/rfnoc/test/ChdrIfaceBfm/ChdrIfaceBfm_all_tb.sv b/fpga/usrp3/sim/rfnoc/test/ChdrIfaceBfm/ChdrIfaceBfm_all_tb.sv new file mode 100644 index 000000000..30d72050c --- /dev/null +++ b/fpga/usrp3/sim/rfnoc/test/ChdrIfaceBfm/ChdrIfaceBfm_all_tb.sv @@ -0,0 +1,53 @@ +// +// Copyright 2020 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: ChdrIfaceBfm_all_tb +// +// Description: +// +// This is the top-level testbench that instantiates multiple instances of +// the ChdrIfaceBfm_tb testbench to test different parameters. +// + +module ChdrIfaceBfm_all_tb(); + + `include "test_exec.svh" + + //--------------------------------------------------------------------------- + // Test Definitions + //--------------------------------------------------------------------------- + + typedef struct { + int CHDR_W; + int ITEM_W; + } test_config_t; + + localparam NUM_TESTS = 8; + + localparam test_config_t tests[NUM_TESTS] = '{ + '{ CHDR_W: 64, ITEM_W: 8 }, + '{ CHDR_W: 64, ITEM_W: 16 }, + '{ CHDR_W: 64, ITEM_W: 32 }, + '{ CHDR_W: 64, ITEM_W: 64 }, + '{ CHDR_W: 128, ITEM_W: 8 }, + '{ CHDR_W: 128, ITEM_W: 16 }, + '{ CHDR_W: 128, ITEM_W: 32 }, + '{ CHDR_W: 128, ITEM_W: 64 } + }; + + + //--------------------------------------------------------------------------- + // DUT Instances + //--------------------------------------------------------------------------- + + genvar i; + for (i = 0; i < NUM_TESTS; i++) begin : gen_test_config + ChdrIfaceBfm_tb #( + .CHDR_W (tests[i].CHDR_W), + .ITEM_W (tests[i].ITEM_W) + ) ChdrIfaceBfm_tb_i (); + end : gen_test_config + +endmodule : ChdrIfaceBfm_all_tb diff --git a/fpga/usrp3/sim/rfnoc/test/ChdrIfaceBfm/ChdrIfaceBfm_tb.sv b/fpga/usrp3/sim/rfnoc/test/ChdrIfaceBfm/ChdrIfaceBfm_tb.sv new file mode 100644 index 000000000..bf771ac49 --- /dev/null +++ b/fpga/usrp3/sim/rfnoc/test/ChdrIfaceBfm/ChdrIfaceBfm_tb.sv @@ -0,0 +1,579 @@ +// +// Copyright 2020 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: ChdrIfaceBfm_tb +// +// Description: This is the testbench for the ChdrIfaceBfm class. +// + +module ChdrIfaceBfm_tb #( + parameter int CHDR_W = 64, + parameter int ITEM_W = 32, + parameter int SPP = 64 +); + + `include "test_exec.svh" + + import PkgTestExec::*; + import PkgChdrUtils::*; + import PkgChdrIfaceBfm::*; + + + //--------------------------------------------------------------------------- + // Simulation Constants + //--------------------------------------------------------------------------- + + localparam bit VERBOSE = 0; // Set to 1 for more display output + + localparam realtime CLOCK_PER = 10.0ns; + + localparam int WPP = SPP * ITEM_W / CHDR_W; // CHDR words per packet + localparam int BYTES_PER_ITEM = ITEM_W/8; + localparam int MAX_PYLD_BYTES = SPP * BYTES_PER_ITEM; + localparam int MAX_PACKETS = 3; + + + //--------------------------------------------------------------------------- + // Clocks and Resets + //--------------------------------------------------------------------------- + + bit rfnoc_chdr_clk; + + sim_clock_gen #(CLOCK_PER) rfnoc_chdr_clk_gen (.clk(rfnoc_chdr_clk), .rst()); + + + //--------------------------------------------------------------------------- + // CHDR Types + //--------------------------------------------------------------------------- + + typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t; + typedef ChdrData #(CHDR_W, ITEM_W)::item_t item_t; + + ChdrData #(CHDR_W, ITEM_W) chdr_data; + + + //--------------------------------------------------------------------------- + // BFM + //--------------------------------------------------------------------------- + + AxiStreamIf #(CHDR_W) chdr_ifc (rfnoc_chdr_clk, 1'b0); + + // Loop the CHDR BFM back to itself + ChdrIfaceBfm #(CHDR_W, ITEM_W) bfm = new(chdr_ifc, chdr_ifc, MAX_PYLD_BYTES); + + + //--------------------------------------------------------------------------- + // Data Structures + //--------------------------------------------------------------------------- + + typedef struct { + chdr_word_t data[$]; + int data_bytes; + chdr_word_t metadata[$]; + packet_info_t pkt_info; + } packet_t; + + typedef enum int { + TEST_RECV, TEST_RECV_ADV, TEST_NUM_ITEMS, TEST_EOB, TEST_EOV + } test_variant_t; + + + //--------------------------------------------------------------------------- + // Utilities + //--------------------------------------------------------------------------- + + // Rand#(WIDTH)::rand_logic() returns a WIDTH-bit random number. We avoid + // std::randomize() due to license requirements and limited tool support. + class Rand #(WIDTH = 32); + + static function logic [WIDTH-1:0] rand_logic(); + logic [WIDTH-1:0] result; + int num_rand32 = (WIDTH + 31) / 32; + for (int i = 0; i < num_rand32; i++) begin + result = {result, $urandom()}; + end + return result; + endfunction : rand_logic + + endclass : Rand + + + // Generate a random packet, in the form of a random packet_t structure. + // + // packets: Generate multiple packets worth of data if 1, generate 1 + // packet if 0. + // items: Make the data a multiple of items if 1, a of bytes if 0. + // + function automatic packet_t rand_pkt(bit packets = 0, bit items = 0); + packet_t packet; + int num_mdata; + int num_packets; + + // Decide how many packets we're going to generate + if (packets) num_packets = $urandom_range(1, MAX_PACKETS); + else num_packets = 1; + + // Decide how much metadata, assuming we can split it across multiple + // packets. + num_mdata = $urandom_range(0, num_packets*(31)); + + // Randomize the rest of the packet info + packet.pkt_info = Rand#($bits(packet.pkt_info))::rand_logic(); + + // Decide how much data we're going to send. The last packet will be a + // random length, all preceding packets will be full length. + if (items) packet.data_bytes = $urandom_range(1, SPP) * BYTES_PER_ITEM; + else packet.data_bytes = $urandom_range(1, SPP*BYTES_PER_ITEM); + packet.data_bytes += (num_packets-1) * MAX_PYLD_BYTES; + + // Generate random data and metadata + packet.data = {}; + for (int bytes = 0; bytes < packet.data_bytes; bytes += (CHDR_W/8)) + packet.data.push_back(Rand#(CHDR_W)::rand_logic()); + packet.metadata = {}; + for (int words = 0; words < num_mdata; words++) + packet.metadata.push_back(Rand#(CHDR_W)::rand_logic()); + + // Zero the timestamp if there's no time, since that's what the BFM will + // return in that case for the time. + if (packet.pkt_info.has_time == 0) packet.pkt_info.timestamp = 0; + + return packet; + endfunction : rand_pkt + + + //--------------------------------------------------------------------------- + // Test Tasks + //--------------------------------------------------------------------------- + + task test_send(test_variant_t test_type); + packet_t send_pkt, recv_pkt; + + // Generate a random packet + send_pkt = rand_pkt(0, 0); + if (VERBOSE) begin + $display("test_send: data_bytes = %04d, num_mdata = %02d, pkt_info = %p", + send_pkt.data_bytes, send_pkt.metadata.size(), send_pkt.pkt_info); + end + + // Send then receive it + bfm.send(send_pkt.data, send_pkt.data_bytes, send_pkt.metadata, send_pkt.pkt_info); + + if (test_type == TEST_RECV_ADV) begin + bfm.recv_adv(recv_pkt.data, recv_pkt.data_bytes, recv_pkt.metadata, recv_pkt.pkt_info); + + // Check if the metadata and packet info matches what we sent + `ASSERT_ERROR(chdr_data.chdr_equal(send_pkt.metadata, recv_pkt.metadata), "Metadata did not match"); + `ASSERT_ERROR(send_pkt.pkt_info == recv_pkt.pkt_info, "Packet info did not match"); + end else begin + bfm.recv(recv_pkt.data, recv_pkt.data_bytes); + end + + // Check if we received the data what we sent + `ASSERT_ERROR(chdr_data.chdr_equal(send_pkt.data, recv_pkt.data), "Data did not match"); + `ASSERT_ERROR(send_pkt.data_bytes == recv_pkt.data_bytes, "Data byte length did not match"); + endtask : test_send + + + task test_send_items(); + packet_t send_pkt, recv_pkt; + item_t send_items[$], recv_items[$]; + + // Generate a random packet + send_pkt = rand_pkt(0, 1); + if (VERBOSE) begin + $display("test_send_items: data_bytes = %04d, num_mdata = %02d, pkt_info = %p", + send_pkt.data_bytes, send_pkt.metadata.size(), send_pkt.pkt_info); + end + + // Send then receive it, converting between CHDR and item words + send_items = chdr_data.chdr_to_item(send_pkt.data, send_pkt.data_bytes); + bfm.send_items(send_items, send_pkt.metadata, send_pkt.pkt_info); + bfm.recv_items_adv(recv_items, recv_pkt.metadata, recv_pkt.pkt_info); + + // Check if we received what we sent + `ASSERT_ERROR(chdr_data.item_equal(send_items, recv_items), "Data did not match"); + `ASSERT_ERROR(chdr_data.chdr_equal(send_pkt.metadata, recv_pkt.metadata), "Metadata did not match"); + `ASSERT_ERROR(send_pkt.pkt_info == recv_pkt.pkt_info, "Packet info did not match"); + endtask : test_send_items + + + task test_send_packets(); + packet_t send_pkt, recv_pkt; + int num_packets; + int data_index, mdata_index; + packet_info_t pkt_info; + + // Generate a random packet + send_pkt = rand_pkt(1, 0); + if (VERBOSE) begin + $display("test_send_packets: data_bytes = %04d, num_mdata = %02d, pkt_info = %p", + send_pkt.data_bytes, send_pkt.metadata.size(), send_pkt.pkt_info); + end + + // Send the packet data, all at once + bfm.send_packets(send_pkt.data, send_pkt.data_bytes, send_pkt.metadata, send_pkt.pkt_info); + + // Receive and check all the generated packets + num_packets = (send_pkt.data_bytes + MAX_PYLD_BYTES - 1) / MAX_PYLD_BYTES; + data_index = 0; + mdata_index = 0; + pkt_info = send_pkt.pkt_info; + pkt_info.eob = 0; // EOB/EOV should only be set for last packet + pkt_info.eov = 0; + for (int pkt_count = 0; pkt_count < num_packets; pkt_count++) begin + int exp_byte_length; + int exp_word_length; + int exp_num_mdata; + chdr_word_t temp_queue[$]; + + // Calculate the length of the next packet + if (pkt_count < num_packets-1) begin + exp_byte_length = MAX_PYLD_BYTES; + end else begin + // Last packet's length is whatever is left + exp_byte_length = send_pkt.data_bytes - pkt_count * MAX_PYLD_BYTES; + end + exp_word_length = (exp_byte_length + (CHDR_W/8) - 1) / (CHDR_W/8); + + // Calculate how much metadata we have left for the next packet + exp_num_mdata = send_pkt.metadata.size() - (pkt_count * 31); + if (exp_num_mdata > 31) exp_num_mdata = 31; // Up to 31 words per packet + if (exp_num_mdata < 0) exp_num_mdata = 0; // No less than 0 + + // Receive the next packet + bfm.recv_adv(recv_pkt.data, recv_pkt.data_bytes, recv_pkt.metadata, recv_pkt.pkt_info); + + // Check the data length of the received packet + `ASSERT_ERROR( + exp_byte_length == recv_pkt.data_bytes, + $sformatf( + "Length of packet %0d didn't match (received %0d, expected %0d)", + pkt_count, recv_pkt.data_bytes, exp_byte_length + ) + ); + + // Check the data contents + temp_queue = send_pkt.data[data_index:data_index+exp_word_length-1]; + `ASSERT_ERROR( + chdr_data.chdr_equal(temp_queue, recv_pkt.data), + "Data did not match" + ); + + // Check the metadata contents + if (exp_num_mdata > 0) begin + temp_queue = send_pkt.metadata[mdata_index:mdata_index+exp_num_mdata-1]; + `ASSERT_ERROR( + chdr_data.chdr_equal(temp_queue, recv_pkt.metadata), + "Metadata did not match" + ); + end + + // Check the pkt_info + if (pkt_count < num_packets-1) begin + // Not the last packet + `ASSERT_ERROR( + pkt_info == recv_pkt.pkt_info, + $sformatf("Packet info did not match on packet %0d", pkt_count) + ); + end else begin + // This is the last packet + pkt_info.eob = send_pkt.pkt_info.eob; + pkt_info.eov = send_pkt.pkt_info.eov; + `ASSERT_ERROR( + pkt_info == recv_pkt.pkt_info, + $sformatf("Packet info did not match on packet %0d (last packet)", pkt_count) + ); + end + + // Update counters for next iteration + if (pkt_info.has_time) pkt_info.timestamp += exp_word_length * CHDR_W/ITEM_W; + data_index += exp_word_length; + mdata_index += exp_num_mdata; + end + + endtask : test_send_packets + + + task test_send_packets_items(); + packet_t send_pkt, recv_pkt; + int num_packets; + int data_index, mdata_index; + packet_info_t pkt_info; + item_t send_items[$], recv_items[$]; + + // Generate a random packet + send_pkt = rand_pkt(1, 1); + if (VERBOSE) begin + $display("test_send_packets_items: data_bytes = %04d, num_mdata = %02d, pkt_info = %p", + send_pkt.data_bytes, send_pkt.metadata.size(), send_pkt.pkt_info); + end + + // Send the packet data, all at once + send_items = chdr_data.chdr_to_item(send_pkt.data, send_pkt.data_bytes); + bfm.send_packets_items(send_items, send_pkt.metadata, send_pkt.pkt_info); + + // Receive and check all the generated packets + num_packets = (send_pkt.data_bytes + MAX_PYLD_BYTES - 1) / MAX_PYLD_BYTES; + data_index = 0; + mdata_index = 0; + pkt_info = send_pkt.pkt_info; + pkt_info.eob = 0; // EOB/EOV should only be set for last packet + pkt_info.eov = 0; + for (int pkt_count = 0; pkt_count < num_packets; pkt_count++) begin + int exp_byte_length; + int exp_word_length; + int exp_num_mdata; + chdr_word_t temp_queue[$]; + + // Calculate the length of the next packet + if (pkt_count < num_packets-1) begin + exp_byte_length = MAX_PYLD_BYTES; + end else begin + // Last packet's length is whatever is left + exp_byte_length = send_pkt.data_bytes - pkt_count * MAX_PYLD_BYTES; + end + exp_word_length = (exp_byte_length + (CHDR_W/8) - 1) / (CHDR_W/8); + + // Calculate how much metadata we have left for the next packet + exp_num_mdata = send_pkt.metadata.size() - (pkt_count * 31); + if (exp_num_mdata > 31) exp_num_mdata = 31; // Up to 31 words per packet + if (exp_num_mdata < 0) exp_num_mdata = 0; // No less than 0 + + // Receive the next packet + bfm.recv_items_adv(recv_items, recv_pkt.metadata, recv_pkt.pkt_info); + recv_pkt.data_bytes = recv_items.size() * (ITEM_W/8); + recv_pkt.data = chdr_data.item_to_chdr(recv_items); + + // Check the data length of the received packet + `ASSERT_ERROR( + exp_byte_length == recv_pkt.data_bytes, + $sformatf( + "Length of packet %0d didn't match (received %0d, expected %0d)", + pkt_count, recv_pkt.data_bytes, exp_byte_length + ) + ); + + // Check the data contents + temp_queue = send_pkt.data[data_index:data_index+exp_word_length-1]; + `ASSERT_ERROR( + chdr_data.chdr_equal(temp_queue, recv_pkt.data), + "Data did not match" + ); + + // Check the metadata contents + if (exp_num_mdata > 0) begin + temp_queue = send_pkt.metadata[mdata_index:mdata_index+exp_num_mdata-1]; + `ASSERT_ERROR( + chdr_data.chdr_equal(temp_queue, recv_pkt.metadata), + "Metadata did not match" + ); + end + + // Check the pkt_info + if (pkt_count < num_packets-1) begin + // Not the last packet + `ASSERT_ERROR( + pkt_info == recv_pkt.pkt_info, + $sformatf("Packet info did not match on packet %0d", pkt_count) + ); + end else begin + // This is the last packet + pkt_info.eob = send_pkt.pkt_info.eob; + pkt_info.eov = send_pkt.pkt_info.eov; + `ASSERT_ERROR( + pkt_info == recv_pkt.pkt_info, + $sformatf("Packet info did not match on packet %0d (last packet)", pkt_count) + ); + end + + // Update counters for next iteration + if (pkt_info.has_time) pkt_info.timestamp += exp_word_length * CHDR_W/ITEM_W; + data_index += exp_word_length; + mdata_index += exp_num_mdata; + end + + endtask : test_send_packets_items + + + task test_recv_packets_items(test_variant_t test_type); + packet_t send_pkt, recv_pkt; + item_t send_items[$], recv_items[$]; + chdr_word_t recv_metadata[$]; + + // Generate a random packet + send_pkt = rand_pkt(1, 1); + if (VERBOSE) begin + $display("test_recv_packets_items: data_bytes = %04d, num_mdata = %02d, pkt_info = %p", + send_pkt.data_bytes, send_pkt.metadata.size(), send_pkt.pkt_info); + end + + // Set the flags, if needed + case (test_type) + TEST_EOB : + send_pkt.pkt_info.eob = 1; + TEST_EOV : + send_pkt.pkt_info.eov = 1; + endcase + + // Send the packet data, all at once + send_items = chdr_data.chdr_to_item(send_pkt.data, send_pkt.data_bytes); + bfm.send_packets_items(send_items, send_pkt.metadata, send_pkt.pkt_info); + + // Receive the data, all at once + case (test_type) + TEST_NUM_ITEMS : + bfm.recv_packets_items( + recv_items, send_items.size()); + TEST_EOB : + bfm.recv_packets_items( + recv_items, /* num_samps */, 1, 0); + TEST_EOV : + bfm.recv_packets_items + (recv_items, /* num_samps */, 0, 1); + endcase + + // Check if we received what we sent + `ASSERT_ERROR(chdr_data.item_equal(send_items, recv_items), "Data did not match"); + + endtask : test_recv_packets_items + + + task test_recv_packets_items_adv(test_variant_t test_type); + packet_t send_pkt, recv_pkt; + item_t send_items[$], recv_items[$]; + chdr_word_t recv_metadata[$]; + + // Generate a random packet + send_pkt = rand_pkt(1, 1); + if (VERBOSE) begin + $display("test_recv_packets_items_adv: data_bytes = %04d, num_mdata = %02d, pkt_info = %p", + send_pkt.data_bytes, send_pkt.metadata.size(), send_pkt.pkt_info); + end + + // Set the flags, if needed + case (test_type) + TEST_EOB : + send_pkt.pkt_info.eob = 1; + TEST_EOV : + send_pkt.pkt_info.eov = 1; + endcase + + // Send the packet data, all at once + send_items = chdr_data.chdr_to_item(send_pkt.data, send_pkt.data_bytes); + bfm.send_packets_items(send_items, send_pkt.metadata, send_pkt.pkt_info); + + // Receive the data, all at once + case (test_type) + TEST_NUM_ITEMS : + bfm.recv_packets_items_adv( + recv_items, recv_pkt.metadata, recv_pkt.pkt_info, send_items.size()); + TEST_EOB : + bfm.recv_packets_items_adv( + recv_items, recv_pkt.metadata, recv_pkt.pkt_info, /* num_samps */, 1, 0); + TEST_EOV : + bfm.recv_packets_items_adv + (recv_items, recv_pkt.metadata, recv_pkt.pkt_info, /* num_samps */, 0, 1); + endcase + + // Check if we received what we sent + `ASSERT_ERROR(chdr_data.item_equal(send_items, recv_items), "Data did not match"); + `ASSERT_ERROR(chdr_data.chdr_equal(send_pkt.metadata, recv_pkt.metadata), "Metadata did not match"); + `ASSERT_ERROR(send_pkt.pkt_info == recv_pkt.pkt_info, "Packet info did not match"); + + endtask : test_recv_packets_items_adv + + + //--------------------------------------------------------------------------- + // Main Test Process + //--------------------------------------------------------------------------- + + initial begin : tb_main + string tb_name; + + //------------------------------------------------------------------------- + // Initialization + //------------------------------------------------------------------------- + + // Generate a string for the name of this instance of the testbench + tb_name = $sformatf( + "ChdrIfaceBfm_tb\nCHDR_W = %0d, ITEM_W = %0d", + CHDR_W, ITEM_W + ); + + // We're not testing flow control, only correct data generate and + // extraction, so there's not need to stall on the CHDR interface. + bfm.set_slave_stall_prob(0); + bfm.set_master_stall_prob(0); + + // Start the BFM runnings + bfm.run(); + + test.start_tb(tb_name, 100ms); + + + //------------------------------------------------------------------------- + // Test Sequences + //------------------------------------------------------------------------- + + test.start_test("Test send() / recv()", 10ms); + for (int i = 0; i < 1000; i++) test_send(TEST_RECV); + test.end_test(); + + test.start_test("Test send() / recv_adv()", 10ms); + for (int i = 0; i < 1000; i++) test_send(TEST_RECV_ADV); + test.end_test(); + + test.start_test("Test send_items() / recv_items_adv()", 10ms); + for (int i = 0; i < 1000; i++) test_send_items(); + test.end_test(); + + test.start_test("Test send_packets() / recv_adv()", 10ms); + for (int i = 0; i < 1000; i++) test_send_packets(); + test.end_test(); + + test.start_test("Test send_packets_items() / recv_items_adv()", 10ms); + for (int i = 0; i < 1000; i++) test_send_packets_items(); + test.end_test(); + + test.start_test("Test send_packets_items() / recv_packets_items(num_items)", 10ms); + for (int i = 0; i < 1000; i++) test_recv_packets_items(TEST_NUM_ITEMS); + test.end_test(); + + test.start_test("Test send_packets_items() / recv_packets_items(eob)", 10ms); + for (int i = 0; i < 1000; i++) test_recv_packets_items(TEST_EOB); + test.end_test(); + + test.start_test("Test send_packets_items() / recv_packets_items(eov)", 10ms); + for (int i = 0; i < 1000; i++) test_recv_packets_items(TEST_EOV); + test.end_test(); + + test.start_test("Test send_packets_items() / recv_packets_items_adv(num_items)", 10ms); + for (int i = 0; i < 1000; i++) test_recv_packets_items_adv(TEST_NUM_ITEMS); + test.end_test(); + + test.start_test("Test send_packets_items() / recv_packets_items_adv(eob)", 10ms); + for (int i = 0; i < 1000; i++) test_recv_packets_items_adv(TEST_EOB); + test.end_test(); + + test.start_test("Test send_packets_items() / recv_packets_items_adv(eov)", 10ms); + for (int i = 0; i < 1000; i++) test_recv_packets_items_adv(TEST_EOV); + test.end_test(); + + // Make sure we don't get any more packets. Wait for more than a packet of + // worth of time the check if we've received anything. + #(CLOCK_PER * WPP * 8); + `ASSERT_ERROR(bfm.num_received() == 0, "Received unexpected packets"); + + // End the TB, but don't $finish, since we don't want to kill other + // instances of this testbench that may be running. + test.end_tb(0); + + // Kill the clocks to end this instance of the testbench + rfnoc_chdr_clk_gen.kill(); + + end + +endmodule : ChdrIfaceBfm_tb diff --git a/fpga/usrp3/sim/rfnoc/test/ChdrIfaceBfm/Makefile b/fpga/usrp3/sim/rfnoc/test/ChdrIfaceBfm/Makefile new file mode 100644 index 000000000..a4931f945 --- /dev/null +++ b/fpga/usrp3/sim/rfnoc/test/ChdrIfaceBfm/Makefile @@ -0,0 +1,32 @@ +# +# Copyright 2020 Ettus Research, A National Instruments Company +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# + +#------------------------------------------------- +# Top-of-Makefile +#------------------------------------------------- +# Define BASE_DIR to point to the "top" dir +BASE_DIR = $(abspath ../../../../top) +# Include viv_sim_preamble after defining BASE_DIR +include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak + +#------------------------------------------------- +# Testbench Specific +#------------------------------------------------- +# Define only one toplevel module +SIM_TOP = ChdrIfaceBfm_tb + +# Add test bench, user design under test, and +# additional user created files +SIM_SRCS = \ +$(abspath ChdrIfaceBfm_tb.sv) + +#------------------------------------------------- +# Bottom-of-Makefile +#------------------------------------------------- +# Include all simulator specific makefiles here +# Each should define a unique target to simulate +# e.g. xsim, vsim, etc and a common "clean" target +include $(BASE_DIR)/../tools/make/viv_simulator.mak |