diff options
Diffstat (limited to 'fpga/usrp3/sim/rfnoc/PkgAxiStreamBfm.sv')
-rw-r--r-- | fpga/usrp3/sim/rfnoc/PkgAxiStreamBfm.sv | 239 |
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); |