diff options
author | Wade Fife <wade.fife@ettus.com> | 2020-02-19 08:13:36 -0600 |
---|---|---|
committer | Wade Fife <wade.fife@ettus.com> | 2020-03-09 13:43:05 -0500 |
commit | 369594ef16d7b2d519940269d2af035cfe648f50 (patch) | |
tree | 491e889c4234475eb99cfceac3411af3441b7e3a /fpga/usrp3/sim | |
parent | b92597e1c9b6f09d5e62e55a60e33c04d437a50a (diff) | |
download | uhd-369594ef16d7b2d519940269d2af035cfe648f50.tar.gz uhd-369594ef16d7b2d519940269d2af035cfe648f50.tar.bz2 uhd-369594ef16d7b2d519940269d2af035cfe648f50.zip |
sim: Split PkgRfnocBlockCtrlBfm into separate packages
Diffstat (limited to 'fpga/usrp3/sim')
-rw-r--r-- | fpga/usrp3/sim/rfnoc/Makefile.srcs | 2 | ||||
-rw-r--r-- | fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv | 272 | ||||
-rw-r--r-- | fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv | 1 | ||||
-rw-r--r-- | fpga/usrp3/sim/rfnoc/PkgCtrlIfaceBfm.sv | 125 | ||||
-rw-r--r-- | fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv | 418 |
5 files changed, 418 insertions, 400 deletions
diff --git a/fpga/usrp3/sim/rfnoc/Makefile.srcs b/fpga/usrp3/sim/rfnoc/Makefile.srcs index 329ffbd27..38bb86655 100644 --- a/fpga/usrp3/sim/rfnoc/Makefile.srcs +++ b/fpga/usrp3/sim/rfnoc/Makefile.srcs @@ -16,6 +16,8 @@ PkgChdrUtils.sv \ PkgChdrBfm.sv \ PkgAxisCtrlBfm.sv \ PkgRfnocItemUtils.sv \ +PkgCtrlIfaceBfm.sv \ +PkgChdrIfaceBfm.sv \ PkgRfnocBlockCtrlBfm.sv \ )) diff --git a/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv b/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv new file mode 100644 index 000000000..513910ee7 --- /dev/null +++ b/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv @@ -0,0 +1,272 @@ +// +// Copyright 2020 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: PkgChdrIfaceBfm +// +// Description: This package includes a high-level bus functional model (BFM) +// for the AXIS-CHDR interface of a Transport Adapter or Stream Endpoint. +// + +package PkgChdrIfaceBfm; + + import PkgChdrUtils::*; + import PkgChdrBfm::*; + + + typedef struct packed { + chdr_vc_t vc; + logic eob; + logic eov; + logic has_time; + chdr_word_t timestamp; + } packet_info_t; + + + class ChdrIfaceBfm #(CHDR_W = 64) extends ChdrBfm #(CHDR_W); + chdr_seq_num_t seq_num; // Sequence number + + protected int max_payload_length; // Maximum number of payload bytes per packet + protected int ticks_per_word; // Timestamp increment per CHDR_W sized word + + + // Class constructor to create a new BFM instance. + // + // m_chdr: Interface for the master connection (BFM's CHDR output) + // s_chdr: Interface for the slave connection (BFM's CHDR input) + // + function new( + 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 + ); + super.new(m_chdr, s_chdr); + this.seq_num = 0; + set_max_payload_length(max_payload_length); + set_ticks_per_word(ticks_per_word); + endfunction : new + + + // Set the maximum payload size for packets. This value is used to split + // large send requests across multiple packets. + // + // 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 + $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; + endfunction + + + // Return the maximum payload size for packets. This value is used to split + // large send requests across multiple packets. + function int get_max_payload_length(); + return max_payload_length; + endfunction + + + // Set the timestamp ticks per CHDR_W sized word. + // + // ticks_per_word: Amount to increment the timestamp per CHDR_W sized word + // + function void set_ticks_per_word(int ticks_per_word); + this.ticks_per_word = ticks_per_word; + endfunction + + + // Return the timestamp ticks per CHDR_W sized word. + function int get_ticks_per_word(); + return ticks_per_word; + endfunction + + + // Send a CHDR data packet. + // + // data: Data words to insert into the CHDR 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. + // 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 ( + input chdr_word_t data[$], + input int data_bytes = -1, + input chdr_word_t metadata[$] = {}, + input packet_info_t pkt_info = 0 + ); + ChdrPacket chdr_packet; + chdr_header_t chdr_header; + + // Build packet + chdr_packet = new(); + chdr_header = '{ + vc : pkt_info.vc, + eob : pkt_info.eob, + eov : pkt_info.eov, + seq_num : seq_num++, + pkt_type : pkt_info.has_time ? CHDR_DATA_WITH_TS : CHDR_DATA_NO_TS, + dst_epid : dst_epid, + default : 0 + }; + chdr_packet.write_raw(chdr_header, data, metadata, pkt_info.timestamp, data_bytes); + + // Send the packet + put_chdr(chdr_packet); + 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. + // + // data: Data words to insert into the CHDR 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. + // 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 ( + input chdr_word_t data[$], + input int data_bytes = -1, + input chdr_word_t metadata[$] = {}, + input packet_info_t pkt_info = 0 + ); + ChdrPacket chdr_packet; + chdr_header_t chdr_header; + chdr_pkt_type_t pkt_type; + chdr_word_t timestamp; + int num_pkts; + int payload_length; + int first_dword, last_dword; + int first_mword, last_mword; + bit eob, eov; + chdr_word_t temp_data[$]; + chdr_word_t temp_mdata[$]; + + num_pkts = $ceil(real'(data.size()*($bits(chdr_word_t)/8)) / max_payload_length); + pkt_type = pkt_info.has_time ? CHDR_DATA_WITH_TS : CHDR_DATA_NO_TS; + timestamp = pkt_info.timestamp; + + // 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"); + + // Send the data, one packet at a time. + for (int i = 0; i < num_pkts; i++) begin + chdr_packet = new(); + + // Figure out which data chunk to send next + if (i == num_pkts-1) begin + // 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); + 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; + end else begin + // A full-sized packet, not the last + 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; + last_mword = last_mword > metadata.size() ? metadata.size() : last_mword; + end + + // Build the packet + chdr_header = '{ + vc : pkt_info.vc, + eob : eob, + eov : eov, + seq_num : seq_num++, + pkt_type : pkt_type, + dst_epid : dst_epid, + default : 0 + }; + + // Copy region of data and metadata to be sent in next packet + temp_data = data[first_dword : last_dword]; + if (first_mword < metadata.size()) temp_mdata = metadata[first_mword : last_mword]; + else temp_mdata = {}; + + // Build the packet + chdr_packet.write_raw( + chdr_header, + temp_data, + temp_mdata, + timestamp, + payload_length + ); + + // Send the packet + 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; + end + endtask : send_packets + + + // Receive a CHDR data packet and extract its contents. + // + // data: Data words from the received CHDR 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. + // 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_adv ( + output chdr_word_t data[$], + output int data_bytes, + output chdr_word_t metadata[$], + output packet_info_t pkt_info + ); + ChdrPacket chdr_packet; + get_chdr(chdr_packet); + + data = chdr_packet.data; + data_bytes = chdr_packet.data_bytes(); + metadata = chdr_packet.metadata; + pkt_info.timestamp = chdr_packet.timestamp; + pkt_info.vc = chdr_packet.header.vc; + pkt_info.eob = chdr_packet.header.eob; + pkt_info.eov = chdr_packet.header.eov; + pkt_info.has_time = chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS ? 1 : 0; + endtask : recv_adv + + + // Receive a CHDR data packet and extract the data. Any metadata or + // timestamp, if present, are discarded. + // + // data: Data words from the received CHDR 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(output chdr_word_t data[$], output int data_bytes); + ChdrPacket chdr_packet; + get_chdr(chdr_packet); + data = chdr_packet.data; + data_bytes = chdr_packet.data_bytes(); + endtask : recv + + endclass : ChdrIfaceBfm + + +endpackage : PkgChdrIfaceBfm diff --git a/fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv b/fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv index 95b9d5473..5f7abb46f 100644 --- a/fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv +++ b/fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv @@ -150,7 +150,6 @@ package PkgChdrUtils; chdr_epid_t dst_epid; } chdr_header_t; - // AXIS-Ctrl packet header typedef struct packed { // Word 1 diff --git a/fpga/usrp3/sim/rfnoc/PkgCtrlIfaceBfm.sv b/fpga/usrp3/sim/rfnoc/PkgCtrlIfaceBfm.sv new file mode 100644 index 000000000..0773eeea0 --- /dev/null +++ b/fpga/usrp3/sim/rfnoc/PkgCtrlIfaceBfm.sv @@ -0,0 +1,125 @@ +// +// Copyright 2020 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: PkgCtrlIfaceBfm +// +// Description: This package includes high-level bus functional models (BFM) +// for the AXIS-Ctrl interface of a Stream Endpoint. +// + + +package PkgCtrlIfaceBfm; + + import PkgChdrUtils::*; + import PkgAxisCtrlBfm::*; + + + class CtrlIfaceBfm extends AxisCtrlBfm; + ctrl_port_t dst_port; + ctrl_port_t src_port; + ctrl_seq_num_t seq_num; + + // Class constructor to create a new BFM instance. + // + // m_chdr: Interface for the master connection (BFM's AXIS output) + // s_chdr: Interface for the slave connection (BFM's AXIS input) + // src_port: Source port to use in generated control packets + // + function new( + virtual AxiStreamIf #(32).master m_chdr, + virtual AxiStreamIf #(32).slave s_chdr, + ctrl_port_t dst_port, + ctrl_port_t src_port + ); + super.new(m_chdr, s_chdr); + this.dst_port = dst_port; + this.src_port = src_port; + this.seq_num = '0; + endfunction : new + + + // Send an AXIS-Ctrl read request packet and get the response. + // + // addr: Address for the read request + // word: Data word that was returned in response to the read + // + task reg_read ( + input ctrl_address_t addr, + output ctrl_word_t word + ); + AxisCtrlPacket ctrl_packet; + + // Create the AXIS-Ctrl packet + ctrl_packet = new(); + ctrl_packet.header = '{ + seq_num : seq_num++, + num_data : 1, + src_port : src_port, + dst_port : dst_port, + default : 0 + }; + ctrl_packet.op_word = '{ + op_code : CTRL_OP_READ, + byte_enable : ~0, + address : addr, + default : 0 + }; + ctrl_packet.data = { 0 }; + + // Send the control packet and get the response + put_ctrl(ctrl_packet); + get_ctrl(ctrl_packet); + word = ctrl_packet.data[0]; + + assert(ctrl_packet.header.is_ack == 1 && + ctrl_packet.op_word.status == CTRL_STS_OKAY) else begin + $fatal(1, "CtrlIfaceBfm::reg_read: Did not receive CTRL_STS_OKAY status"); + end + endtask : reg_read + + + // Send an AXIS-Ctrl write request packet and get the response. + // + // addr: Address for the write request + // word: Data word to write + // + task reg_write ( + ctrl_address_t addr, + ctrl_word_t word + ); + AxisCtrlPacket ctrl_packet; + + // Create the AXIS-Ctrl packet + ctrl_packet = new(); + ctrl_packet.header = '{ + seq_num : seq_num++, + num_data : 1, + src_port : src_port, + dst_port : dst_port, + default : 0 + }; + ctrl_packet.op_word = '{ + op_code : CTRL_OP_WRITE, + byte_enable : ~0, + address : addr, + default : 0 + }; + + // Send the packet and get the response + ctrl_packet.data = { word }; + put_ctrl(ctrl_packet); + get_ctrl(ctrl_packet); + word = ctrl_packet.data[0]; + + assert(ctrl_packet.header.is_ack == 1 && + ctrl_packet.op_word.status == CTRL_STS_OKAY) else begin + $fatal(1, "CtrlIfaceBfm::reg_write: Did not receive CTRL_STS_OKAY status"); + end + endtask : reg_write + + endclass : CtrlIfaceBfm + + +endpackage : PkgCtrlIfaceBfm diff --git a/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv b/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv index 8712884c0..722299bb6 100644 --- a/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv +++ b/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv @@ -5,16 +5,13 @@ // // Module: PkgRfnocBlockCtrlBfm // -// Description: This package includes high-level bus functional models (BFMs) -// for communicating with RFNoC. This includes the following: +// Description: This package includes a high-level bus functional model (BFM) +// for a block controller. This models a software block controller and allows +// communication with a single RFNoC block. It includes the following: // -// - ChdrDataStreamBfm: Model for the AXIS CHDR interface of a Transport -// Adapter or Stream Endpoint. -// -// - RegisterIfaceBfm: Model for the AXIS CTRL interface of a Stream Endpoint. -// -// - RfnocBlockCtrlBfm: Model for a software block controller, which includes -// both a ChdrDataStreamBfm and a RegisterIfaceBfm. +// - A CtrlIfaceBfm for an AXIS-Ctrl port connection of a block +// - One or more ChdrIfaceBfm for the AXIS-CHDR port connections +// - A connection for the backend interface of a block // @@ -82,387 +79,10 @@ package PkgRfnocBlockCtrlBfm; import PkgChdrUtils::*; import PkgChdrBfm::*; - import PkgAxisCtrlBfm::*; - import PkgRfnocItemUtils::*; - - - typedef struct packed { - chdr_vc_t vc; - logic eob; - logic eov; - logic has_time; - chdr_word_t timestamp; - } packet_info_t; - - - //--------------------------------------------------------------------------- - // CHDR Stream BFM - //--------------------------------------------------------------------------- - // - // This class models an AXIS CHDR interface, such as that on a Transport - // Adapter or in a Stream Endpoint. - // - //--------------------------------------------------------------------------- - - class ChdrDataStreamBfm #(CHDR_W = 64) extends ChdrBfm #(CHDR_W); - chdr_seq_num_t seq_num; // Sequence number - - protected int max_payload_length; // Maximum number of payload bytes per packet - protected int ticks_per_word; // Timestamp increment per CHDR_W sized word - - - // Class constructor to create a new BFM instance. - // - // m_chdr: Interface for the master connection (BFM's CHDR output) - // s_chdr: Interface for the slave connection (BFM's CHDR input) - // - function new( - 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 - ); - super.new(m_chdr, s_chdr); - this.seq_num = 0; - set_max_payload_length(max_payload_length); - set_ticks_per_word(ticks_per_word); - endfunction : new - - - // Set the maximum payload size for packets. This value is used to split - // large send requests across multiple packets. - // - // 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 - $fatal(1, "ChdrDataStreamBfm::set_max_payload_length: max_payload_length must be a multiple of CHDR_W in bytes"); - end - this.max_payload_length = max_payload_length; - endfunction - - - // Return the maximum payload size for packets. This value is used to split - // large send requests across multiple packets. - function int get_max_payload_length(); - return max_payload_length; - endfunction - - - // Set the timestamp ticks per CHDR_W sized word. - // - // ticks_per_word: Amount to increment the timestamp per CHDR_W sized word - // - function void set_ticks_per_word(int ticks_per_word); - this.ticks_per_word = ticks_per_word; - endfunction - - - // Return the timestamp ticks per CHDR_W sized word. - function int get_ticks_per_word(); - return ticks_per_word; - endfunction - - - // Send a CHDR data packet. - // - // data: Data words to insert into the CHDR 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. - // 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 ( - input chdr_word_t data[$], - input int data_bytes = -1, - input chdr_word_t metadata[$] = {}, - input packet_info_t pkt_info = 0 - ); - ChdrPacket chdr_packet; - chdr_header_t chdr_header; - - // Build packet - chdr_packet = new(); - chdr_header = '{ - vc : pkt_info.vc, - eob : pkt_info.eob, - eov : pkt_info.eov, - seq_num : seq_num++, - pkt_type : pkt_info.has_time ? CHDR_DATA_WITH_TS : CHDR_DATA_NO_TS, - dst_epid : dst_epid, - default : 0 - }; - chdr_packet.write_raw(chdr_header, data, metadata, pkt_info.timestamp, data_bytes); - - // Send the packet - put_chdr(chdr_packet); - 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. - // - // data: Data words to insert into the CHDR 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. - // 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 ( - input chdr_word_t data[$], - input int data_bytes = -1, - input chdr_word_t metadata[$] = {}, - input packet_info_t pkt_info = 0 - ); - ChdrPacket chdr_packet; - chdr_header_t chdr_header; - chdr_pkt_type_t pkt_type; - chdr_word_t timestamp; - int num_pkts; - int payload_length; - int first_dword, last_dword; - int first_mword, last_mword; - bit eob, eov; - chdr_word_t temp_data[$]; - chdr_word_t temp_mdata[$]; - - num_pkts = $ceil(real'(data.size()*($bits(chdr_word_t)/8)) / max_payload_length); - pkt_type = pkt_info.has_time ? CHDR_DATA_WITH_TS : CHDR_DATA_NO_TS; - timestamp = pkt_info.timestamp; - - // 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, "ChdrDataStreamBfm::send: Too much metadata for this send request"); - - // Send the data, one packet at a time. - for (int i = 0; i < num_pkts; i++) begin - chdr_packet = new(); - - // Figure out which data chunk to send next - if (i == num_pkts-1) begin - // 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); - 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; - end else begin - // A full-sized packet, not the last - 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; - last_mword = last_mword > metadata.size() ? metadata.size() : last_mword; - end - - // Build the packet - chdr_header = '{ - vc : pkt_info.vc, - eob : eob, - eov : eov, - seq_num : seq_num++, - pkt_type : pkt_type, - dst_epid : dst_epid, - default : 0 - }; - - // Copy region of data and metadata to be sent in next packet - temp_data = data[first_dword : last_dword]; - if (first_mword < metadata.size()) temp_mdata = metadata[first_mword : last_mword]; - else temp_mdata = {}; - - // Build the packet - chdr_packet.write_raw( - chdr_header, - temp_data, - temp_mdata, - timestamp, - payload_length - ); - - // Send the packet - 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; - end - endtask : send_packets - - - // Receive a CHDR data packet and extract its contents. - // - // data: Data words from the received CHDR 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. - // 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_adv ( - output chdr_word_t data[$], - output int data_bytes, - output chdr_word_t metadata[$], - output packet_info_t pkt_info - ); - ChdrPacket chdr_packet; - get_chdr(chdr_packet); - - data = chdr_packet.data; - data_bytes = chdr_packet.data_bytes(); - metadata = chdr_packet.metadata; - pkt_info.timestamp = chdr_packet.timestamp; - pkt_info.vc = chdr_packet.header.vc; - pkt_info.eob = chdr_packet.header.eob; - pkt_info.eov = chdr_packet.header.eov; - pkt_info.has_time = chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS ? 1 : 0; - endtask : recv_adv - - - // Receive a CHDR data packet and extract the data. Any metadata or - // timestamp, if present, are discarded. - // - // data: Data words from the received CHDR 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(output chdr_word_t data[$], output int data_bytes); - ChdrPacket chdr_packet; - get_chdr(chdr_packet); - data = chdr_packet.data; - data_bytes = chdr_packet.data_bytes(); - endtask : recv - - endclass : ChdrDataStreamBfm - - - - //--------------------------------------------------------------------------- - // CTRL Stream BFM - //--------------------------------------------------------------------------- - // - // This class models an AXIS CTRL interface, such as that in a Stream - // Endpoint. - // - //--------------------------------------------------------------------------- - - class RegisterIfaceBfm extends AxisCtrlBfm; - ctrl_port_t dst_port; - ctrl_port_t src_port; - ctrl_seq_num_t seq_num; - - // Class constructor to create a new BFM instance. - // - // m_chdr: Interface for the master connection (BFM's AXIS output) - // s_chdr: Interface for the slave connection (BFM's AXIS input) - // src_port: Source port to use in generated control packets - // - function new( - virtual AxiStreamIf #(32).master m_chdr, - virtual AxiStreamIf #(32).slave s_chdr, - ctrl_port_t dst_port, - ctrl_port_t src_port - ); - super.new(m_chdr, s_chdr); - this.dst_port = dst_port; - this.src_port = src_port; - this.seq_num = '0; - endfunction : new - - - // Send an AXIS-Ctrl read request packet and get the response. - // - // addr: Address for the read request - // word: Data word that was returned in response to the read - // - task reg_read ( - input ctrl_address_t addr, - output ctrl_word_t word - ); - AxisCtrlPacket ctrl_packet; - - // Create the AXIS-Ctrl packet - ctrl_packet = new(); - ctrl_packet.header = '{ - seq_num : seq_num++, - num_data : 1, - src_port : src_port, - dst_port : dst_port, - default : 0 - }; - ctrl_packet.op_word = '{ - op_code : CTRL_OP_READ, - byte_enable : ~0, - address : addr, - default : 0 - }; - ctrl_packet.data = { 0 }; - - // Send the control packet and get the response - put_ctrl(ctrl_packet); - get_ctrl(ctrl_packet); - word = ctrl_packet.data[0]; - - assert(ctrl_packet.header.is_ack == 1 && - ctrl_packet.op_word.status == CTRL_STS_OKAY) else begin - $fatal(1, "RegisterIfaceBfm::reg_read: Did not receive CTRL_STS_OKAY status"); - end - endtask : reg_read - - - // Send an AXIS-Ctrl write request packet and get the response. - // - // addr: Address for the write request - // word: Data word to write - // - task reg_write ( - ctrl_address_t addr, - ctrl_word_t word - ); - AxisCtrlPacket ctrl_packet; - - // Create the AXIS-Ctrl packet - ctrl_packet = new(); - ctrl_packet.header = '{ - seq_num : seq_num++, - num_data : 1, - src_port : src_port, - dst_port : dst_port, - default : 0 - }; - ctrl_packet.op_word = '{ - op_code : CTRL_OP_WRITE, - byte_enable : ~0, - address : addr, - default : 0 - }; - - // Send the packet and get the response - ctrl_packet.data = { word }; - put_ctrl(ctrl_packet); - get_ctrl(ctrl_packet); - word = ctrl_packet.data[0]; - - assert(ctrl_packet.header.is_ack == 1 && - ctrl_packet.op_word.status == CTRL_STS_OKAY) else begin - $fatal(1, "RegisterIfaceBfm::reg_write: Did not receive CTRL_STS_OKAY status"); - end - endtask : reg_write + import PkgCtrlIfaceBfm::*; + import PkgChdrIfaceBfm::*; - endclass : RegisterIfaceBfm + export PkgChdrIfaceBfm::packet_info_t; //--------------------------------------------------------------------------- @@ -476,9 +96,9 @@ package PkgRfnocBlockCtrlBfm; class RfnocBlockCtrlBfm #(CHDR_W = 64); local virtual RfnocBackendIf.master backend; - local RegisterIfaceBfm ctrl; - local ChdrDataStreamBfm #(CHDR_W) m_data[$]; - local ChdrDataStreamBfm #(CHDR_W) s_data[$]; + local CtrlIfaceBfm ctrl; + local ChdrIfaceBfm #(CHDR_W) m_data[$]; + local ChdrIfaceBfm #(CHDR_W) s_data[$]; local bit running; localparam CMD_PROP_CYC = 5; @@ -516,7 +136,7 @@ package PkgRfnocBlockCtrlBfm; int max_payload_length = 2**$bits(chdr_length_t), int ticks_per_word = CHDR_W/32 ); - ChdrDataStreamBfm #(CHDR_W) bfm = new(m_chdr, null, max_payload_length, ticks_per_word); + ChdrIfaceBfm #(CHDR_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 @@ -528,7 +148,7 @@ package PkgRfnocBlockCtrlBfm; function int add_slave_data_port( virtual AxiStreamIf #(CHDR_W).slave s_chdr ); - ChdrDataStreamBfm #(CHDR_W) bfm = new(null, s_chdr); + ChdrIfaceBfm #(CHDR_W) bfm = new(null, s_chdr); s_data.push_back(bfm); return s_data.size() - 1; endfunction : add_slave_data_port @@ -550,7 +170,7 @@ package PkgRfnocBlockCtrlBfm; int max_payload_length = 2**$bits(chdr_length_t), int ticks_per_word = CHDR_W/32 ); - ChdrDataStreamBfm #(CHDR_W) bfm = new(m_chdr, null, max_payload_length, ticks_per_word); + ChdrIfaceBfm #(CHDR_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 @@ -566,7 +186,7 @@ package PkgRfnocBlockCtrlBfm; int port_num, virtual AxiStreamIf #(CHDR_W).slave s_chdr ); - ChdrDataStreamBfm #(CHDR_W) bfm = new(null, s_chdr); + ChdrIfaceBfm #(CHDR_W) bfm = new(null, s_chdr); wait (s_data.size() == port_num); s_data.push_back(bfm); endtask : connect_slave_data_port @@ -587,12 +207,12 @@ package PkgRfnocBlockCtrlBfm; endtask : run // Return a handle to the control BFM - function RegisterIfaceBfm get_ctrl_bfm(); + function CtrlIfaceBfm get_ctrl_bfm(); return ctrl; endfunction : get_ctrl_bfm // Return a handle to the indicated master port BFM - function ChdrDataStreamBfm #(CHDR_W) get_master_data_bfm(int port); + function ChdrIfaceBfm #(CHDR_W) get_master_data_bfm(int port); assert (port >= 0 && port < m_data.size()) else begin $fatal(1, "Invalid master port number"); end @@ -600,7 +220,7 @@ package PkgRfnocBlockCtrlBfm; endfunction : get_master_data_bfm // Return a handle to the indicated slave port BFM - function ChdrDataStreamBfm #(CHDR_W) get_slave_data_bfm(int port); + function ChdrIfaceBfm #(CHDR_W) get_slave_data_bfm(int port); assert (port >= 0 && port < m_data.size()) else begin $fatal(1, "Invalid slave port number"); end |