aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWade Fife <wade.fife@ettus.com>2020-02-21 08:35:24 -0600
committerWade Fife <wade.fife@ettus.com>2020-03-09 13:43:05 -0500
commitfc895feacb8dde3b02c9a4eccb4b4f4a654f2881 (patch)
tree0325ce379611fae9e9902e0e9a5fd299c1c48243
parent369594ef16d7b2d519940269d2af035cfe648f50 (diff)
downloaduhd-fc895feacb8dde3b02c9a4eccb4b4f4a654f2881.tar.gz
uhd-fc895feacb8dde3b02c9a4eccb4b4f4a654f2881.tar.bz2
uhd-fc895feacb8dde3b02c9a4eccb4b4f4a654f2881.zip
sim: Parameterize chdr_word_t data type
This replaces chdr_word_t, which was a statically defined 64-bit data type, with a paramaterizable data type that matches the defined CHDR_W. Code that formerly referenced the chdr_word_t data type can now define the data type for their desired CHDR_W and ITEM_W as follows: // Define the CHDR word and item/sample data types typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t; typedef ChdrData #(CHDR_W, ITEM_W)::item_t item_t; ITEM_W is optional when defining chdr_word_t if items are not needed. Static methods in the ChdrData class also provide the ability to convert between CHDR words and data items. For example: // Convert CHDR data buffer to a buffer of samples samples = ChdrData#(CHDR_W, ITEM_W)::chdr_to_item(data);
-rw-r--r--fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_axi_ram_fifo/rfnoc_block_axi_ram_fifo_tb.sv2
-rw-r--r--fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_ddc/rfnoc_block_ddc_tb.sv3
-rw-r--r--fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_duc/rfnoc_block_duc_tb.sv4
-rw-r--r--fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft_tb.sv3
-rw-r--r--fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fir_filter/rfnoc_block_fir_filter_tb.sv3
-rw-r--r--fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink_tb.sv9
-rw-r--r--fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_radio/rfnoc_block_radio_tb.sv12
-rw-r--r--fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/chdr_stream_endpoint_tb.sv2
-rw-r--r--fpga/usrp3/sim/rfnoc/Makefile.srcs1
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgAxisCtrlBfm.sv4
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv273
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgChdrData.sv155
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv10
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv63
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv8
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgRfnocItemUtils.sv75
-rw-r--r--host/examples/rfnoc-example/fpga/rfnoc_block_gain/rfnoc_block_gain_tb.sv7
-rw-r--r--host/utils/rfnoc_blocktool/templates/rfnoc_block_template_tb.sv.mako7
18 files changed, 423 insertions, 218 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 8ae72027e..e4753e92f 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
@@ -83,6 +83,8 @@ module rfnoc_block_axi_ram_fifo_tb #(
// Bus Functional Models
//---------------------------------------------------------------------------
+ typedef ChdrData #(CHDR_W)::chdr_word_t chdr_word_t;
+
RfnocBackendIf backend (rfnoc_chdr_clk, rfnoc_ctrl_clk);
AxiStreamIf #(32) m_ctrl (rfnoc_ctrl_clk, 1'b0);
AxiStreamIf #(32) s_ctrl (rfnoc_ctrl_clk, 1'b0);
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 86f64ab4c..e6f2c4d6b 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
@@ -35,6 +35,7 @@ module rfnoc_block_ddc_tb();
// Block configuration
localparam int CHDR_W = 64;
+ localparam int SAMP_W = 32;
localparam int THIS_PORTID = 'h123;
localparam int MTU = 8;
localparam int NUM_PORTS = 1;
@@ -60,6 +61,8 @@ module rfnoc_block_ddc_tb();
// Bus Functional Models
//---------------------------------------------------------------------------
+ typedef ChdrData #(CHDR_W, SAMP_W)::chdr_word_t chdr_word_t;
+
RfnocBackendIf backend (rfnoc_chdr_clk, rfnoc_ctrl_clk);
AxiStreamIf #(32) m_ctrl (rfnoc_ctrl_clk, 1'b0);
AxiStreamIf #(32) s_ctrl (rfnoc_ctrl_clk, 1'b0);
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 de54d5ee0..8151ed761 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
@@ -35,6 +35,7 @@ module rfnoc_block_duc_tb();
// Block configuration
localparam int CHDR_W = 64;
+ localparam int SAMP_W = 32;
localparam int THIS_PORTID = 'h123;
localparam int MTU = 8;
localparam int NUM_PORTS = 1;
@@ -49,6 +50,7 @@ module rfnoc_block_duc_tb();
bit rfnoc_chdr_clk;
bit rfnoc_ctrl_clk;
+ bit ce_clk;
sim_clock_gen #(CHDR_CLK_PER) rfnoc_chdr_clk_gen (.clk(rfnoc_chdr_clk), .rst());
sim_clock_gen #(CHDR_CLK_PER) rfnoc_ctrl_clk_gen (.clk(rfnoc_ctrl_clk), .rst());
@@ -59,6 +61,8 @@ module rfnoc_block_duc_tb();
// Bus Functional Models
//---------------------------------------------------------------------------
+ typedef ChdrData #(CHDR_W, SAMP_W)::chdr_word_t chdr_word_t;
+
RfnocBackendIf backend (rfnoc_chdr_clk, rfnoc_ctrl_clk);
AxiStreamIf #(32) m_ctrl (rfnoc_ctrl_clk, 1'b0);
AxiStreamIf #(32) s_ctrl (rfnoc_ctrl_clk, 1'b0);
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 05b38ddeb..412963dc7 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
@@ -30,6 +30,7 @@ module rfnoc_block_fft_tb();
// Block configuration
localparam int NOC_ID = 32'hFF70_0000;
localparam int CHDR_W = 64;
+ localparam int SAMP_W = 32;
localparam int THIS_PORTID = 'h123;
localparam int MTU = 10;
localparam int NUM_PORTS = 1;
@@ -60,6 +61,8 @@ module rfnoc_block_fft_tb();
// Bus Functional Models
//---------------------------------------------------------------------------
+ typedef ChdrData #(CHDR_W, SAMP_W)::chdr_word_t chdr_word_t;
+
RfnocBackendIf backend (rfnoc_chdr_clk, rfnoc_ctrl_clk);
AxiStreamIf #(32) m_ctrl (rfnoc_ctrl_clk, 1'b0);
AxiStreamIf #(32) s_ctrl (rfnoc_ctrl_clk, 1'b0);
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 2a961b89f..fedb4f46b 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
@@ -36,6 +36,7 @@ module rfnoc_block_fir_filter_tb #(
// DUT parameters to test
localparam int CHDR_W = 64;
+ localparam int SAMP_W = 32;
localparam int THIS_PORTID = 'h123;
localparam int MTU = 8;
//
@@ -86,6 +87,8 @@ module rfnoc_block_fir_filter_tb #(
// Bus Functional Models
//---------------------------------------------------------------------------
+ typedef ChdrData #(CHDR_W, SAMP_W)::chdr_word_t chdr_word_t;
+
RfnocBackendIf backend (rfnoc_chdr_clk, rfnoc_ctrl_clk);
AxiStreamIf #(32) m_ctrl (rfnoc_ctrl_clk, 1'b0);
AxiStreamIf #(32) s_ctrl (rfnoc_ctrl_clk, 1'b0);
diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink_tb.sv
index 699d53b11..192a8143b 100644
--- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink_tb.sv
+++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_null_src_sink/rfnoc_block_null_src_sink_tb.sv
@@ -24,6 +24,7 @@ module rfnoc_block_null_src_sink_tb;
localparam [9:0] THIS_PORTID = 10'h17;
localparam [15:0] THIS_EPID = 16'hDEAD;
localparam int CHDR_W = 64;
+ localparam int ITEM_W = 32;
localparam int SPP = 201;
localparam int LPP = ((SPP+1)/2);
localparam int NUM_PKTS = 50;
@@ -48,6 +49,8 @@ module rfnoc_block_null_src_sink_tb;
AxiStreamIf #(CHDR_W) s0_chdr (rfnoc_chdr_clk); // Optional data iface
AxiStreamIf #(CHDR_W) s1_chdr (rfnoc_chdr_clk); // Optional data iface
+ typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t;
+
// Bus functional model for a software block controller
RfnocBlockCtrlBfm #(.CHDR_W(CHDR_W)) blk_ctrl;
@@ -128,7 +131,7 @@ module rfnoc_block_null_src_sink_tb;
// Read status register and validate it
blk_ctrl.reg_read(dut.REG_CTRL_STATUS, rvalue);
`ASSERT_ERROR(rvalue[31:24] == 2, "Incorrect NIPC Value");
- `ASSERT_ERROR(rvalue[23:16] == 32, "Incorrect ITEM_W Value");
+ `ASSERT_ERROR(rvalue[23:16] == ITEM_W, "Incorrect ITEM_W Value");
test.end_timeout(timeout);
end
test.end_test();
@@ -139,7 +142,7 @@ module rfnoc_block_null_src_sink_tb;
repeat (NUM_PKTS) begin
chdr_word_t rx_data[$];
int rx_bytes;
- automatic ItemDataBuff #(logic[31:0]) tx_dbuff = new, rx_dbuff = new;
+ automatic ItemDataBuff #(logic[ITEM_W-1:0]) tx_dbuff = new, rx_dbuff = new;
for (int i = 0; i < SPP; i++)
tx_dbuff.put($urandom());
test.start_timeout(timeout, 5us, "Waiting for pkt to loop back");
@@ -176,7 +179,7 @@ module rfnoc_block_null_src_sink_tb;
repeat (NUM_PKTS) begin
chdr_word_t rx_data[$];
int rx_bytes;
- automatic ItemDataBuff #(logic[31:0]) tx_dbuff = new;
+ automatic ItemDataBuff #(logic[ITEM_W-1:0]) tx_dbuff = new;
for (int i = 0; i < SPP; i++)
tx_dbuff.put($urandom());
test.start_timeout(timeout, 5us, "Waiting for pkt to loop back");
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 4438cae9e..553b0e33e 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
@@ -27,7 +27,6 @@ module rfnoc_block_radio_tb #(
import PkgRfnocBlockCtrlBfm::*;
import PkgAxisCtrlBfm::*;
import PkgChdrBfm::*;
- import PkgRfnocItemUtils::*;
// Pull in radio register offsets and constants
`include "rfnoc_block_radio_regs.vh"
@@ -87,6 +86,9 @@ module rfnoc_block_radio_tb #(
AxiStreamIf #(CHDR_W) m_chdr [NUM_PORTS] (rfnoc_chdr_clk, 1'b0);
AxiStreamIf #(CHDR_W) s_chdr [NUM_PORTS] (rfnoc_chdr_clk, 1'b0);
+ typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t;
+ 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);
@@ -370,13 +372,13 @@ module rfnoc_block_radio_tb #(
for (int i = 0; i < valid_words; i++) begin
// Check each sample of the next chdr_word_t value
for (int sub_sample = 0; sub_sample < $bits(chdr_word_t)/ITEM_W; sub_sample++) begin
- chdr_word_t word;
- word = data[i][ITEM_W*sub_sample +: ITEM_W]; // Work around Vivado 2018.3 issue
+ sample_t actual;
+ actual = data[i][ITEM_W*sub_sample +: ITEM_W]; // Work around Vivado 2018.3 issue
`ASSERT_ERROR(
- word == sample_val,
+ actual == sample_val,
$sformatf(
"Sample %0d (0x%X) didn't match expected value (0x%X)",
- sample_count, data[i][ITEM_W*sub_sample +: ITEM_W], sample_val
+ sample_count, actual, sample_val
)
);
sample_val++;
diff --git a/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/chdr_stream_endpoint_tb.sv b/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/chdr_stream_endpoint_tb.sv
index 0626ee447..34bf10707 100644
--- a/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/chdr_stream_endpoint_tb.sv
+++ b/fpga/usrp3/lib/rfnoc/sim/chdr_stream_endpoint_tb/chdr_stream_endpoint_tb.sv
@@ -45,6 +45,8 @@ module chdr_stream_endpoint_tb;
localparam [9:0] PORT_A = 10'd1;
localparam [9:0] PORT_B = 10'd2;
+ typedef ChdrData #(CHDR_W)::chdr_word_t chdr_word_t;
+
// ----------------------------------------
// DUT (and Crossbar) Instantiations
// ----------------------------------------
diff --git a/fpga/usrp3/sim/rfnoc/Makefile.srcs b/fpga/usrp3/sim/rfnoc/Makefile.srcs
index 38bb86655..a48d166b6 100644
--- a/fpga/usrp3/sim/rfnoc/Makefile.srcs
+++ b/fpga/usrp3/sim/rfnoc/Makefile.srcs
@@ -12,6 +12,7 @@ PkgTestExec.sv \
test_exec.svh \
sim_clock_gen.sv \
PkgAxiStreamBfm.sv \
+PkgChdrData.sv \
PkgChdrUtils.sv \
PkgChdrBfm.sv \
PkgAxisCtrlBfm.sv \
diff --git a/fpga/usrp3/sim/rfnoc/PkgAxisCtrlBfm.sv b/fpga/usrp3/sim/rfnoc/PkgAxisCtrlBfm.sv
index 8c88792c7..7d7c01eff 100644
--- a/fpga/usrp3/sim/rfnoc/PkgAxisCtrlBfm.sv
+++ b/fpga/usrp3/sim/rfnoc/PkgAxisCtrlBfm.sv
@@ -29,7 +29,7 @@ package PkgAxisCtrlBfm;
//------------
axis_ctrl_header_t header;
- chdr_word_t timestamp;
+ chdr_timestamp_t timestamp;
ctrl_op_word_t op_word;
ctrl_word_t data[$];
@@ -86,7 +86,7 @@ package PkgAxisCtrlBfm;
ref axis_ctrl_header_t header,
ref ctrl_op_word_t op_word,
ref ctrl_word_t data[$],
- input chdr_word_t timestamp = 0
+ input chdr_timestamp_t timestamp = 0
);
this.header = header;
this.data = data;
diff --git a/fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv b/fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv
index fd0bd0048..5863bb598 100644
--- a/fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv
+++ b/fpga/usrp3/sim/rfnoc/PkgChdrBfm.sv
@@ -21,14 +21,17 @@ package PkgChdrBfm;
// CHDR Packet Class
//---------------------------------------------------------------------------
- class ChdrPacket #(int BUS_WIDTH = 64);
+ class ChdrPacket #(int CHDR_W = 64);
- typedef ChdrPacket #(BUS_WIDTH) ChdrPacket;
+ typedef ChdrPacket #(CHDR_W) ChdrPacket;
+ typedef ChdrData #(CHDR_W)::chdr_word_t chdr_word_t;
- chdr_header_t header;
- chdr_word_t timestamp;
- chdr_word_t metadata[$];
- chdr_word_t data[$];
+ const int BYTES_PER_CHDR_W = CHDR_W / 8;
+
+ chdr_header_t header;
+ chdr_timestamp_t timestamp;
+ chdr_word_t metadata[$];
+ chdr_word_t data[$];
extern function ChdrPacket copy();
extern function bit equal(ChdrPacket packet);
@@ -39,12 +42,12 @@ package PkgChdrBfm;
extern function void write_raw (ref chdr_header_t header,
ref chdr_word_t data[$],
input chdr_word_t metadata[$] = {},
- input chdr_word_t timestamp = 0,
+ input chdr_timestamp_t timestamp = 0,
input int data_byte_length = -1);
extern function void read_raw (output chdr_header_t header,
output chdr_word_t data[$],
output chdr_word_t metadata[$],
- output chdr_word_t timestamp,
+ output chdr_timestamp_t timestamp,
output int data_byte_length);
extern function void write_stream_status(ref chdr_header_t header,
ref chdr_str_status_t status);
@@ -62,12 +65,12 @@ package PkgChdrBfm;
ref chdr_ctrl_header_t ctrl_header,
ref ctrl_op_word_t ctrl_op_word,
ref ctrl_word_t ctrl_data[$],
- input chdr_word_t ctrl_timestamp = 0);
+ input chdr_timestamp_t ctrl_timestamp = 0);
extern function void read_ctrl (output chdr_header_t header,
output chdr_ctrl_header_t ctrl_header,
output ctrl_op_word_t ctrl_op_word,
output ctrl_word_t ctrl_data[$],
- output chdr_word_t ctrl_timestamp);
+ output chdr_timestamp_t ctrl_timestamp);
// Helper methods
@@ -79,6 +82,8 @@ package PkgChdrBfm;
extern function string sprint_raw();
extern function string sprint_pretty();
+ extern function bit chdr_word_queues_equal(ref chdr_word_t a[$], ref chdr_word_t b[$]);
+
endclass : ChdrPacket;
@@ -88,14 +93,14 @@ package PkgChdrBfm;
//---------------------------------------------------------------------------
class ChdrBfm #(
- parameter int BUS_WIDTH = 64,
+ parameter int CHDR_W = 64,
parameter int USER_WIDTH = 1
- ) extends AxiStreamBfm #(BUS_WIDTH, USER_WIDTH);
+ ) extends AxiStreamBfm #(CHDR_W, USER_WIDTH);
- typedef ChdrPacket #(BUS_WIDTH) ChdrPacket;
+ typedef ChdrPacket #(CHDR_W) ChdrPacket;
+ typedef ChdrData #(CHDR_W)::chdr_word_t chdr_word_t;
- // Number of 64-bit CHDR words per AXI word
- const int CHDR_PER_BUS = BUS_WIDTH / $bits(chdr_word_t);
+ const int BYTES_PER_CHDR_W = CHDR_W / 8;
// Default fields used by high-level transaction methods
chdr_epid_t dst_epid;
@@ -103,8 +108,8 @@ package PkgChdrBfm;
extern function new (
- virtual AxiStreamIf #(BUS_WIDTH, USER_WIDTH).master master,
- virtual AxiStreamIf #(BUS_WIDTH, USER_WIDTH).slave slave
+ virtual AxiStreamIf #(CHDR_W, USER_WIDTH).master master,
+ virtual AxiStreamIf #(CHDR_W, USER_WIDTH).slave slave
);
@@ -210,7 +215,7 @@ package PkgChdrBfm;
str = {str, $sformatf(" > chdr_str_command_t : %p\n", tmp_cmd)};
end else if (header.pkt_type == CHDR_CONTROL) begin
chdr_header_t tmp_hdr;
- chdr_word_t tmp_ts;
+ chdr_timestamp_t tmp_ts;
chdr_ctrl_header_t tmp_ctrl_hdr;
ctrl_op_word_t tmp_op_word;
ctrl_word_t tmp_ctrl_data[$];
@@ -250,11 +255,11 @@ package PkgChdrBfm;
// method to calculate the payload length based on the size of the data
// array.
function void ChdrPacket::write_raw (
- ref chdr_header_t header,
- ref chdr_word_t data[$],
- input chdr_word_t metadata[$] = {},
- input chdr_word_t timestamp = 0,
- input int data_byte_length = -1
+ ref chdr_header_t header,
+ ref chdr_word_t data[$],
+ input chdr_word_t metadata[$] = {},
+ input chdr_timestamp_t timestamp = 0,
+ input int data_byte_length = -1
);
this.header = header;
this.timestamp = timestamp;
@@ -267,11 +272,11 @@ package PkgChdrBfm;
int array_num_bytes;
// Make sure number of words for data_byte_length matches data length
- assert((data_byte_length+7) / 8 == data.size()) else begin
+ assert((data_byte_length+(BYTES_PER_CHDR_W-1)) / BYTES_PER_CHDR_W == data.size()) else begin
$error("ChdrPacket::write_raw: data_byte_length doesn't correspond to number of words in data");
end
- array_num_bytes = data.size() * $bits(chdr_word_t)/8;
+ array_num_bytes = data.size() * BYTES_PER_CHDR_W;
this.header.length -= (array_num_bytes - data_byte_length);
end
endfunction : write_raw
@@ -279,11 +284,11 @@ package PkgChdrBfm;
// Read the contents of this packet
function void ChdrPacket::read_raw (
- output chdr_header_t header,
- output chdr_word_t data[$],
- output chdr_word_t metadata[$],
- output chdr_word_t timestamp,
- output int data_byte_length
+ output chdr_header_t header,
+ output chdr_word_t data[$],
+ output chdr_word_t metadata[$],
+ output chdr_timestamp_t timestamp,
+ output int data_byte_length
);
header = this.header;
data = this.data;
@@ -301,8 +306,8 @@ package PkgChdrBfm;
header.pkt_type = CHDR_STRM_STATUS; // Update packet type in header
this.header = header;
data = {};
- for (int i = 0; i < $bits(status); i += $bits(chdr_word_t)) begin
- data.push_back( status[i +: $bits(chdr_word_t)] );
+ for (int i = 0; i < $bits(status); i += CHDR_W) begin
+ data.push_back( status[i +: CHDR_W] );
end
update_lengths();
endfunction : write_stream_status
@@ -315,17 +320,17 @@ package PkgChdrBfm;
);
// Make sure it's a stream status packet
assert(this.header.pkt_type == CHDR_STRM_STATUS) else begin
- $error("ChdrPacket::read_status: Packet type is not CHDR_STRM_STATUS");
+ $error("ChdrPacket::read_stream_status: Packet type is not CHDR_STRM_STATUS");
end
// Make sure we have enough payload
assert($bits(status) <= $bits(data)) else begin
- $error("ChdrPacket::read_status: Not enough data for status payload");
+ $error("ChdrPacket::read_stream_status: Not enough data for status payload");
end
header = this.header;
- for (int i = 0; i < $bits(status)/$bits(chdr_word_t); i++) begin
- status[i*$bits(chdr_word_t) +: $bits(chdr_word_t)] = data[i];
+ for (int i = 0; i < $bits(status)/CHDR_W; i++) begin
+ status[i*CHDR_W +: CHDR_W] = data[i];
end
endfunction : read_stream_status
@@ -338,8 +343,8 @@ package PkgChdrBfm;
header.pkt_type = CHDR_STRM_CMD; // Update packet type in header
this.header = header;
data = {};
- for (int i = 0; i < $bits(command); i += $bits(chdr_word_t)) begin
- data.push_back( command[i +: $bits(chdr_word_t)] );
+ for (int i = 0; i < $bits(command); i += CHDR_W) begin
+ data.push_back( command[i +: CHDR_W] );
end
update_lengths();
endfunction : write_stream_cmd
@@ -352,17 +357,17 @@ package PkgChdrBfm;
);
// Make sure it's a stream command packet
assert(this.header.pkt_type == CHDR_STRM_CMD) else begin
- $error("ChdrPacket::read_command: Packet type is not CHDR_STRM_CMD");
+ $error("ChdrPacket::read_stream_cmd: Packet type is not CHDR_STRM_CMD");
end
// Make sure we have enough payload
assert($bits(command) <= $bits(data)) else begin
- $error("ChdrPacket::read_command: Not enough data for command payload");
+ $error("ChdrPacket::read_stream_cmd: Not enough data for command payload");
end
header = this.header;
- for (int i = 0; i < $bits(command)/$bits(chdr_word_t); i++) begin
- command[i*$bits(chdr_word_t) +: $bits(chdr_word_t)] = data[i];
+ for (int i = 0; i < $bits(command)/CHDR_W; i++) begin
+ command[i*CHDR_W +: CHDR_W] = data[i];
end
endfunction : read_stream_cmd
@@ -402,7 +407,7 @@ package PkgChdrBfm;
header = this.header;
- num_ops = data_bytes()/8 - 1; // Num words, minus one for the header
+ num_ops = data_bytes()/BYTES_PER_CHDR_W - 1; // Num words, minus one for the header
// Make sure we have enough payload
assert(1 + num_ops <= data.size()) else begin
@@ -425,34 +430,49 @@ package PkgChdrBfm;
ref chdr_ctrl_header_t ctrl_header,
ref ctrl_op_word_t ctrl_op_word,
ref ctrl_word_t ctrl_data[$],
- input chdr_word_t ctrl_timestamp = 0
+ input chdr_timestamp_t ctrl_timestamp = 0
);
bit partial_word;
ctrl_word_t mandatory_data;
+ ChdrData #(CHDR_W, 64)::item_queue_t data64;
+
header.pkt_type = CHDR_CONTROL; // Update packet type in header
this.header = header;
- data = {};
+ data64 = {};
// Insert word 0 of control payload
- data.push_back(ctrl_header[63:0]);
+ data64.push_back(ctrl_header);
// Insert word 1 of control payload, if timestamp is used
if (ctrl_header.has_time) begin
- data.push_back(ctrl_timestamp);
+ data64.push_back(ctrl_timestamp);
+ end
+
+ // Make sure the amount of data passed matches the header
+ assert (ctrl_header.num_data == ctrl_data.size()) else begin
+ $error("ChdrPacket::write_ctrl: NumData doesn't match ctrl_data[] size");
end
// Insert word 2 of control payload, the operation word
// and first word of control data.
mandatory_data = (ctrl_header.num_data > 0) ? ctrl_data[0] : '0;
- data.push_back({mandatory_data, ctrl_op_word[31:0]});
+ data64.push_back({mandatory_data, ctrl_op_word[31:0]});
// We have a half CHDR word if num_data is even
partial_word = (ctrl_header.num_data[0] == '0);
// Insert remaining data, if present
for (int i = 1; i < ctrl_data.size(); i+=2) begin
- data.push_back({(partial_word ? '0 : ctrl_data[i+1]), ctrl_data[i]});
+ if (i == ctrl_data.size()-1) begin
+ // num_data must be even in this case, so last word is half filled
+ data64.push_back({ 32'b0, ctrl_data[i] });
+ end else begin
+ data64.push_back({ ctrl_data[i+1], ctrl_data[i] });
+ end
end
+ // Convert from 64-bit words to CHDR_W-bit words
+ data = ChdrData #(CHDR_W, 64)::item_to_chdr(data64);
+
update_lengths();
endfunction : write_ctrl
@@ -463,62 +483,71 @@ package PkgChdrBfm;
output chdr_ctrl_header_t ctrl_header,
output ctrl_op_word_t ctrl_op_word,
output ctrl_word_t ctrl_data[$],
- output chdr_word_t ctrl_timestamp
+ output chdr_timestamp_t ctrl_timestamp
);
+ ChdrData #(CHDR_W, 32)::item_queue_t data32;
chdr_word_t chdr_op_word;
+ int ctrl_packet_size;
int dptr = 0;
// Make sure it's a stream status packet
assert(this.header.pkt_type == CHDR_CONTROL) else begin
- $error("ChdrPacket::read_status: Packet type is not CHDR_CONTROL");
+ $error("ChdrPacket::read_ctrl: Packet type is not CHDR_CONTROL");
end
- // Make sure we have enough payload
- assert($bits(ctrl_header)+$bits(ctrl_op_word) <= $bits(data)) else begin
- $error("ChdrPacket::read_status: Not enough data for status payload");
- end
+ // Convert packet to 32-bit words for easier parsing
+ data32 = ChdrData #(CHDR_W, 32)::chdr_to_item(data, data_bytes());
+ // CHDR header
header = this.header;
- // Word 0
- ctrl_header[63:0] = data[dptr++];
+ // Ctrl header
+ ctrl_header = { data32[dptr+1], data32[dptr] };
+ dptr += 2;
- // Word 1
- if (ctrl_header.has_time) begin
- ctrl_timestamp = data[dptr++];
+ // Make sure we have enough payload. Calculate expected size in 32-bit
+ // words.
+ ctrl_packet_size = 3 + ctrl_header.num_data; // header + op_word + data
+ if (ctrl_header.has_time) ctrl_packet_size += 2; // timestamp
+ assert(data32.size() < ctrl_packet_size) else begin
+ $error("ChdrPacket::read_ctrl: Not enough CHDR payload for control packet");
+ end
+ assert(data32.size() > ctrl_packet_size) else begin
+ $warning("ChdrPacket::read_ctrl: Excess CHDR payload for control packet");
end
- // Word 2, last 32-bits of control header and first word of control data
- chdr_op_word = data[dptr++];
- ctrl_op_word = chdr_op_word[31:0];
- ctrl_data.delete();
- if (ctrl_header.num_data > 0) begin
- ctrl_data[0] = chdr_op_word[63:32];
+ // Timestamp (optional)
+ if(ctrl_header.has_time) begin
+ ctrl_timestamp = { data32[dptr+1], data32[dptr] };
+ dptr += 2;
end
- // Copy any remaining data words
- for (int i = dptr; i < data.size(); i++) begin
- ctrl_data.push_back(data[i][31:0]);
- if (i != data.size()-1 || ctrl_header.num_data[0] != 0)
- ctrl_data.push_back(data[i][63:32]);
+ // Operation word
+ ctrl_op_word = data32[dptr++];
+
+ // Data words
+ ctrl_data = {};
+ while (dptr < data32.size()) begin
+ ctrl_data.push_back(data32[dptr++]);
end
+
endfunction : read_ctrl
// Calculate the header size (including timestamp), in bytes, from the header
// information.
function int ChdrPacket::header_bytes();
- if (BUS_WIDTH == $bits(chdr_word_t) && header.pkt_type == CHDR_DATA_WITH_TS) begin
- header_bytes = 2 * (BUS_WIDTH / 8); // Two words (header + timestamp)
+ if (CHDR_W == 64 && header.pkt_type == CHDR_DATA_WITH_TS) begin
+ header_bytes = 2 * BYTES_PER_CHDR_W; // Two words (header + timestamp)
end else begin
- header_bytes = (BUS_WIDTH / 8); // One word, regardless of timestamp
+ header_bytes = BYTES_PER_CHDR_W; // One word, regardless of timestamp
end
endfunction : header_bytes
// Calculate the metadata size from the header information.
function int ChdrPacket::mdata_bytes();
- mdata_bytes = header.num_mdata * BUS_WIDTH/8;
+ mdata_bytes = header.num_mdata * BYTES_PER_CHDR_W;
endfunction : mdata_bytes
@@ -535,15 +564,12 @@ package PkgChdrBfm;
int num_mdata;
// Calculate NumMData based on the size of metadata queue
- num_mdata = metadata.size() / (BUS_WIDTH / $bits(chdr_word_t));
- if (metadata.size() % (BUS_WIDTH / $bits(chdr_word_t)) != 0) begin
- num_mdata++;
- end
+ num_mdata = metadata.size();
assert(num_mdata < 2**$bits(chdr_num_mdata_t)) else
$fatal(1, "ChdrPacket::update_lengths(): Calculated NumMData exceeds maximum size");
// Calculate the Length field
- num_bytes = data.size() * $bits(chdr_word_t) / 8; // Payload length
+ num_bytes = data.size() * BYTES_PER_CHDR_W; // Payload length
num_bytes = num_bytes + header_bytes() + mdata_bytes(); // Payload + header length
assert(num_bytes < 2**$bits(chdr_length_t)) else
$fatal(1, "ChdrPacket::update_lengths(): Calculated Length exceeds maximum size");
@@ -554,6 +580,20 @@ package PkgChdrBfm;
endfunction : update_lengths
+ // Returns 1 if the queues have the same contents, otherwise returns 0. This
+ // function is equivalent to (a == b), but this doesn't work correctly yet in
+ // Vivado 2018.3.
+ function automatic bit ChdrPacket::chdr_word_queues_equal(ref chdr_word_t a[$], ref chdr_word_t b[$]);
+ chdr_word_t x, y;
+ if (a.size() != b.size()) return 0;
+ foreach (a[i]) begin
+ x = a[i];
+ y = b[i];
+ if (x !== y) return 0;
+ end
+ return 1;
+ endfunction : chdr_word_queues_equal
+
//---------------------------------------------------------------------------
@@ -564,11 +604,11 @@ package PkgChdrBfm;
// Class constructor. This must be given an interface for the master
// connection and an interface for the slave connection.
function ChdrBfm::new (
- virtual AxiStreamIf #(BUS_WIDTH, USER_WIDTH).master master,
- virtual AxiStreamIf #(BUS_WIDTH, USER_WIDTH).slave slave
+ virtual AxiStreamIf #(CHDR_W, USER_WIDTH).master master,
+ virtual AxiStreamIf #(CHDR_W, USER_WIDTH).slave slave
);
super.new(master, slave);
- assert(BUS_WIDTH % 64 == 0) else begin
+ assert(CHDR_W % 64 == 0) else begin
$fatal(1, "ChdrBfm::new: CHDR bus width must be a multiple of 64 bits");
end
endfunction : new
@@ -637,6 +677,7 @@ package PkgChdrBfm;
enum int { ST_HEADER, ST_TIMESTAMP, ST_METADATA, ST_PAYLOAD } rx_state;
data_t word;
int num_rx_mdata;
+ int num_rx_bytes;
ChdrPacket chdr_packet = new();
rx_state = ST_HEADER;
@@ -646,12 +687,13 @@ package PkgChdrBfm;
case (rx_state)
ST_HEADER : begin
+ num_rx_bytes += BYTES_PER_CHDR_W;
chdr_packet.header = word[63:0];
// Depending on the size of the word, we could have just the header
// or both the header and the timestamp in this word.
if (chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS) begin
- if ($bits(word) >= 128) begin
+ if (CHDR_W >= 128) begin
chdr_packet.timestamp = word[127:64];
rx_state = ST_METADATA;
end else begin
@@ -667,33 +709,33 @@ package PkgChdrBfm;
end
end
ST_TIMESTAMP : begin
+ num_rx_bytes += BYTES_PER_CHDR_W;
chdr_packet.timestamp = word;
rx_state = (chdr_packet.header.num_mdata > 0) ? ST_METADATA : ST_PAYLOAD;
end
ST_METADATA : begin
- for(int w = 0; w < CHDR_PER_BUS; w++) begin
- // Grab the next chdr_word_t worth of bits
- //$display("Grabbing meta word %d (%016X)", w, word[w*$bits(chdr_word_t) +: $bits(chdr_word_t)]);
- chdr_packet.metadata.push_back(word[w*$bits(chdr_word_t) +: $bits(chdr_word_t)]);
- end
+ chdr_packet.metadata.push_back(word);
num_rx_mdata++;
+ num_rx_bytes += BYTES_PER_CHDR_W;
if (num_rx_mdata == chdr_packet.header.num_mdata) rx_state = ST_PAYLOAD;
end
ST_PAYLOAD : begin
- for(int w = 0; w < CHDR_PER_BUS; w++) begin
- // Grab the next chdr_word_t worth of bits
- //$display("Grabbing data word %d (%016X)", w, word[w*$bits(chdr_word_t) +: $bits(chdr_word_t)]);
- chdr_packet.data.push_back(word[w*$bits(chdr_word_t) +: $bits(chdr_word_t)]);
- end
+ chdr_packet.data.push_back(word);
+ num_rx_bytes += BYTES_PER_CHDR_W;
end
endcase
-
end
- assert(rx_state == ST_PAYLOAD) else begin
+ assert (rx_state == ST_PAYLOAD) else begin
$error("ChdrBfm::axis_to_chdr: Malformed CHDR packet");
end
+ // Check length field, noting that the last word may be partially filled
+ assert (chdr_packet.header.length >= num_rx_bytes-(BYTES_PER_CHDR_W-1) &&
+ chdr_packet.header.length <= num_rx_bytes) else begin
+ $error("ChdrBfm::axis_to_chdr: Incorrect CHDR length");
+ end
+
return chdr_packet;
endfunction : axis_to_chdr
@@ -702,44 +744,37 @@ package PkgChdrBfm;
// Convert a CHDR packet data structure to a an AXI-Stream packet data
// structure.
function ChdrBfm::AxisPacket ChdrBfm::chdr_to_axis (ChdrPacket chdr_packet);
- int num_bus_words, num_chdr_words, expected_bus_words;
+ int num_words, expected_words;
data_t bus_word = 0;
AxisPacket axis_packet = new();
// Check that we have the right number of metadata words
- num_chdr_words = chdr_packet.metadata.size();
- num_bus_words = num_chdr_words / CHDR_PER_BUS;
- if (num_chdr_words % CHDR_PER_BUS != 0) num_bus_words++;
- assert (num_bus_words == chdr_packet.header.num_mdata) else begin
+ assert (chdr_packet.metadata.size() == chdr_packet.header.num_mdata) else begin
$error("ChdrBfm::chdr_to_axis: Packet metadata size doesn't match header NumMData field");
end
// Calculate the number of words needed to represent this packet
- num_bus_words = 0;
- num_bus_words += chdr_packet.data.size() / CHDR_PER_BUS;
- if (chdr_packet.data.size() % CHDR_PER_BUS != 0) num_bus_words++;
- num_bus_words += chdr_packet.metadata.size() / CHDR_PER_BUS;
- if (chdr_packet.metadata.size() % CHDR_PER_BUS != 0) num_bus_words++;
- if (chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS && CHDR_PER_BUS == 1) begin
+ num_words = chdr_packet.data.size() + chdr_packet.metadata.size();
+ if (chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS && CHDR_W == 64) begin
// Add two words, one for header and one for timestamp
- num_bus_words += 2;
+ num_words += 2;
end else begin
// Add one word only for header (which may or may not include a timestamp)
- num_bus_words += 1;
+ num_words += 1;
end
// Calculate the number of words represented by the Length field
- expected_bus_words = chdr_packet.header.length / (BUS_WIDTH/8);
- if (chdr_packet.header.length % (BUS_WIDTH/8) != 0) expected_bus_words++;
+ expected_words = chdr_packet.header.length / BYTES_PER_CHDR_W;
+ if (chdr_packet.header.length % BYTES_PER_CHDR_W != 0) expected_words++;
// Make sure length field matches actual packet length
- assert (num_bus_words == expected_bus_words) else begin
+ assert (num_words == expected_words) else begin
$error("ChdrBfm::chdr_to_axis: Packet size doesn't match header Length field");
end
// Insert header
bus_word[63:0] = chdr_packet.header;
- if (BUS_WIDTH == 64) begin
+ if (CHDR_W == 64) begin
axis_packet.data.push_back(bus_word);
if (chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS) begin
// Insert timestamp
@@ -754,21 +789,13 @@ package PkgChdrBfm;
// Insert metadata
while (chdr_packet.metadata.size() > 0) begin
- bus_word = 0;
- for (int w = 0; w < CHDR_PER_BUS; w++) begin
- bus_word[w*$bits(chdr_word_t) +: $bits(chdr_word_t)] = chdr_packet.metadata.pop_front();
- if (chdr_packet.metadata.size() == 0) break;
- end
+ bus_word = chdr_packet.metadata.pop_front();
axis_packet.data.push_back(bus_word);
end
// Insert payload
while (chdr_packet.data.size() > 0) begin
- bus_word = 0;
- for (int word_count = 0; word_count < CHDR_PER_BUS; word_count++) begin
- bus_word[word_count*64 +: 64] = chdr_packet.data.pop_front();
- if (chdr_packet.data.size() == 0) break;
- end
+ bus_word = chdr_packet.data.pop_front();
axis_packet.data.push_back(bus_word);
end
diff --git a/fpga/usrp3/sim/rfnoc/PkgChdrData.sv b/fpga/usrp3/sim/rfnoc/PkgChdrData.sv
new file mode 100644
index 000000000..a849346d6
--- /dev/null
+++ b/fpga/usrp3/sim/rfnoc/PkgChdrData.sv
@@ -0,0 +1,155 @@
+//
+// Copyright 2020 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: PkgChdrData
+//
+// Description: This package defines the data types used to represent CHDR
+// words and data samples in RFNoC as well as utilities for converting between
+// them.
+//
+
+package PkgChdrData;
+
+ // Default value for ITEM_W needs to be 64 due to a bug in Vivado 2019.1.
+ class ChdrData #(int CHDR_W = 64, int ITEM_W = 64);
+
+ // CHDR bus word (CHDR_W bits)
+ typedef logic [CHDR_W-1:0] chdr_word_t ;
+ typedef chdr_word_t chdr_word_queue_t[$];
+
+ // The item/sample word type (user-defined width, a multiple of 8 bits)
+ typedef logic [ITEM_W-1:0] item_t ;
+ typedef item_t item_queue_t[$];
+
+
+ function new();
+ assert ((ITEM_W % 8 == 0) && (CHDR_W % ITEM_W == 0)) else begin
+ $fatal(1, "RfnocData::new: Invalid CHDR_W and/or ITEM_W");
+ end
+ endfunction
+
+
+ // Convert a queue of items to a queue of CHDR words
+ static function chdr_word_queue_t item_to_chdr(ref item_queue_t items);
+ int items_per_word = CHDR_W / ITEM_W;
+ int num_chdr_words = ((items.size() + items_per_word - 1) / items_per_word);
+ chdr_word_queue_t chdr_words;
+ chdr_word_t word;
+
+ for (int i = 0; i < num_chdr_words; i++) begin
+ for (int j = 0; j < items_per_word; j++) begin
+ word[j*ITEM_W +: ITEM_W] = items[i*items_per_word + j];
+ end
+ chdr_words.push_back(word);
+ end
+ return chdr_words;
+ endfunction : item_to_chdr
+
+
+ // Convert a queue of CHDR words to a queue of items. The optional
+ // num_bytes argument indicates how many bytes are in the item queue that
+ // you want to convert.
+ static function item_queue_t chdr_to_item(
+ ref chdr_word_queue_t chdr_words,
+ input int num_bytes = -1
+ );
+ int items_per_word = CHDR_W / ITEM_W;
+ int bytes_left;
+ item_queue_t item_words;
+
+ if (num_bytes < 0) bytes_left = chdr_words.size() * (CHDR_W / 8);
+ else bytes_left = num_bytes;
+
+ foreach (chdr_words[i]) begin
+ for (int j = 0; j < items_per_word; j++) begin
+ if (bytes_left > 0) begin
+ item_words.push_back(chdr_words[i][j*ITEM_W +: ITEM_W]);
+ bytes_left -= (ITEM_W/8);
+ end
+ end
+ end
+
+ assert (bytes_left == 0) else begin
+ $warning("ChdrData::chdr_to_item: num_bytes is not a multiple of items");
+ end
+
+ return item_words;
+ endfunction : chdr_to_item
+
+
+ // Return a string representation of the contents of the CHDR queue
+ static function string chdr_string(
+ ref chdr_word_queue_t chdr_words,
+ input string format = "%X"
+ );
+ string str = $sformatf("%0d-bit CHDR words (%0d words or %0d bytes):\n",
+ CHDR_W, chdr_words.size(), chdr_words.size() * (CHDR_W/8));
+ foreach (chdr_words[i]) begin
+ str = { str, $sformatf({"%5d> ", format, "\n"}, i, chdr_words[i]) };
+ end
+ return str;
+ endfunction : chdr_string
+
+
+ // Return a string representation of the contents of the item queue
+ static function string item_string(
+ ref item_queue_t items,
+ input string format = "%X"
+ );
+ string str = $sformatf("%0d-bit items (%0d items or %0d bytes)\n",
+ ITEM_W, items.size(), items.size() * (ITEM_W/8));
+ foreach (items[i]) begin
+ str = { str, $sformatf({"%5d> ", format, "\n"}, i, items[i]) };
+ end
+ return str;
+ endfunction : item_string
+
+
+ // Display a string representation of the contents of a CHDR word queue
+ static function void print_chdr(
+ ref chdr_word_queue_t chdr_words,
+ input string format = "%X"
+ );
+ $display(chdr_string(chdr_words, format));
+ endfunction : print_chdr
+
+
+ // Display a string representation of the contents of an item queue
+ static function void print_item(
+ ref item_queue_t items,
+ input string format = "%X"
+ );
+ $display(item_string(items, format));
+ endfunction : print_item
+
+
+ // Check if the contents of two CHDR queues is equal
+ static function bit chdr_equal(
+ ref chdr_word_queue_t left,
+ ref chdr_word_queue_t right
+ );
+ if (left.size() != right.size()) return 0;
+ for (int i = 0; i < left.size(); i++) begin
+ if (left[i] != right[i]) return 0;
+ end
+ return 1;
+ endfunction : chdr_equal
+
+
+ // Check if the contents of two item queues is equal
+ static function bit item_equal(
+ ref item_queue_t left,
+ ref item_queue_t right
+ );
+ if (left.size() != right.size()) return 0;
+ for (int i = 0; i < left.size(); i++) begin
+ if (left[i] != right[i]) return 0;
+ end
+ return 1;
+ endfunction : item_equal
+
+ endclass
+
+endpackage : PkgChdrData
diff --git a/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv b/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv
index 513910ee7..0b372684c 100644
--- a/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv
+++ b/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv
@@ -16,11 +16,11 @@ package PkgChdrIfaceBfm;
typedef struct packed {
- chdr_vc_t vc;
- logic eob;
- logic eov;
- logic has_time;
- chdr_word_t timestamp;
+ chdr_vc_t vc;
+ chdr_eob_t eob;
+ chdr_eov_t eov;
+ bit has_time;
+ chdr_timestamp_t timestamp;
} packet_info_t;
diff --git a/fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv b/fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv
index 5f7abb46f..31c6984d7 100644
--- a/fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv
+++ b/fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv
@@ -13,16 +13,20 @@
package PkgChdrUtils;
+ import PkgChdrData::*;
+
+
//---------------------------------------------------------------------------
// Type Definitions
//---------------------------------------------------------------------------
- // CHDR Definitions
- // ----------------
+ //----------------------
+ // AXIS-CHDR Definitions
+ //----------------------
- // The fundamental unit of the CHDR bus, which is always a multiple of 64-bits
- typedef logic [63:0] chdr_word_t;
- typedef chdr_word_t chdr_word_queue_t[$];
+ // Expose the CHDR word and item/sample data types and methods in the
+ // ChdrData class. The width of these types is a class parameter.
+ export PkgChdrData::ChdrData;
// CHDR header fields
typedef enum bit [2:0] {
@@ -37,10 +41,13 @@ package PkgChdrUtils;
} chdr_pkt_type_t; // CHDR Packet Type
typedef bit [ 5:0] chdr_vc_t; // CHDR Virtual Channel field
+ typedef bit [ 0:0] chdr_eob_t; // CHDR End of Burst field
+ typedef bit [ 0:0] chdr_eov_t; // CHDR End of Vector field
typedef bit [ 4:0] chdr_num_mdata_t; // CHDR Num Metadata field
typedef bit [15:0] chdr_seq_num_t; // CHDR SeqNum field
typedef bit [15:0] chdr_length_t; // CHDR Length field
typedef bit [15:0] chdr_epid_t; // CHDR EPID field
+ typedef bit [63:0] chdr_timestamp_t; // CHDR Timestamp field
// CHDR Context Field Identifiers
typedef enum bit [3:0] {
@@ -50,8 +57,9 @@ package PkgChdrUtils;
CONTEXT_FIELD_MDATA = 4'd3
} chdr_context_type_t;
+ //----------------------
// AXIS-Ctrl Definitions
- // ---------------------
+ //----------------------
// The fundamental unit of the AXIS-Ctrl (control) bus, which is always 32 bits
typedef logic [31:0] ctrl_word_t;
@@ -82,9 +90,9 @@ package PkgChdrUtils;
typedef bit [3:0] ctrl_byte_en_t; // AXIS-Ctrl ByteEnable field
typedef bit [19:0] ctrl_address_t; // AXIS-Ctrl Address field
-
+ //-------------------------------
// CHDR Type-Specific Definitions
- // ------------------------------
+ //-------------------------------
// CHDR Status packet fields
typedef enum bit [3:0] {
@@ -141,8 +149,8 @@ package PkgChdrUtils;
// CHDR packet header
typedef struct packed {
chdr_vc_t vc;
- bit eob;
- bit eov;
+ chdr_eob_t eob;
+ chdr_eov_t eov;
chdr_pkt_type_t pkt_type;
chdr_num_mdata_t num_mdata;
chdr_seq_num_t seq_num;
@@ -237,39 +245,4 @@ package PkgChdrUtils;
} chdr_mgmt_t;
-
- //---------------------------------------------------------------------------
- // Functions
- //---------------------------------------------------------------------------
-
- // Returns 1 if the queues have the same contents, otherwise returns 0. This
- // function is equivalent to (a == b), but this doesn't work correctly yet in
- // Vivado 2018.3.
- function automatic bit chdr_word_queues_equal(ref chdr_word_t a[$], ref chdr_word_t b[$]);
- chdr_word_t x, y;
- if (a.size() != b.size()) return 0;
- foreach (a[i]) begin
- x = a[i];
- y = b[i];
- if (x !== y) return 0;
- end
- return 1;
- endfunction : chdr_word_queues_equal
-
-
- // Returns 1 if the queues have the same contents, otherwise returns 0. This
- // function is equivalent to (a == b), but this doesn't work correctly yet in
- // Vivado 2018.3.
- function automatic bit chdr_mgmt_op_queues_equal(ref chdr_mgmt_op_t a[$], ref chdr_mgmt_op_t b[$]);
- chdr_mgmt_op_t x, y;
- if (a.size() != b.size()) return 0;
- foreach (a[i]) begin
- x = a[i];
- y = b[i];
- if (x !== y) return 0;
- end
- return 1;
- endfunction : chdr_mgmt_op_queues_equal
-
-
endpackage : PkgChdrUtils
diff --git a/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv b/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv
index 722299bb6..ac2bf00ec 100644
--- a/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv
+++ b/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv
@@ -96,13 +96,15 @@ package PkgRfnocBlockCtrlBfm;
class RfnocBlockCtrlBfm #(CHDR_W = 64);
local virtual RfnocBackendIf.master backend;
- local CtrlIfaceBfm ctrl;
- local ChdrIfaceBfm #(CHDR_W) m_data[$];
- local ChdrIfaceBfm #(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;
+ typedef ChdrData #(CHDR_W)::chdr_word_t chdr_word_t;
+
// Class constructor to create a new BFM instance.
//
// backend: Interface for the backend signals of a block
diff --git a/fpga/usrp3/sim/rfnoc/PkgRfnocItemUtils.sv b/fpga/usrp3/sim/rfnoc/PkgRfnocItemUtils.sv
index 2c671ad93..f827d2363 100644
--- a/fpga/usrp3/sim/rfnoc/PkgRfnocItemUtils.sv
+++ b/fpga/usrp3/sim/rfnoc/PkgRfnocItemUtils.sv
@@ -5,11 +5,14 @@
//
// Module: PkgRfnocItemUtils
//
-// Description: This package contains utilities to handle and process items.
+// Description: This package contains classes to handle and process CHDR items
+// (e.g., samples) and to convert between CHDR words and items. It includes the
+// following classes:
//
-// - ItemDataBuff: A class that holds a collection of items of arbitrary width
-// To can convert to and from a CHDR vector
-// - ItemDataBuffQueue: A queue of ItemDataBuff buffers
+// - ItemDataBuff: A class that holds a collection of items of arbitrary
+// width and functions to convert to and from a CHDR vector.
+//
+// - ItemDataBuffQueue: A queue of ItemDataBuff buffers
//
package PkgRfnocItemUtils;
@@ -20,14 +23,20 @@ package PkgRfnocItemUtils;
// Item Data Buffer
//---------------------------------------------------------------------------
//
- // This class items of an arbitrary type
+ // This is a class of "items" of an arbitrary type
//
//---------------------------------------------------------------------------
- class ItemDataBuff #(type data_t);
- typedef ItemDataBuff #(data_t) ItemDataBuffQueue[$];
+
+ class ItemDataBuff #(type item_t = logic [31:0], int CHDR_W = 64);
+
+ localparam ITEM_W = $bits(item_t);
+
+ // Redefine these types from PkgChdrUtils to workaround Vivado 2019.1 bug
+ typedef logic [CHDR_W-1:0] chdr_word_t;
+ typedef chdr_word_t chdr_word_queue_t[$];
// Store data in the user-specified format
- local data_t buff[$];
+ local item_t buff[$];
// Create a new empty buffer
function new();
@@ -36,7 +45,7 @@ package PkgRfnocItemUtils;
// Get the bitwidth of a item in this buffer
function int item_w();
- return $size(data_t);
+ return ITEM_W;
endfunction : item_w
// Delete the contents of this buffer
@@ -55,48 +64,46 @@ package PkgRfnocItemUtils;
endfunction : get_bytes
// Get the i'th element in this buffer
- function data_t get(int i);
+ function item_t get(int i);
return buff[i];
endfunction : get
// Put and element in this buffer. If i is negative
// then put it at the end
- function void put(data_t d, int i = -1);
+ function void put(item_t d, int i = -1);
if (i < 0)
buff.push_back(d);
else
buff.insert(i, d);
endfunction : put
- // Convert the contents of this buffer to a CHDR payload
- // A CHDR payload can be transmitted using the block controller
- // BFM.
+ // Convert the contents of this buffer to a CHDR payload A CHDR payload can
+ // be transmitted using the block controller BFM.
function chdr_word_queue_t to_chdr_payload();
- int samps_per_word = $size(chdr_word_t) / $size(data_t);
+ int samps_per_word = CHDR_W / ITEM_W;
int num_chdr_lines = ((buff.size() + samps_per_word - 1) / samps_per_word);
chdr_word_t chdr_w_vtr[$];
for (int i = 0; i < num_chdr_lines; i++) begin
chdr_word_t tmp = 'x;
for (int j = 0; j < samps_per_word; j++) begin
- tmp[j*$size(data_t) +: $size(data_t)] = buff[i*samps_per_word + j];
+ tmp[j*ITEM_W +: ITEM_W] = buff[i*samps_per_word + j];
end
chdr_w_vtr.push_back(tmp);
end
return chdr_w_vtr;
endfunction : to_chdr_payload
- // Populate this buffer using a CHDR payload
- // A CHDR payload can be received using the block controller
- // BFM.
+ // Populate this buffer using a CHDR payload A CHDR payload can be received
+ // using the block controller BFM.
function void from_chdr_payload(chdr_word_queue_t chdr_w_vtr, int bytes);
- int samps_per_word = $size(chdr_word_t) / $size(data_t);
+ int samps_per_word = CHDR_W / ITEM_W;
int bytes_left = bytes;
buff.delete();
foreach (chdr_w_vtr[i]) begin
for (int j = 0; j < samps_per_word; j++) begin
if (bytes_left > 0) begin
- buff.push_back(chdr_w_vtr[i][j*$size(data_t) +: $size(data_t)]);
- bytes_left -= ($size(data_t)/8);
+ buff.push_back(chdr_w_vtr[i][j*ITEM_W +: ITEM_W]);
+ bytes_left -= (ITEM_W/8);
end
end
end
@@ -112,7 +119,7 @@ package PkgRfnocItemUtils;
end
return str;
end else begin
- string str = $sformatf("ItemDataBuff (%0d-bit)\n", $size(data_t));
+ string str = $sformatf("ItemDataBuff (%0d-bit)\n", ITEM_W);
foreach (buff[i]) begin
str = { str, $sformatf({"%5d> ", format, "\n"}, i, buff[i]) };
end
@@ -127,7 +134,7 @@ package PkgRfnocItemUtils;
// Check if the contents of two buffers is equal
function bit equal(
- ItemDataBuff #(data_t) rhs
+ ItemDataBuff #(item_t) rhs
);
if (this.size() != rhs.size()) return 0;
for (int i = 0; i < this.size(); i++) begin
@@ -139,8 +146,16 @@ package PkgRfnocItemUtils;
endclass
- class ItemDataBuffQueue #(type data_t);
- local ItemDataBuff #(data_t) queue[$];
+ //---------------------------------------------------------------------------
+ // Item Data Buffer Queue
+ //---------------------------------------------------------------------------
+ //
+ // This is a queue of item buffers
+ //
+ //---------------------------------------------------------------------------
+
+ class ItemDataBuffQueue #(type item_t = logic [31:0], int CHDR_W = 64);
+ local ItemDataBuff #(item_t, CHDR_W) queue[$];
// Create a new empty queue
function new();
@@ -158,13 +173,13 @@ package PkgRfnocItemUtils;
endfunction : size
// Get the i'th element in this buffer
- function ItemDataBuff #(data_t) get(int i);
+ function ItemDataBuff #(item_t) get(int i);
return queue[i];
endfunction : get
// Put an element in this buffer. If i is negative
// then put it at the end
- function void put(ItemDataBuff #(data_t) buff, int i = -1);
+ function void put(ItemDataBuff #(item_t) buff, int i = -1);
if (i < 0)
queue.push_back(buff);
else
@@ -181,10 +196,10 @@ package PkgRfnocItemUtils;
int handle = $fopen(filename, "r");
queue.delete();
while ($fgets(line, handle) > 0) begin
- data_t word = 'x;
+ item_t word = 'x;
int buff_i = word_i++ / max_buff_size;
if (queue.size() < buff_i + 1) begin
- ItemDataBuff #(data_t) buff = new;
+ ItemDataBuff #(item_t) buff = new;
queue.push_back(buff);
end
if ($sscanf(line, "%x", word) > 0) begin
diff --git a/host/examples/rfnoc-example/fpga/rfnoc_block_gain/rfnoc_block_gain_tb.sv b/host/examples/rfnoc-example/fpga/rfnoc_block_gain/rfnoc_block_gain_tb.sv
index 1f76563a8..2b0c892f7 100644
--- a/host/examples/rfnoc-example/fpga/rfnoc_block_gain/rfnoc_block_gain_tb.sv
+++ b/host/examples/rfnoc-example/fpga/rfnoc_block_gain/rfnoc_block_gain_tb.sv
@@ -27,11 +27,12 @@ module rfnoc_block_gain_tb;
localparam [ 9:0] THIS_PORTID = 10'h123;
localparam [31:0] NOC_ID = 32'h00000B16;
localparam int CHDR_W = 64;
+ localparam int ITEM_W = 32;
localparam int NUM_PORTS_I = 1;
localparam int NUM_PORTS_O = 1;
localparam int MTU = 13;
localparam int SPP = 64;
- localparam int PKT_SIZE_BYTES = SPP * 4; // Assumes 4 bytes per sample
+ localparam int PKT_SIZE_BYTES = SPP * (ITEM_W/8);
localparam int STALL_PROB = 25; // Default BFM stall probability
localparam real CHDR_CLK_PER = 5.0; // 200 MHz
localparam real CTRL_CLK_PER = 25.0; // 40 MHz
@@ -64,6 +65,10 @@ module rfnoc_block_gain_tb;
// Block Controller BFM
RfnocBlockCtrlBfm #(.CHDR_W(CHDR_W)) blk_ctrl = new(backend, m_ctrl, s_ctrl);
+ // CHDR word and item/sample data types
+ typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t;
+ typedef ChdrData #(CHDR_W, ITEM_W)::item_t item_t;
+
// Connect block controller to BFMs
for (genvar i = 0; i < NUM_PORTS_I; i++) begin : gen_bfm_input_connections
initial begin
diff --git a/host/utils/rfnoc_blocktool/templates/rfnoc_block_template_tb.sv.mako b/host/utils/rfnoc_blocktool/templates/rfnoc_block_template_tb.sv.mako
index 4ec1d1b93..ef535f166 100644
--- a/host/utils/rfnoc_blocktool/templates/rfnoc_block_template_tb.sv.mako
+++ b/host/utils/rfnoc_blocktool/templates/rfnoc_block_template_tb.sv.mako
@@ -28,6 +28,7 @@ module rfnoc_block_${config['module_name']}_tb;
localparam [ 9:0] THIS_PORTID = 10'h123;
localparam [31:0] NOC_ID = 32'h${format(config['noc_id'], "08X")};
localparam int CHDR_W = ${config['chdr_width']};
+ localparam int ITEM_W = 32;
%if 'parameters' in config:
%for param, value in config['parameters'].items():
localparam int ${'{:<15}'.format(param)} = ${value};
@@ -37,7 +38,7 @@ module rfnoc_block_${config['module_name']}_tb;
localparam int NUM_PORTS_O = ${func.num_ports_out_str()};
localparam int MTU = 13;
localparam int SPP = 64;
- localparam int PKT_SIZE_BYTES = SPP * 4; // Assumes 4 bytes per sample
+ localparam int PKT_SIZE_BYTES = SPP * (ITEM_W/8);
localparam int STALL_PROB = 25; // Default BFM stall probability
localparam real CHDR_CLK_PER = 5.0; // 200 MHz
localparam real CTRL_CLK_PER = 25.0; // 40 MHz
@@ -85,6 +86,10 @@ module rfnoc_block_${config['module_name']}_tb;
// Block Controller BFM
RfnocBlockCtrlBfm #(.CHDR_W(CHDR_W)) blk_ctrl = new(backend, m_ctrl, s_ctrl);
+ // CHDR word and item/sample data types
+ typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t;
+ typedef ChdrData #(CHDR_W, ITEM_W)::item_t item_t;
+
// Connect block controller to BFMs
for (genvar i = 0; i < NUM_PORTS_I; i++) begin : gen_bfm_input_connections
initial begin