diff options
8 files changed, 420 insertions, 40 deletions
diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_axi_ram_fifo/rfnoc_block_axi_ram_fifo_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_axi_ram_fifo/rfnoc_block_axi_ram_fifo_tb.sv index e4753e92f..5fc9e71fb 100644 --- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_axi_ram_fifo/rfnoc_block_axi_ram_fifo_tb.sv +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_axi_ram_fifo/rfnoc_block_axi_ram_fifo_tb.sv @@ -92,7 +92,7 @@ module rfnoc_block_axi_ram_fifo_tb #( AxiStreamIf #(CHDR_W) s_chdr [NUM_PORTS] (rfnoc_chdr_clk, 1'b0); // Bus functional model for a software block controller - RfnocBlockCtrlBfm #(.CHDR_W(CHDR_W)) blk_ctrl = + RfnocBlockCtrlBfm #(CHDR_W) blk_ctrl = new(backend, m_ctrl, s_ctrl); // Connect block controller to BFMs diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_ddc/rfnoc_block_ddc_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_ddc/rfnoc_block_ddc_tb.sv index e6f2c4d6b..fbb017fb5 100644 --- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_ddc/rfnoc_block_ddc_tb.sv +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_ddc/rfnoc_block_ddc_tb.sv @@ -70,7 +70,7 @@ module rfnoc_block_ddc_tb(); AxiStreamIf #(CHDR_W) s_chdr [NUM_PORTS] (rfnoc_chdr_clk, 1'b0); // Bus functional model for a software block controller - RfnocBlockCtrlBfm #(.CHDR_W(CHDR_W)) blk_ctrl = + RfnocBlockCtrlBfm #(CHDR_W, SAMP_W) blk_ctrl = new(backend, m_ctrl, s_ctrl); // Connect block controller to BFMs diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_duc/rfnoc_block_duc_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_duc/rfnoc_block_duc_tb.sv index 8151ed761..7af3bc9b4 100644 --- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_duc/rfnoc_block_duc_tb.sv +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_duc/rfnoc_block_duc_tb.sv @@ -70,7 +70,7 @@ module rfnoc_block_duc_tb(); AxiStreamIf #(CHDR_W) s_chdr [NUM_PORTS] (rfnoc_chdr_clk, 1'b0); // Bus functional model for a software block controller - RfnocBlockCtrlBfm #(.CHDR_W(CHDR_W)) blk_ctrl = + RfnocBlockCtrlBfm #(CHDR_W, SAMP_W) blk_ctrl = new(backend, m_ctrl, s_ctrl); // Connect block controller to BFMs diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft_tb.sv index 412963dc7..0f442ddd4 100644 --- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft_tb.sv +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft_tb.sv @@ -70,7 +70,7 @@ module rfnoc_block_fft_tb(); AxiStreamIf #(CHDR_W) s_chdr (rfnoc_chdr_clk, 1'b0); // Bus functional model for a software block controller - RfnocBlockCtrlBfm #(.CHDR_W(CHDR_W)) blk_ctrl = + RfnocBlockCtrlBfm #(CHDR_W, SAMP_W) blk_ctrl = new(backend, m_ctrl, s_ctrl); // Connect block controller to BFMs diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fir_filter/rfnoc_block_fir_filter_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fir_filter/rfnoc_block_fir_filter_tb.sv index fedb4f46b..88995e01c 100644 --- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fir_filter/rfnoc_block_fir_filter_tb.sv +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fir_filter/rfnoc_block_fir_filter_tb.sv @@ -96,7 +96,7 @@ module rfnoc_block_fir_filter_tb #( AxiStreamIf #(CHDR_W) s_chdr [NUM_PORTS] (rfnoc_chdr_clk, 1'b0); // Bus functional model for a software block controller - RfnocBlockCtrlBfm #(.CHDR_W(CHDR_W)) blk_ctrl = new(backend, m_ctrl, s_ctrl); + RfnocBlockCtrlBfm #(CHDR_W, SAMP_W) blk_ctrl = new(backend, m_ctrl, s_ctrl); // Connect block controller to BFMs for (genvar i = 0; i < NUM_PORTS; i++) begin : gen_bfm_connections diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_radio/rfnoc_block_radio_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_radio/rfnoc_block_radio_tb.sv index 553b0e33e..7dfa00fe5 100644 --- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_radio/rfnoc_block_radio_tb.sv +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_radio/rfnoc_block_radio_tb.sv @@ -90,7 +90,7 @@ module rfnoc_block_radio_tb #( typedef ChdrData #(CHDR_W, ITEM_W)::item_t sample_t; // Bus functional model for a software block controller - RfnocBlockCtrlBfm #(.CHDR_W(CHDR_W)) blk_ctrl = new(backend, m_ctrl, s_ctrl); + RfnocBlockCtrlBfm #(CHDR_W, ITEM_W) blk_ctrl = new(backend, m_ctrl, s_ctrl); // Connect block controller to BFMs for (genvar i = 0; i < NUM_PORTS; i++) begin : gen_bfm_connections diff --git a/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv b/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv index 0b372684c..243987d68 100644 --- a/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv +++ b/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv @@ -24,7 +24,17 @@ package PkgChdrIfaceBfm; } packet_info_t; - class ChdrIfaceBfm #(CHDR_W = 64) extends ChdrBfm #(CHDR_W); + class ChdrIfaceBfm #(CHDR_W = 64, ITEM_W = 32) extends ChdrBfm #(CHDR_W); + + // Redefine the ChdrPacket and chdr_word_t data types from ChdrBfm due to a + // bug in Vivado 2019.1. + typedef ChdrPacket #(CHDR_W) ChdrPacket; + typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t; + typedef ChdrData #(CHDR_W, ITEM_W)::item_t item_t; + + localparam int BYTES_PER_CHDR_W = CHDR_W/8; + localparam int BYTES_PER_ITEM_W = ITEM_W/8; + chdr_seq_num_t seq_num; // Sequence number protected int max_payload_length; // Maximum number of payload bytes per packet @@ -55,7 +65,7 @@ package PkgChdrIfaceBfm; // max_length: Maximum payload length in bytes for each packet // function void set_max_payload_length(int max_payload_length); - assert (max_payload_length % (CHDR_W/8) == 0) else begin + assert (max_payload_length % BYTES_PER_CHDR_W == 0) else begin $fatal(1, "ChdrIfaceBfm::set_max_payload_length: max_payload_length must be a multiple of CHDR_W in bytes"); end this.max_payload_length = max_payload_length; @@ -122,9 +132,28 @@ package PkgChdrIfaceBfm; endtask : send - // Send data as one or more CHDR data packets. The input data and metadata - // is automatically broken into max_payload_length'd packets. If multiple - // packets are needed, EOB and EOV are only applied to the last packet. + // Send a CHDR data packet, filling the payload with items. + // + // items: Data items to insert into the CHDR packet. + // metadata: Metadata words to insert into the CHDR packet. Omit this + // argument (or set to an empty array) to not include metadata. + // pkt_info: Data structure containing packet header information. + // + task send_items ( + input item_t items[$], + input chdr_word_t metadata[$] = {}, + input packet_info_t pkt_info = 0 + ); + chdr_word_t data[$]; + data = ChdrData#(CHDR_W, ITEM_W)::item_to_chdr(items); + send(data, items.size()*BYTES_PER_ITEM_W, metadata, pkt_info); + endtask : send_items + + + // Send data as one or more CHDR data packets. The input data and metadata + // is automatically broken into max_payload_length'd packets. The + // timestamp, if present, is set for the first packet and updated for + // subsequent packets. The EOB and EOV are only applied to the last packet. // // data: Data words to insert into the CHDR packet. // data_bytes: The number of data bytes in the CHDR packet. This @@ -153,10 +182,12 @@ package PkgChdrIfaceBfm; chdr_word_t temp_data[$]; chdr_word_t temp_mdata[$]; - num_pkts = $ceil(real'(data.size()*($bits(chdr_word_t)/8)) / max_payload_length); + num_pkts = $ceil(real'(data.size()*BYTES_PER_CHDR_W) / max_payload_length); pkt_type = pkt_info.has_time ? CHDR_DATA_WITH_TS : CHDR_DATA_NO_TS; timestamp = pkt_info.timestamp; + 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 $fatal(1, "ChdrIfaceBfm::send: Too much metadata for this send request"); @@ -170,8 +201,8 @@ package PkgChdrIfaceBfm; // The last packet, which may or may not be full-sized eob = pkt_info.eob; eov = pkt_info.eov; - payload_length = (data_bytes < 0) ? data_bytes : data_bytes % max_payload_length; - first_dword = i*max_payload_length/($bits(chdr_word_t)/8); + 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)); last_mword = metadata.size()-1; @@ -180,10 +211,10 @@ package PkgChdrIfaceBfm; eob = 1'b0; eov = 1'b0; payload_length = max_payload_length; - first_dword = (i+0)*max_payload_length / ($bits(chdr_word_t)/8); - last_dword = (i+1)*max_payload_length / ($bits(chdr_word_t)/8) - 1; - first_mword = (i+0)*(2**$bits(chdr_num_mdata_t) * CHDR_W / $bits(chdr_word_t)); - last_mword = (i+1)*(2**$bits(chdr_num_mdata_t) * CHDR_W / $bits(chdr_word_t)) - 1; + first_dword = (i+0)*max_payload_length / BYTES_PER_CHDR_W; + last_dword = (i+1)*max_payload_length / BYTES_PER_CHDR_W - 1; + first_mword = (i+0)*(2**$bits(chdr_num_mdata_t)-1); + last_mword = (i+1)*(2**$bits(chdr_num_mdata_t)-1) - 1; last_mword = last_mword > metadata.size() ? metadata.size() : last_mword; end @@ -216,11 +247,33 @@ package PkgChdrIfaceBfm; put_chdr(chdr_packet); // Update timestamp for next packet (in case this is not the last) - timestamp += max_payload_length/(CHDR_W/8) * ticks_per_word; + timestamp += max_payload_length/BYTES_PER_CHDR_W * ticks_per_word; end endtask : send_packets + // Send one or more CHDR data packets, filling the payload with items. The + // input data and metadata is automatically broken into + // max_payload_length'd packets. The timestamp, if present, is set for the + // first packet and updated for subsequent packets. The EOB and EOV are + // only applied to the last packet. + // + // items: Data items to insert into the payload of the CHDR packets. + // metadata: Metadata words to insert into the CHDR packet. Omit this + // argument (or set to an empty array) to not include metadata. + // pkt_info: Data structure containing packet header information. + // + task send_packets_items ( + input item_t items[$], + input chdr_word_t metadata[$] = {}, + input packet_info_t pkt_info = 0 + ); + chdr_word_t data[$]; + data = ChdrData#(CHDR_W, ITEM_W)::item_to_chdr(items); + send_packets(data, items.size()*BYTES_PER_ITEM_W, metadata, pkt_info); + endtask : send_packets_items + + // Receive a CHDR data packet and extract its contents. // // data: Data words from the received CHDR packet. @@ -251,6 +304,31 @@ package PkgChdrIfaceBfm; endtask : recv_adv + // Receive a CHDR data packet and extract its contents, putting the payload + // into a queue of items. + // + // items: Items extracted from the payload of the received packet. + // metadata: Metadata words from the received CHDR packet. This will be + // an empty array if there was no metadata. + // pkt_info: Data structure to receive packet header information. + // + task recv_items_adv ( + output item_t items[$], + output chdr_word_t metadata[$], + output packet_info_t pkt_info + ); + chdr_word_t data[$]; + int data_bytes; + + recv_adv(data, data_bytes, metadata, pkt_info); + items = ChdrData#(CHDR_W, ITEM_W)::chdr_to_item(data, data_bytes); + assert (data_bytes % BYTES_PER_ITEM_W == 0) else begin + $error({"ChdrIfaceBfm::recv_items_adv: ", + "Received data was not a multiple of items"}); + end + endtask : recv_items_adv + + // Receive a CHDR data packet and extract the data. Any metadata or // timestamp, if present, are discarded. // @@ -266,6 +344,123 @@ package PkgChdrIfaceBfm; data_bytes = chdr_packet.data_bytes(); endtask : recv + + // Receive a CHDR data packet and extract its payload into a queue of + // items. Any metadata or timestamp, if present, are discarded. + // + // items: Data items extracted from payload of the received CHDR packet. + // + task recv_items( + output item_t items[$] + ); + chdr_word_t data[$]; + int data_bytes; + + recv(data, data_bytes); + items = ChdrData#(CHDR_W, ITEM_W)::chdr_to_item(data, data_bytes); + assert (data_bytes % BYTES_PER_ITEM_W == 0) else begin + $error({"ChdrIfaceBfm::recv_items: ", + "Received data was not a multiple of items"}); + end + endtask : recv_items + + + // Receive one ore more CHDR data packets and extract their contents, + // putting the payload into a queue of items. Any metadata or timestamp, if + // present, are discarded. + // + // items: Items extracted from the payload of the received packets. + // num_items: (Optional) Minimum number of items to receive. This must be + // provided, unless eob or eov are set. Defaults to -1, which + // means that the number of items is not limited. + // eob: (Optional) Receive up until the next End of Burst (EOB). + // Default value is 1, so an entire burst is received. + // eov: (Optional) Receive up until the next End of Vector (EOV). + // + task recv_packets_items( + output item_t items[$], + input int num_items = -1, // Receive a full burst by default + input bit eob = 1, + input bit eov = 0 + ); + chdr_word_t metadata[$]; + packet_info_t pkt_info; + recv_packets_items_adv(items, metadata, pkt_info, num_items, eob, eov); + endtask : recv_packets_items + + + // Receive one or more CHDR data packets and extract their contents, + // putting the payload into a queue of items and the metadata into a queue + // of CHDR words. + // + // items: Items extracted from the payload of the received packets. + // metadata: Metadata words from the received CHDR packets. This will be + // an empty array if there was no metadata. + // pkt_info: Data structure to receive packet information. The + // timestamp, if present, will correspond to the time of the + // first sample, whereas vc/eob/eov will correspond to the + // state of the last packet. + // num_items: (Optional) Minimum number of items to receive. This must be + // provided, unless eob or eov are set. Defaults to -1, which + // means that the number of items is not limited. + // eob: (Optional) Receive up until the next End of Burst (EOB). + // Default value is 1, so an entire burst is received. + // eov: (Optional) Receive up until the next End of Vector (EOV). + // + task recv_packets_items_adv( + output item_t items[$], + output chdr_word_t metadata[$], + output packet_info_t pkt_info, + input int num_items = -1, // Receive a full burst by default + input bit eob = 1, + input bit eov = 0 + ); + chdr_word_t pkt_data[$]; + chdr_word_t pkt_metadata[$]; + int pkt_data_bytes; + int item_count; + packet_info_t time_info; + item_t new_items[$]; + + if (num_items < 0) begin + assert (eob || eov) else begin + $fatal(1, {"ChdrIfaceBfm::recv_packets_items_adv: ", + "eob or eov must be set when num_items is not limited"}); + end + num_items = 32'h7FFF_FFFF; + end + + time_info = 0; + items = {}; + metadata = {}; + while (items.size() < num_items) begin + // Receive the next packet + recv_adv(pkt_data, pkt_data_bytes, pkt_metadata, pkt_info); + + if (items.size() == 0) begin + // First packet, so grab the timestamp if it exists + if (pkt_info.has_time) time_info = pkt_info; + end + + // Enqueue the data + new_items = ChdrData#(CHDR_W, ITEM_W)::chdr_to_item(pkt_data, pkt_data_bytes); + items = {items, new_items}; + assert (pkt_data_bytes % BYTES_PER_ITEM_W == 0) else begin + $error({"ChdrIfaceBfm::recv_packets_items_adv: ", + "Received data was not a multiple of items"}); + end + + // Enqueue the metadata + metadata = {metadata, pkt_metadata}; + + if ((eob && pkt_info.eob) || (eov && pkt_info.eov)) break; + end + + // Restore timestamp from the first packet + pkt_info.has_time = time_info.has_time; + pkt_info.timestamp = time_info.timestamp; + endtask : recv_packets_items_adv + endclass : ChdrIfaceBfm diff --git a/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv b/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv index ac2bf00ec..e41bf9445 100644 --- a/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv +++ b/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv @@ -93,17 +93,18 @@ package PkgRfnocBlockCtrlBfm; // //--------------------------------------------------------------------------- - class RfnocBlockCtrlBfm #(CHDR_W = 64); + class RfnocBlockCtrlBfm #(CHDR_W = 64, ITEM_W = 32); - local virtual RfnocBackendIf.master backend; - local CtrlIfaceBfm ctrl; - local ChdrIfaceBfm #(CHDR_W) m_data[$]; - local ChdrIfaceBfm #(CHDR_W) s_data[$]; - local bit running; + local virtual RfnocBackendIf.master backend; + local CtrlIfaceBfm ctrl; + local ChdrIfaceBfm #(CHDR_W, ITEM_W) m_data[$]; + local ChdrIfaceBfm #(CHDR_W, ITEM_W) s_data[$]; + local bit running; localparam CMD_PROP_CYC = 5; - typedef ChdrData #(CHDR_W)::chdr_word_t chdr_word_t; + typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t; + typedef ChdrData #(CHDR_W, ITEM_W)::item_t item_t; // Class constructor to create a new BFM instance. // @@ -128,17 +129,18 @@ package PkgRfnocBlockCtrlBfm; // Add a master data port. This should connect to a DUT slave input. // // m_chdr: Virtual master interface to connect new port to. - // max_payload_length: Maximum payload length to create when building - // packets from data. + // max_payload_length: Maximum payload length (in bytes) to create when + // building packets from data. // ticks_per_word: Number of timebase clock ticks to increment per // CHDR word. // function int add_master_data_port( virtual AxiStreamIf #(CHDR_W).master m_chdr, int max_payload_length = 2**$bits(chdr_length_t), - int ticks_per_word = CHDR_W/32 + int ticks_per_word = CHDR_W/ITEM_W ); - ChdrIfaceBfm #(CHDR_W) bfm = new(m_chdr, null, max_payload_length, ticks_per_word); + ChdrIfaceBfm #(CHDR_W, ITEM_W) bfm = + new(m_chdr, null, max_payload_length, ticks_per_word); m_data.push_back(bfm); return m_data.size() - 1; endfunction : add_master_data_port @@ -150,7 +152,7 @@ package PkgRfnocBlockCtrlBfm; function int add_slave_data_port( virtual AxiStreamIf #(CHDR_W).slave s_chdr ); - ChdrIfaceBfm #(CHDR_W) bfm = new(null, s_chdr); + ChdrIfaceBfm #(CHDR_W, ITEM_W) bfm = new(null, s_chdr); s_data.push_back(bfm); return s_data.size() - 1; endfunction : add_slave_data_port @@ -161,8 +163,8 @@ package PkgRfnocBlockCtrlBfm; // // port_num: The port number to which m_chdr should be connected // m_chdr: Master CHDR interface to connect to the port - // max_payload_length: Maximum payload length to create when building - // packets from data. + // max_payload_length: Maximum payload length (in bytes) to create when + // building packets from data. // ticks_per_word: Number of timebase clock ticks to increment per // CHDR word. // @@ -170,9 +172,10 @@ package PkgRfnocBlockCtrlBfm; int port_num, virtual AxiStreamIf #(CHDR_W).master m_chdr, int max_payload_length = 2**$bits(chdr_length_t), - int ticks_per_word = CHDR_W/32 + int ticks_per_word = CHDR_W/ITEM_W ); - ChdrIfaceBfm #(CHDR_W) bfm = new(m_chdr, null, max_payload_length, ticks_per_word); + ChdrIfaceBfm #(CHDR_W, ITEM_W) bfm = + new(m_chdr, null, max_payload_length, ticks_per_word); wait (m_data.size() == port_num); m_data.push_back(bfm); endtask : connect_master_data_port @@ -188,7 +191,7 @@ package PkgRfnocBlockCtrlBfm; int port_num, virtual AxiStreamIf #(CHDR_W).slave s_chdr ); - ChdrIfaceBfm #(CHDR_W) bfm = new(null, s_chdr); + ChdrIfaceBfm #(CHDR_W, ITEM_W) bfm = new(null, s_chdr); wait (s_data.size() == port_num); s_data.push_back(bfm); endtask : connect_slave_data_port @@ -214,7 +217,7 @@ package PkgRfnocBlockCtrlBfm; endfunction : get_ctrl_bfm // Return a handle to the indicated master port BFM - function ChdrIfaceBfm #(CHDR_W) get_master_data_bfm(int port); + function ChdrIfaceBfm #(CHDR_W, ITEM_W) get_master_data_bfm(int port); assert (port >= 0 && port < m_data.size()) else begin $fatal(1, "Invalid master port number"); end @@ -222,7 +225,7 @@ package PkgRfnocBlockCtrlBfm; endfunction : get_master_data_bfm // Return a handle to the indicated slave port BFM - function ChdrIfaceBfm #(CHDR_W) get_slave_data_bfm(int port); + function ChdrIfaceBfm #(CHDR_W, ITEM_W) get_slave_data_bfm(int port); assert (port >= 0 && port < m_data.size()) else begin $fatal(1, "Invalid slave port number"); end @@ -429,10 +432,39 @@ package PkgRfnocBlockCtrlBfm; endtask : send - // Send data as one or more CHDR data packets out the CHDR data interface. + // Send a CHDR data packet, filling the payload with items. + // + // port: Port to send the CHDR packet on. + // items: Data items to insert into the CHDR packet's payload. + // metadata: Metadata words to insert into the CHDR packet. Omit this + // argument (or set to an empty array) to not include + // metadata. + // pkt_info: Data structure containing packet header information. + // + task send_items( + input int port, + input item_t items[$], + input chdr_word_t metadata[$] = {}, + input packet_info_t pkt_info = 0 + ); + assert (running) else begin + $fatal(1, "Cannot call send_items until RfnocBlockCtrlBfm is running"); + end + assert (port >= 0 && port < m_data.size()) else begin + $fatal(1, "Invalid master port number"); + end + + m_data[port].send_items(items, metadata, pkt_info); + endtask : send_items + + + // Send data as one or more CHDR data packets. The input data and metadata + // is automatically broken into max_payload_length'd packets. The + // timestamp, if present, is set for the first packet and updated for + // subsequent packets. The EOB and EOV are only applied to the last packet. // // port: Port to send the CHDR packet(s) on. - // data: Data words to insert into the CHDR packet. + // data: Data words to insert into the CHDR packets. // data_bytes: Size of data in bytes. If omitted or -1, data_bytes will // be calculated based on the number of words in data. // metadata: Metadata words to insert into the CHDR packet(s). Omit @@ -458,6 +490,36 @@ package PkgRfnocBlockCtrlBfm; endtask : send_packets + // Send one or more CHDR data packets, filling the payload with items. The + // input data and metadata is automatically broken into + // max_payload_length'd packets. The timestamp, if present, is set for the + // first packet and updated for subsequent packets. The EOB and EOV are + // only applied to the last packet. + // + // port: Port to send the CHDR packet(s) on. + // items: Data items to insert into the payload of the CHDR packets. + // metadata: Metadata words to insert into the CHDR packet(s). Omit + // this argument (or set to an empty array) to not include + // metadata. + // pkt_info: Data structure containing packet header information. + // + task send_packets_items( + input int port, + input item_t items[$], + input chdr_word_t metadata[$] = {}, + input packet_info_t pkt_info = 0 + ); + assert (running) else begin + $fatal(1, "Cannot call send_packets_items until RfnocBlockCtrlBfm is running"); + end + assert (port >= 0 && port < m_data.size()) else begin + $fatal(1, "Invalid master port number"); + end + + m_data[port].send_packets_items(items, metadata, pkt_info); + endtask : send_packets_items + + // Receive a CHDR data packet on the CHDR data interface and extract its // contents. // @@ -488,6 +550,32 @@ package PkgRfnocBlockCtrlBfm; endtask : recv_adv + // Receive a CHDR data packet on the CHDR data interface and extract its + // contents, putting the payload into a queue of items. + // + // port: Port to receive the CHDR packet from. + // items: Items extracted from the payload of the received packet. + // metadata: Metadata words from the received CHDR packet. This + // will be an empty array if there was no metadata. + // pkt_info: Data structure to receive packet header information. + // + task recv_items_adv( + input int port, + output item_t items[$], + output chdr_word_t metadata[$], + output packet_info_t pkt_info + ); + assert (running) else begin + $fatal(1, "Cannot call recv_items_adv until RfnocBlockCtrlBfm is running"); + end + assert (port >= 0 && port < s_data.size()) else begin + $fatal(1, "Invalid slave port number"); + end + + s_data[port].recv_items_adv(items, metadata, pkt_info); + endtask : recv_items_adv + + // Receive a CHDR data packet on the CHDR data interface and extract the // data. Any metadata or timestamp, if present, are discarded. // @@ -513,6 +601,103 @@ package PkgRfnocBlockCtrlBfm; endtask : recv + // Receive a CHDR data packet on the CHDR data interface and extract its + // payload into a queue of items. Any metadata or timestamp, if present, + // are discarded. + // + // port: Port number for the block to receive from. + // items: Data items extracted from payload of the received packet. + // data_bytes: The number of data bytes in the CHDR packet. This + // is useful if the data is not a multiple of the + // chdr_word_t size. + // + task recv_items( + input int port, + output item_t items[$] + ); + assert (running) else begin + $fatal(1, "Cannot call recv_items until RfnocBlockCtrlBfm is running"); + end + assert (port >= 0 && port < s_data.size()) else begin + $fatal(1, "Invalid slave port number"); + end + + s_data[port].recv_items(items); + endtask : recv_items + + + // Receive one ore more CHDR data packets and extract their contents, + // putting the payload into a queue of items. Any metadata or timestamp, if + // present, are discarded. + // + // port: Port number for the block to receive from. + // items: Items extracted from the payload of the received packets. + // num_items: (Optional) Minimum number of items to receive. This must be + // provided, unless eob or eov are set. Defaults to -1, which + // means that the number of items is not limited. + // eob: (Optional) Receive up until the next End of Burst (EOB). + // Default value is 1, so an entire burst is received. + // eov: (Optional) Receive up until the next End of Vector (EOV). + // + task recv_packets_items( + input int port, + output item_t items[$], + input int num_items = -1, // Receive a full burst by default + input bit eob = 1, + input bit eov = 0 + ); + assert (running) else begin + $fatal(1, "Cannot call recv_items_adv until RfnocBlockCtrlBfm is running"); + end + assert (port >= 0 && port < s_data.size()) else begin + $fatal(1, "Invalid slave port number"); + end + + s_data[port].recv_packets_items( + items, num_items, eob, eov); + endtask : recv_packets_items + + + // Receive one or more CHDR data packets and extract their contents, + // putting the payload into a queue of items and the metadata into a queue + // of CHDR words. + // + // port: Port number for the block to receive from. + // items: Items extracted from the payload of the received packets. + // metadata: Metadata words from the received CHDR packets. This will be + // an empty array if there was no metadata. + // pkt_info: Data structure to receive packet information. The + // timestamp, if present, will correspond to the time of the + // first sample, whereas vc/eob/eov will correspond to the + // state of the last packet. + // num_items: (Optional) Minimum number of items to receive. This must be + // provided, unless eob or eov are set. Defaults to -1, which + // means that the number of items is not limited. + // eob: (Optional) Receive up until the next End of Burst (EOB). + // Default value is 1, so an entire burst is received. + // eov: (Optional) Receive up until the next End of Vector (EOV). + // + task recv_packets_items_adv( + input int port, + output item_t items[$], + output chdr_word_t metadata[$], + output packet_info_t pkt_info, + input int num_items = -1, // Receive a full burst by default + input bit eob = 1, + input bit eov = 0 + ); + assert (running) else begin + $fatal(1, "Cannot call recv_items_adv until RfnocBlockCtrlBfm is running"); + end + assert (port >= 0 && port < s_data.size()) else begin + $fatal(1, "Invalid slave port number"); + end + + s_data[port].recv_packets_items_adv( + items, metadata, pkt_info, num_items, eob, eov); + endtask : recv_packets_items_adv + + // Transmit a raw CHDR packet. // // port: Port number on which to transmit the packet |