aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/sim/rfnoc/PkgAxiStreamBfm.sv
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/sim/rfnoc/PkgAxiStreamBfm.sv')
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgAxiStreamBfm.sv239
1 files changed, 170 insertions, 69 deletions
diff --git a/fpga/usrp3/sim/rfnoc/PkgAxiStreamBfm.sv b/fpga/usrp3/sim/rfnoc/PkgAxiStreamBfm.sv
index 9e2530350..fd23e501c 100644
--- a/fpga/usrp3/sim/rfnoc/PkgAxiStreamBfm.sv
+++ b/fpga/usrp3/sim/rfnoc/PkgAxiStreamBfm.sv
@@ -1,61 +1,79 @@
//
-// Copyright 2019 Ettus Research, A National Instruments Company
+// Copyright 2020 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
-// Module: PkgAxiStream
+// Module: PkgAxiStreamBfm
//
-// Description: Package for a bi-directional AXI Stream bus functional model
-// (BFM). This consists of the AxiStreamIf interface, and the
-// AxiStreamPacket and AxiStreamBfm classes.
+// Description: Package for a bi-directional AXI Stream bus functional model
+// (BFM). This consists of the AxiStreamPacket and AxiStreamBfm classes.
+// It's based on the AxiStreamIf in lib/axi4s_svPkgAXI4S.sv
//
-
//-----------------------------------------------------------------------------
-// Unidirectional AXI4-Stream interface
+// AXI-Stream BFM Package
//-----------------------------------------------------------------------------
-interface AxiStreamIf #(
- parameter int DATA_WIDTH = 64,
- parameter int USER_WIDTH = 1
-) (
- input logic clk,
- input logic rst = 1'b0
-);
-
- // Signals that make up a unidirectional AXI-Stream interface
- logic tready;
- logic tvalid;
- logic [DATA_WIDTH-1:0] tdata;
- logic [USER_WIDTH-1:0] tuser;
- logic [DATA_WIDTH/8-1:0] tkeep;
- logic tlast;
-
- // View from the master side
- modport master (
- input clk, rst,
- output tvalid, tdata, tuser, tkeep, tlast,
- input tready
- );
-
- // View from the slave side
- modport slave (
- input clk, rst,
- input tvalid, tdata, tuser, tkeep, tlast,
- output tready
- );
-
-endinterface : AxiStreamIf
+package PkgAxiStreamBfm;
+ //---------------------------------------------------------------------------
+ // Raw packets - packet of just bytes
+ //---------------------------------------------------------------------------
+ // Ethernet in particular defies normal word boundaries, so underneath treating
+ // it as the most fundamental quantity - Bytes.
+ typedef byte raw_pkt_t[$]; // Byte Queue
+
+ // Push a packet with random data onto to the AXI Stream bus
+ // Args:
+ // - num_bytes: number of random bytes to add to the raw packet.
+ // - pkt: packet with rand data
+ task automatic get_rand_raw_pkt (
+ input int num_bytes,
+ output raw_pkt_t pkt);
+ begin
+ repeat(num_bytes) begin
+ pkt.push_back($urandom);
+ end
+ end
+ endtask
+
+ // Push a packet with a ramp on to the AXI Stream bus
+ // Args:
+ // - num_samps: Packet size in bytes *8
+ // - ramp_start: Start value for the ramp
+ // - ramp_inc: Increment per clock cycle
+ task automatic get_ramp_raw_pkt (
+ input int num_samps,
+ input logic [63:0] ramp_start,
+ input logic [63:0] ramp_inc,
+ input int SWIDTH=64,
+ output raw_pkt_t pkt);
+ begin
+ logic[63:0] word;
+ automatic integer counter = 0;
+ repeat(num_samps) begin
+ word = ramp_start+(counter*ramp_inc);
+ for (int i=0; i < SWIDTH ; i+=8) begin
+ pkt.push_back(word[i +: 8]);
+ end
+ counter = counter + 1;
+ end
+ end
+ endtask
-//-----------------------------------------------------------------------------
-// AXI-Stream BFM Package
-//-----------------------------------------------------------------------------
+ // Comparison Functions
+ function automatic bit raw_pkt_compare(input raw_pkt_t a, input raw_pkt_t b);
-package PkgAxiStreamBfm;
+ bit queue_match;
+ queue_match = 1;
+ // check each element of the queue and clear queue_match if they don't match.
+ // workaround for vivado bug - could be a==b
+ foreach(a[i]) queue_match = queue_match && a[i] == b[i];
+ return ((a.size() == b.size()) && queue_match);
+ endfunction
//---------------------------------------------------------------------------
// AXI Stream Packet Class
@@ -73,7 +91,7 @@ package PkgAxiStreamBfm;
typedef AxiStreamPacket #(DATA_WIDTH, USER_WIDTH) AxisPacket_t;
-
+ bit verbose=0;
//------------
// Properties
//------------
@@ -105,6 +123,12 @@ package PkgAxiStreamBfm;
keep = {};
endfunction;
+ // Delete a word from the current packet
+ function void delete(int i);
+ data.delete(i);
+ user.delete(i);
+ keep.delete(i);
+ endfunction;
// Return true if this packet equals that of the argument
virtual function bit equal(AxisPacket_t packet);
@@ -117,21 +141,30 @@ package PkgAxiStreamBfm;
foreach (data[i]) begin
data_a = data[i];
data_b = packet.data[i];
- if (data_a !== data_b) return 0;
+ if (data_a !== data_b) begin
+ if (verbose) $display("AxisPacket data mismatch a[%2d]=%X b[%2d]=%X",i,data_a,i,data_b);
+ return 0;
+ end
end
if (user.size() != packet.user.size()) return 0;
foreach (data[i]) begin
user_a = user[i];
user_b = packet.user[i];
- if (user_a !== user_b) return 0;
+ if (user_a !== user_b) begin
+ if (verbose) $display("AxisPacket user mismatch a[%2d]=%X b[%2d]=%X",i,user_a,i,user_b);
+ return 0;
+ end
end
if (keep.size() != packet.keep.size()) return 0;
foreach (keep[i]) begin
keep_a = keep[i];
keep_b = packet.keep[i];
- if (keep_a !== keep_b) return 0;
+ if (keep_a !== keep_b) begin
+ if (verbose) $display("AxisPacket keep mismatch a[%2d]=%X b[%2d]=%X",i,user_a,i,user_b);
+ return 0;
+ end
end
return 1;
@@ -141,10 +174,22 @@ package PkgAxiStreamBfm;
// Format the contents of the packet into a string
function string sprint();
string str = "";
+ string data_str = "";
if (data.size() == user.size() && data.size() == keep.size()) begin
str = { str, "data, user, keep:\n" };
foreach (data[i]) begin
- str = { str, $sformatf("%5d> %X %X %b\n", i, data[i], user[i], keep[i]) };
+ data_str = "";
+ if (DATA_WIDTH > 64) begin
+ for (int b=0; b < DATA_WIDTH; b +=64) begin
+ data_str = { data_str, $sformatf("%3d: %X",b,data[i][b+:64])};
+ if (b+64 < DATA_WIDTH) begin
+ data_str = { data_str, $sformatf("\n ")};
+ end
+ end
+ end else begin
+ data_str = { data_str, $sformatf("%X",data[i]) };
+ end
+ str = { str, $sformatf("%5d> %s %X %X \n", i, data_str, user[i], keep[i]) };
end
end else begin
str = { str, "data:\n" };
@@ -169,6 +214,45 @@ package PkgAxiStreamBfm;
$display(sprint());
endfunction : print
+ // Add an array of bytes (little endian)
+ function void push_bytes(raw_pkt_t raw, input user_t user = '0);
+ data_t word;
+ keep_t my_keep;
+ while (raw.size() > 0) begin
+ // fill tkeep
+ // SIZE = TKEEP / 0 = 0000, 1 = 0001, 2 = 0011, etc
+ my_keep = '1;
+ if (raw.size <= DATA_WIDTH/8) begin
+ foreach (my_keep[i]) my_keep[i] = i < (raw.size);
+ end
+ // fill the word with raw data from bottom up
+ word = '0;
+ for (int i = 0; i < DATA_WIDTH/8 ; i++) begin
+ if (my_keep[i]) word[i*8 +: 8] = raw.pop_front();
+ end
+ this.data.push_back(word);
+ this.keep.push_back(my_keep);
+ this.user.push_back(user);
+ end
+ endfunction
+
+ // Dump data contents as an array of bytes. (little endian)
+ function raw_pkt_t dump_bytes();
+ data_t word;
+ keep_t my_keep;
+ raw_pkt_t raw;
+ assert (data.size == keep.size) else
+ $fatal("data and keep have different sizes!");
+ foreach (data[i]) begin
+ my_keep = this.keep[i];
+ word = this.data[i];
+ for (int j = 0; j < DATA_WIDTH/8 ; j++) begin
+ if (my_keep[j]) raw.push_back(word[j*8 +: 8]);
+ end;
+ end
+ return raw;
+ endfunction
+
endclass : AxiStreamPacket;
@@ -178,8 +262,13 @@ package PkgAxiStreamBfm;
//---------------------------------------------------------------------------
class AxiStreamBfm #(
- parameter int DATA_WIDTH = 64,
- parameter int USER_WIDTH = 1
+ int DATA_WIDTH = 64,
+ int USER_WIDTH = 1,
+ int MAX_PACKET_BYTES = 0,
+ bit TDATA = 1,
+ bit TUSER = 1,
+ bit TKEEP = 1,
+ bit TLAST = 1
);
//------------------
@@ -205,13 +294,16 @@ package PkgAxiStreamBfm;
local const AxisPacket_t::keep_t IDLE_KEEP = {(DATA_WIDTH/8){1'bX}};
// Virtual interfaces for master and slave connections to DUT
- local virtual AxiStreamIf #(DATA_WIDTH, USER_WIDTH).master master;
- local virtual AxiStreamIf #(DATA_WIDTH, USER_WIDTH).slave slave;
+ local virtual AxiStreamIf #(DATA_WIDTH,USER_WIDTH,MAX_PACKET_BYTES,
+ TDATA,TUSER,TKEEP,TLAST).master master;
+ local virtual AxiStreamIf #(DATA_WIDTH,USER_WIDTH,MAX_PACKET_BYTES,
+ TDATA,TUSER,TKEEP,TLAST).slave slave;
// NOTE: We should not need these flags if Vivado would be OK with null check
// without throwing unnecessary null-ptr deref exceptions.
local bit master_en;
local bit slave_en;
+ bit slave_tready_init = 0;
// Queues to store the bus transactions
mailbox #(AxisPacket_t) tx_packets;
mailbox #(AxisPacket_t) rx_packets;
@@ -220,6 +312,8 @@ package PkgAxiStreamBfm;
protected int master_stall_prob = DEF_STALL_PROB;
protected int slave_stall_prob = DEF_STALL_PROB;
+ // Number of clocks betwen packets
+ int inter_packet_gap = 0;
//---------
// Methods
@@ -231,11 +325,13 @@ package PkgAxiStreamBfm;
endfunction : packets_equal
- // Class constructor. This must be given an interface for the master
+ // Class constructor. This must be given an interface for the master
// connection and an interface for the slave connection.
function new(
- virtual AxiStreamIf #(DATA_WIDTH, USER_WIDTH).master master,
- virtual AxiStreamIf #(DATA_WIDTH, USER_WIDTH).slave slave
+ virtual AxiStreamIf #(DATA_WIDTH,USER_WIDTH,MAX_PACKET_BYTES,
+ TDATA,TUSER,TKEEP,TLAST).master master,
+ virtual AxiStreamIf #(DATA_WIDTH,USER_WIDTH,MAX_PACKET_BYTES,
+ TDATA,TUSER,TKEEP,TLAST).slave slave
);
this.master_en = (master != null);
this.slave_en = (slave != null);
@@ -253,7 +349,7 @@ package PkgAxiStreamBfm;
endtask : put
- // Attempt to queue the provided packet for transmission. Return 1 if
+ // Attempt to queue the provided packet for transmission. Return 1 if
// successful, return 0 if the queue is full.
function bit try_put(AxisPacket_t packet);
assert (master_en) else $fatal(1, "Cannot use TX operations for a null master");
@@ -268,7 +364,7 @@ package PkgAxiStreamBfm;
endtask : get
- // Get the next packet if there's one available and return 1. Return 0 if
+ // Get the next packet if there's one available and return 1. Return 0 if
// there's no packet available.
function bit try_get(output AxisPacket_t packet);
assert (slave_en) else $fatal(1, "Cannot use RX operations for a null slave");
@@ -276,7 +372,7 @@ package PkgAxiStreamBfm;
endfunction : try_get
- // Get the next packet when it becomes available (wait if necessary), but
+ // Get the next packet when it becomes available (wait if necessary), but
// don't remove it from the receive queue.
task peek(output AxisPacket_t packet);
assert (slave_en) else $fatal(1, "Cannot use RX operations for a null slave");
@@ -284,8 +380,8 @@ package PkgAxiStreamBfm;
endtask : peek
- // Get the next packet if there's one available and return 1, but don't
- // remove it from the receive queue. Return 0 if there's no packet
+ // Get the next packet if there's one available and return 1, but don't
+ // remove it from the receive queue. Return 0 if there's no packet
// available.
function bit try_peek(output AxisPacket_t packet);
assert (slave_en) else $fatal(1, "Cannot use RX operations for a null slave");
@@ -300,8 +396,8 @@ package PkgAxiStreamBfm;
endfunction
- // Wait until num packets have started transmission (i.e., until num
- // packets have been dequeued). Set num = -1 to wait until all currently
+ // Wait until num packets have started transmission (i.e., until num
+ // packets have been dequeued). Set num = -1 to wait until all currently
// queued packets have started transmission.
task wait_send(int num = -1);
int end_num;
@@ -318,7 +414,7 @@ package PkgAxiStreamBfm;
endtask : wait_send
- // Wait until num packets have completed transmission. Set num = -1 to wait
+ // Wait until num packets have completed transmission. Set num = -1 to wait
// for all currently queued packets to complete transmission.
task wait_complete(int num = -1);
int end_num;
@@ -340,7 +436,7 @@ package PkgAxiStreamBfm;
endtask : wait_complete
- // Set the probability (as a percentage, 0 to 100) of the master interface
+ // Set the probability (as a percentage, 0 to 100) of the master interface
// stalling due to lack of data to send.
function void set_master_stall_prob(int stall_probability = DEF_STALL_PROB);
assert(stall_probability >= 0 && stall_probability <= 100) else begin
@@ -350,7 +446,7 @@ package PkgAxiStreamBfm;
endfunction
- // Set the probability (as a percentage, 0 to 100) of the slave interface
+ // Set the probability (as a percentage, 0 to 100) of the slave interface
// stalling due to lack of buffer space.
function void set_slave_stall_prob(int stall_probability = DEF_STALL_PROB);
assert(stall_probability >= 0 && stall_probability <= 100) else begin
@@ -360,14 +456,14 @@ package PkgAxiStreamBfm;
endfunction
- // Get the probability (as a percentage, 0 to 100) of the master interface
+ // Get the probability (as a percentage, 0 to 100) of the master interface
// stalling due to lack of data to send.
function int get_master_stall_prob(int stall_probability = DEF_STALL_PROB);
return master_stall_prob;
endfunction
- // Get the probability (as a percentage, 0 to 100) of the slave interface
+ // Get the probability (as a percentage, 0 to 100) of the slave interface
// stalling due to lack of buffer space.
function int get_slave_stall_prob(int stall_probability = DEF_STALL_PROB);
return slave_stall_prob;
@@ -397,8 +493,10 @@ package PkgAxiStreamBfm;
master.tlast <= 0;
forever begin
- @(posedge master.clk);
- if (master.rst) continue;
+ repeat(inter_packet_gap) begin
+ @(posedge master.clk);
+ if (master.rst) continue;
+ end
if (tx_packets.try_get(packet)) begin
foreach (packet.data[i]) begin
@@ -433,6 +531,9 @@ package PkgAxiStreamBfm;
master.tuser <= IDLE_USER;
master.tkeep <= IDLE_KEEP;
master.tlast <= 0;
+ end else begin
+ @(posedge master.clk);
+ if (master.rst) continue;
end
end
endtask : master_body
@@ -445,7 +546,7 @@ package PkgAxiStreamBfm;
local task slave_body();
AxisPacket_t packet = new();
- slave.tready <= 0;
+ slave.tready <= slave_tready_init;
forever begin
@(posedge slave.clk);