aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/sim
diff options
context:
space:
mode:
authorWade Fife <wade.fife@ettus.com>2020-02-19 08:13:36 -0600
committerWade Fife <wade.fife@ettus.com>2020-03-09 13:43:05 -0500
commit369594ef16d7b2d519940269d2af035cfe648f50 (patch)
tree491e889c4234475eb99cfceac3411af3441b7e3a /fpga/usrp3/sim
parentb92597e1c9b6f09d5e62e55a60e33c04d437a50a (diff)
downloaduhd-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.srcs2
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv272
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv1
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgCtrlIfaceBfm.sv125
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv418
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