aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/sim/rfnoc/PkgEthernet.sv
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/sim/rfnoc/PkgEthernet.sv')
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgEthernet.sv809
1 files changed, 809 insertions, 0 deletions
diff --git a/fpga/usrp3/sim/rfnoc/PkgEthernet.sv b/fpga/usrp3/sim/rfnoc/PkgEthernet.sv
new file mode 100644
index 000000000..a971b5c7e
--- /dev/null
+++ b/fpga/usrp3/sim/rfnoc/PkgEthernet.sv
@@ -0,0 +1,809 @@
+//
+// Copyright 2020 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: PkgEthernet
+//
+// Description: This package defines the data types used to represent ETHER,
+// IPV4, and UDP. It's based on a queue of bytes representation named
+// raw_pkt_t.
+//
+
+package PkgEthernet;
+
+ import PkgAxiStreamBfm::*;
+ export PkgAxiStreamBfm::*;
+
+ //************************************************************//
+ //////////////////// ETHER PACKETS /////////////////////////////
+ //************************************************************//
+
+ // Ether type - subset of possibilities. Add more as needed.
+ typedef enum logic [15:0] {
+ // Byte order 1 0
+ IPV4=16'h0800, IPV6=16'h86_DD, VLAN_TAGGED=16'h8100,
+ DOUBLE_VLAN_TAGGED=16'h9100, ROCE=16'h8915
+ } ether_type_t;
+
+ // Some MAC addresses
+ // Byte order 5 4 3 2 1 0
+ localparam logic [47:0] DEF_DEST_MAC_ADDR = 48'h5E_35_EB_71_46_F7;
+ localparam logic [47:0] DEF_SRC_MAC_ADDR = 48'h98_03_9B_8E_09_B9;
+ localparam logic [47:0] DEF_BRIDGE_MAC_ADDR = 48'hBB_BB_BB_BB_BB_BB;
+
+ // Ether Header
+ typedef struct {
+ logic [47:0] dest_mac = DEF_DEST_MAC_ADDR;
+ logic [47:0] src_mac = DEF_SRC_MAC_ADDR;
+ ether_type_t ether_type = IPV4;
+ } eth_hdr_t;
+
+ // Ethernet Packet, Header + Payload
+ typedef struct {
+ eth_hdr_t hdr;
+ raw_pkt_t payload;
+ logic [31:0] fcs;
+ int ipg = 12; // interpacket gap
+ } eth_pkt_t;
+
+ // Break an eth_pkt into a queue of bytes
+ function automatic raw_pkt_t flatten_eth_pkt(input eth_pkt_t pkt);
+ raw_pkt_t pay;
+
+ pay.push_back(pkt.hdr.dest_mac[47:40]);
+ pay.push_back(pkt.hdr.dest_mac[39:32]);
+ pay.push_back(pkt.hdr.dest_mac[31:24]);
+ pay.push_back(pkt.hdr.dest_mac[23:16]);
+ pay.push_back(pkt.hdr.dest_mac[15:8]);
+ pay.push_back(pkt.hdr.dest_mac[7:0]);
+ pay.push_back(pkt.hdr.src_mac[47:40]);
+ pay.push_back(pkt.hdr.src_mac[39:32]);
+ pay.push_back(pkt.hdr.src_mac[31:24]);
+ pay.push_back(pkt.hdr.src_mac[23:16]);
+ pay.push_back(pkt.hdr.src_mac[15:8]);
+ pay.push_back(pkt.hdr.src_mac[7:0]);
+ pay.push_back(pkt.hdr.ether_type[15:8]);
+ pay.push_back(pkt.hdr.ether_type[7:0]);
+ pay = {pay,pkt.payload};
+
+ return pay;
+
+ endfunction
+
+ // Break a queue of bytes into a eth_pkt
+ function automatic eth_pkt_t unflatten_eth_pkt(input raw_pkt_t pay);
+ eth_pkt_t pkt;
+
+ pkt.hdr.dest_mac[47:40] = pay.pop_front();
+ pkt.hdr.dest_mac[39:32] = pay.pop_front();
+ pkt.hdr.dest_mac[31:24] = pay.pop_front();
+ pkt.hdr.dest_mac[23:16] = pay.pop_front();
+ pkt.hdr.dest_mac[15:8] = pay.pop_front();
+ pkt.hdr.dest_mac[7:0] = pay.pop_front();
+ pkt.hdr.src_mac[47:40] = pay.pop_front();
+ pkt.hdr.src_mac[39:32] = pay.pop_front();
+ pkt.hdr.src_mac[31:24] = pay.pop_front();
+ pkt.hdr.src_mac[23:16] = pay.pop_front();
+ pkt.hdr.src_mac[15:8] = pay.pop_front();
+ pkt.hdr.src_mac[7:0] = pay.pop_front();
+ pkt.hdr.ether_type[15:8] = pay.pop_front();
+ pkt.hdr.ether_type[7:0] = pay.pop_front();
+ pkt.payload = pay;
+
+ return pkt;
+
+ endfunction
+
+ function automatic logic eth_pkt_compare(input eth_pkt_t a, input eth_pkt_t b);
+
+ return ((a.hdr.dest_mac == b.hdr.dest_mac) &&
+ (a.hdr.src_mac == b.hdr.src_mac) &&
+ (a.hdr.ether_type == b.hdr.ether_type) &&
+ raw_pkt_compare(a.payload,b.payload));
+
+ endfunction
+
+ //************************************************************//
+ //////////////////// IPV4 PACKETS //////////////////////////////
+ //************************************************************//
+
+ // IP Protocol - subset of possibilities. add more as needed
+ typedef enum logic [7:0] {
+ UDP=8'd17, TCP=8'd6, ICMP=8'd1, IGMP=8'd2, ENCAP=8'd41
+ } ip_protocol_t;
+
+ // follow normal convention of an IP address
+ function automatic logic [31:0] ip(logic [7:0] a,b,c,d);
+ return {a,b,c,d};
+ endfunction
+
+
+ localparam logic [31:0] DEF_DEST_IP_ADDR = ip(192,168,10,2);
+ localparam logic [31:0] DEF_SRC_IP_ADDR = ip(192,168,10,1);
+ localparam logic [31:0] DEF_BRIDGE_IP_ADDR = 32'h33_33_33_33;
+
+ // IPv4 Header
+ typedef struct {
+ logic [3:0] header_length = 4'd5;
+ logic [3:0] version = 4'd4;
+ logic [5:0] dscp = 6'b0000_00;
+ logic [1:0] ecn = 2'b00;
+ logic [15:0] length = 16'hXXXX; //flag for (fill it in please)
+ logic [15:0] identification = 16'h462E;
+ logic rsv_zero = 1'b0;
+ logic dont_frag = 1'b1;
+ logic more_frag = 1'b0;
+ logic [12:0] frag_offset = 16'd0;
+ logic [7:0] time_to_live = 16'd64;
+ ip_protocol_t protocol = UDP;
+ logic [15:0] checksum = 16'hXXXX; //flag for (fill it in please)
+ logic [31:0] src_ip = DEF_SRC_IP_ADDR;
+ logic [31:0] dest_ip = DEF_DEST_IP_ADDR;
+ } ipv4_hdr_t;
+
+ // IP Packet, Header + Payload
+ typedef struct {
+ ipv4_hdr_t hdr;
+ raw_pkt_t payload;
+ } ipv4_pkt_t;
+
+ // The checksum for an IP header is the sum of all the 16 bit words that
+ // make up the header with the checksum set to zero. Add back the carry over
+ // from bits [31:16] then invert.
+ // See https://en.wikipedia.org/wiki/IPv4_header_checksum
+ function automatic logic [15:0] calc_ipv4_checksum(input raw_pkt_t pkt);
+
+ // This is a bit oversized, but it's not costing anything.
+ // 10 max sized words can at most add logbase2 of 10 bits.
+ logic [31:0] checksum;
+
+ checksum = 0;
+ // Iterate over 16 bit chunks reading from a byte addressed memory.
+ // There are 20 bytes in an ipv4 header.
+ for (int i = 0 ; i < 20 ; i+=2 ) begin
+ // BIG endian network ordering... so weird
+ checksum += {pkt[i],pkt[i+1]};
+ end
+ checksum += checksum[31:16];
+ checksum = ~checksum;
+
+ return checksum[15:0];
+
+ endfunction
+
+ // Break an eth_pkt into a queue of bytes
+ function automatic raw_pkt_t flatten_ipv4_pkt(input ipv4_pkt_t pkt);
+ raw_pkt_t pay;
+
+ logic [15:0] length;
+ logic [15:0] checksum;
+ logic [2:0] flags;
+
+ // If header or length is not set to default value then use the value in
+ // the packet.
+ if ($isunknown(pkt.hdr.length))
+ length = pkt.payload.size()+20; // 20 because length includes IP header length.
+ else
+ length = pkt.hdr.length;
+
+ flags = {pkt.hdr.more_frag,pkt.hdr.dont_frag,pkt.hdr.rsv_zero};
+ // Start off with checksum as 0
+ checksum = 0;
+
+ // 20 byte IP header
+ pay.push_back({pkt.hdr.version,pkt.hdr.header_length}); // byte 0
+ pay.push_back({pkt.hdr.dscp,pkt.hdr.ecn}); // byte 1
+ pay.push_back(length[15:8]); // byte 2
+ pay.push_back(length[7:0]); // byte 3
+ pay.push_back(pkt.hdr.identification[15:8]); // byte 4
+ pay.push_back(pkt.hdr.identification[7:0]); // byte 5
+ pay.push_back({flags,pkt.hdr.frag_offset[12:8]}); // byte 6
+ pay.push_back(pkt.hdr.frag_offset[7:0]); // byte 7
+ pay.push_back(pkt.hdr.time_to_live); // byte 8
+ pay.push_back(pkt.hdr.protocol); // byte 9
+ pay.push_back(checksum[15:8]); // byte 10
+ pay.push_back(checksum[7:0]); // byte 11
+ pay.push_back(pkt.hdr.src_ip[31:24]); // byte 12
+ pay.push_back(pkt.hdr.src_ip[23:16]); // byte 13
+ pay.push_back(pkt.hdr.src_ip[15:8]); // byte 14
+ pay.push_back(pkt.hdr.src_ip[7:0]); // byte 15
+ pay.push_back(pkt.hdr.dest_ip[31:24]); // byte 16
+ pay.push_back(pkt.hdr.dest_ip[23:16]); // byte 17
+ pay.push_back(pkt.hdr.dest_ip[15:8]); // byte 18
+ pay.push_back(pkt.hdr.dest_ip[7:0]); // byte 19
+ pay = {pay,pkt.payload};
+
+ if ($isunknown(pkt.hdr.checksum))
+ checksum = calc_ipv4_checksum(pay);
+ else
+ checksum = pkt.hdr.checksum;
+ // replace the checksum (bytes 11:10
+ pay[10] = checksum[15:8];
+ pay[11] = checksum[7:0];
+
+ return pay;
+ endfunction
+
+ // Break a queue of bytes into a ip_pkt
+ function automatic ipv4_pkt_t unflatten_ipv4_pkt(input raw_pkt_t pay);
+ ipv4_pkt_t pkt;
+
+ // 20 byte IP header
+ {pkt.hdr.version,
+ pkt.hdr.header_length} = pay.pop_front(); // byte 0
+ {pkt.hdr.dscp,pkt.hdr.ecn} = pay.pop_front(); // byte 1
+ pkt.hdr.length[15:8] = pay.pop_front(); // byte 2
+ pkt.hdr.length[7:0] = pay.pop_front(); // byte 3
+ pkt.hdr.identification[15:8] = pay.pop_front(); // byte 4
+ pkt.hdr.identification[7:0] = pay.pop_front(); // byte 5
+ {pkt.hdr.more_frag,
+ pkt.hdr.dont_frag,
+ pkt.hdr.rsv_zero,
+ pkt.hdr.frag_offset[12:8]} = pay.pop_front(); // byte 6
+ pkt.hdr.frag_offset[7:0] = pay.pop_front(); // byte 7
+ pkt.hdr.time_to_live = pay.pop_front(); // byte 8
+ pkt.hdr.protocol = ip_protocol_t'(pay.pop_front()); // byte 9
+ pkt.hdr.checksum[15:8] = pay.pop_front(); // byte 10
+ pkt.hdr.checksum[7:0] = pay.pop_front(); // byte 11
+ pkt.hdr.src_ip[31:24] = pay.pop_front(); // byte 12
+ pkt.hdr.src_ip[23:16] = pay.pop_front(); // byte 13
+ pkt.hdr.src_ip[15:8] = pay.pop_front(); // byte 14
+ pkt.hdr.src_ip[7:0] = pay.pop_front(); // byte 15
+ pkt.hdr.dest_ip[31:24] = pay.pop_front(); // byte 16
+ pkt.hdr.dest_ip[23:16] = pay.pop_front(); // byte 17
+ pkt.hdr.dest_ip[15:8] = pay.pop_front(); // byte 18
+ pkt.hdr.dest_ip[7:0] = pay.pop_front(); // byte 19
+ pkt.payload = pay;
+
+ return pkt;
+
+ endfunction
+
+ function automatic logic ipv4_pkt_compare(input ipv4_pkt_t a, input ipv4_pkt_t b);
+
+ return ((a.hdr.header_length == b.hdr.header_length) &&
+ (a.hdr.version == b.hdr.version) &&
+ (a.hdr.dscp == b.hdr.dscp) &&
+ (a.hdr.ecn == b.hdr.ecn) &&
+ (a.hdr.length == b.hdr.length) &&
+ (a.hdr.identification == b.hdr.identification) &&
+ (a.hdr.rsv_zero == b.hdr.rsv_zero) &&
+ (a.hdr.dont_frag == b.hdr.dont_frag) &&
+ (a.hdr.more_frag == b.hdr.more_frag) &&
+ (a.hdr.frag_offset == b.hdr.frag_offset) &&
+ (a.hdr.time_to_live == b.hdr.time_to_live) &&
+ (a.hdr.protocol == b.hdr.protocol) &&
+ (a.hdr.checksum == b.hdr.checksum) &&
+ (a.hdr.src_ip == b.hdr.src_ip) &&
+ (a.hdr.dest_ip == b.hdr.dest_ip) &&
+ raw_pkt_compare(a.payload,b.payload));
+
+ endfunction
+
+ //************************************************************//
+ //////////////////// UDP PACKETS ///////////////////////////////
+ //************************************************************//
+
+ localparam logic [15:0] DEF_SRC_UDP_PORT = 16'd49748;
+ localparam logic [15:0] DEF_DEST_UDP_PORT = 16'd49153;
+ localparam logic [15:0] DEF_BRIDGE_UDP_PORT = 16'h66_55;
+
+ // UDP Header
+ typedef struct {
+ logic [15:0] src_port = DEF_SRC_UDP_PORT;
+ logic [15:0] dest_port = DEF_DEST_UDP_PORT;
+ logic [15:0] length = 16'hXXXX; //flag for (fill it in please)
+ logic [15:0] checksum = 16'hXXXX; //flag for (fill it in please)
+ } udp_hdr_t;
+
+ // UDP Packet, Header + Payload
+ typedef struct {
+ udp_hdr_t hdr;
+ raw_pkt_t payload;
+ } udp_pkt_t;
+
+ function automatic logic [15:0] calc_udp_checksum(
+ input logic [31:0] src_ip,
+ input logic [31:0] dest_ip,
+ input raw_pkt_t pkt);
+
+ logic [31:0] checksum;
+ raw_pkt_t virtual_header;
+
+ // UDP checksum is calculated over a virtual header that is added to
+ // the front of the packet.
+ virtual_header.push_back(src_ip[31:24]); // byte 0
+ virtual_header.push_back(src_ip[23:16]); // byte 1
+ virtual_header.push_back(src_ip[15:8]); // byte 2
+ virtual_header.push_back(src_ip[7:0]); // byte 3
+ virtual_header.push_back(dest_ip[31:24]); // byte 4
+ virtual_header.push_back(dest_ip[23:16]); // byte 5
+ virtual_header.push_back(dest_ip[15:8]); // byte 6
+ virtual_header.push_back(dest_ip[7:0]); // byte 7
+ virtual_header.push_back(0); // byte 8
+ virtual_header.push_back(UDP); // byte 9 UDP (Protocol enum) x11
+ virtual_header.push_back(0); // byte 10
+ virtual_header.push_back(pkt[6]); // byte 11 Length
+ virtual_header.push_back(pkt[7]); // byte 12 Length
+
+ pkt = {virtual_header,pkt}; // add virtual header in front
+
+ checksum = 0;
+ // Iterate over 16 bit chunks reading from an array of bytes
+ // need to traverse the virtual header / udp header / udp data
+ for (int i = 0 ; i < pkt.size ; i+=2 ) begin
+ // BIG endian network ordering... so weird
+ checksum += {pkt[i],pkt[i+1]};
+ end
+ checksum += checksum[31:16];
+ checksum = ~checksum;
+
+ return checksum[15:0];
+
+ endfunction
+
+ // Break a udp_pkt into a queue of bytes
+ function automatic raw_pkt_t flatten_udp_pkt(
+ input logic [31:0] src_ip,
+ input logic [31:0] dest_ip,
+ input udp_pkt_t pkt);
+ raw_pkt_t pay;
+
+ logic [15:0] length;
+ logic [15:0] checksum;
+
+ // If header or length is not set to default value then use the value in
+ // the packet.
+ if ($isunknown(pkt.hdr.length))
+ length = pkt.payload.size()+8; // 8 because length includes UDP header length.
+ else
+ length = pkt.hdr.length;
+
+ //temporary checksum
+ checksum = 0;
+
+ pay.push_back(pkt.hdr.src_port[15:8]); // byte 0
+ pay.push_back(pkt.hdr.src_port[7:0]); // byte 1
+ pay.push_back(pkt.hdr.dest_port[15:8]); // byte 2
+ pay.push_back(pkt.hdr.dest_port[7:0]); // byte 3
+ pay.push_back(length[15:8]); // byte 4
+ pay.push_back(length[7:0]); // byte 5
+ pay.push_back(checksum[15:8]); // byte 6
+ pay.push_back(checksum[7:0]); // byte 7
+ pay = {pay,pkt.payload};
+
+ if ($isunknown(pkt.hdr.checksum))
+ checksum = calc_udp_checksum(src_ip,dest_ip,pay);
+ else
+ checksum = pkt.hdr.checksum;
+
+ pay[6] = checksum[15:8];
+ pay[7] = checksum[7:0];
+
+ return pay;
+
+ endfunction
+
+ // Break a queue of bytes into a udp_pkt
+ function automatic udp_pkt_t unflatten_udp_pkt(input raw_pkt_t pay);
+ udp_pkt_t pkt;
+
+ pkt.hdr.src_port[15:8] = pay.pop_front();
+ pkt.hdr.src_port[7:0] = pay.pop_front();
+ pkt.hdr.dest_port[15:8] = pay.pop_front();
+ pkt.hdr.dest_port[7:0] = pay.pop_front();
+ pkt.hdr.length[15:8] = pay.pop_front();
+ pkt.hdr.length[7:0] = pay.pop_front();
+ pkt.hdr.checksum[15:8] = pay.pop_front();
+ pkt.hdr.checksum[7:0] = pay.pop_front();
+ pkt.payload = pay;
+
+ return pkt;
+
+ endfunction
+
+ function automatic logic udp_pkt_compare(input udp_pkt_t a, input udp_pkt_t b);
+
+ return ((a.hdr.src_port == b.hdr.src_port) &&
+ (a.hdr.dest_port == b.hdr.dest_port) &&
+ (a.hdr.length == b.hdr.length) &&
+ raw_pkt_compare(a.payload,b.payload));
+
+ endfunction
+
+ typedef enum int {
+ NO_PREAMBLE=0, NORMAL_PREAMBLE=1, ZERO_PREAMBLE=2
+ } preamble_t;
+
+ // Build up a raw UDP packet.
+ // Args:
+ // - pkt: Packet data (queue)
+ // - stream: Stream to use (Optional)
+ function automatic raw_pkt_t build_udp_pkt (
+ input eth_hdr_t eth_hdr,
+ input ipv4_hdr_t ipv4_hdr,
+ input udp_hdr_t udp_hdr,
+ input raw_pkt_t pay,
+ input int preamble = NO_PREAMBLE);
+
+ automatic udp_pkt_t udp_pkt;
+ automatic ipv4_pkt_t ipv4_pkt;
+ automatic eth_pkt_t eth_pkt;
+ automatic raw_pkt_t raw_pkt;
+
+ udp_pkt.hdr = udp_hdr;
+ udp_pkt.payload = pay;
+ ipv4_pkt.hdr = ipv4_hdr;
+ ipv4_pkt.payload = flatten_udp_pkt(ipv4_hdr.src_ip,ipv4_hdr.dest_ip,udp_pkt);
+ eth_pkt.hdr = eth_hdr;
+ eth_pkt.payload = flatten_ipv4_pkt(ipv4_pkt);
+ raw_pkt = flatten_eth_pkt(eth_pkt);
+ if (preamble==NORMAL_PREAMBLE) begin
+ raw_pkt.push_front(8'hAB);
+ raw_pkt.push_front(8'hAA);
+ raw_pkt.push_front(8'hAA);
+ raw_pkt.push_front(8'hAA);
+ raw_pkt.push_front(8'hAA);
+ raw_pkt.push_front(8'hAA);
+ end else if (preamble==ZERO_PREAMBLE) begin
+ raw_pkt.push_front(8'h00);
+ raw_pkt.push_front(8'h00);
+ raw_pkt.push_front(8'h00);
+ raw_pkt.push_front(8'h00);
+ raw_pkt.push_front(8'h00);
+ raw_pkt.push_front(8'h00);
+ end
+ return raw_pkt;
+
+ endfunction
+
+ // Wait for a packet to finish on the bus
+ // and decode it
+ task automatic decode_udp_pkt (
+ input raw_pkt_t raw_pkt,
+ output eth_hdr_t eth_hdr,
+ output ipv4_hdr_t ipv4_hdr,
+ output udp_hdr_t udp_hdr,
+ output raw_pkt_t payload);
+
+ eth_pkt_t eth_pkt;
+ ipv4_pkt_t ipv4_pkt;
+ udp_pkt_t udp_pkt;
+
+ eth_pkt = unflatten_eth_pkt(raw_pkt);
+ ipv4_pkt = unflatten_ipv4_pkt(eth_pkt.payload);
+ udp_pkt = unflatten_udp_pkt(ipv4_pkt.payload);
+
+ eth_hdr = eth_pkt.hdr;
+ ipv4_hdr = ipv4_pkt.hdr;
+ udp_hdr = udp_pkt.hdr;
+ payload = udp_pkt.payload;
+
+ endtask
+
+ //---------------------------------------------------------------------------
+ // XPORT Stream Packet Class
+ //---------------------------------------------------------------------------
+ // Extensions to the AxiStreamPacket used in the XPORT code
+ class XportStreamPacket #(
+ int DATA_WIDTH = 64
+ ) extends AxiStreamPacket #(DATA_WIDTH, $clog2((DATA_WIDTH/8)+1));
+
+ typedef XportStreamPacket #(DATA_WIDTH) XportPacket_t;
+ localparam UWIDTH = $clog2((DATA_WIDTH/8)+1);
+ // Class constructor.
+ function new ();
+ super.new();
+ endfunction : new
+
+ // Return a handle to a copy of this transaction
+ function XportPacket_t copy();
+ XportPacket_t temp;
+ temp = new();
+ temp.data = this.data;
+ temp.user = this.user;
+ temp.keep = this.keep;
+ return temp;
+ endfunction
+
+ // bring in data from an AxisPacket
+ function void import_axis(AxisPacket_t axi_pkt);
+ this.data = axi_pkt.data;
+ this.user = axi_pkt.user;
+ this.keep = axi_pkt.keep;
+ endfunction : import_axis
+
+ // take the tuser signal's and use them to set
+ // tkeep signals
+ task automatic tuser_to_tkeep(logic PRESERVE_TUSER=1);
+ keep_t last_tkeep;
+ user_t last_tuser;
+ logic [$clog2(DATA_WIDTH/8)-1:0] last_bytes;
+ last_tuser = this.user[$];
+ last_bytes = last_tuser[$clog2(DATA_WIDTH/8)-1:0];
+ // set all the tuser values to zero
+ // set all the tuser values to zero
+ foreach (this.user[i]) begin
+ this.keep[i] = '1;
+ if(!PRESERVE_TUSER)
+ this.user[i] = 0;
+ end
+ // figure out the value of tkeep for the last word
+ if (last_bytes == 0) last_tkeep = '1;
+ // check if there is an X
+ else if ($isunknown(last_tuser)) last_tkeep = '1;
+ else begin
+ last_tkeep = 0;
+ foreach (last_tkeep[i]) begin
+ last_tkeep[i] = i < last_bytes;
+ end
+ end
+ this.keep[$] = last_tkeep;
+ // set data bytes where the value isn't used to zero
+ foreach (last_tkeep[i]) begin
+ if (last_tkeep[i] == 0) this.data[$][i*8 +: 8] = 0;
+ end
+ endtask : tuser_to_tkeep
+
+ // take the tkeep signal's and use them to set
+ // width in the user signals
+ task automatic tkeep_to_tuser(int ERROR_PROB=0);
+ keep_t last_tkeep;
+ user_t last_tuser;
+
+ last_tkeep = this.keep[$];
+ // set all the tuser values to zero
+ foreach (this.user[i]) begin
+ this.user[i] = 0;
+ this.user[i][UWIDTH-1] = $urandom_range(99) < ERROR_PROB;
+ end
+ // check if there is an X
+ if ($isunknown(last_tkeep)) last_tuser = '0;
+ else begin
+ last_tuser = 0;
+ foreach (last_tkeep[i]) begin
+ if (last_tkeep[i]==1'b1) begin
+ last_tuser = last_tuser+1;
+ end
+ end
+ end
+ // full word is 0. MSB set is error
+ if (last_tuser == DATA_WIDTH/8)last_tuser = 0;
+ this.user[$] = last_tuser;
+ this.user[$][UWIDTH-1] = $urandom_range(99) < ERROR_PROB;
+
+ // set data bytes where the value isn't used to zero
+ foreach (last_tkeep[i]) begin
+ if (last_tkeep[i] == 0) this.data[$][i*8 +: 8] = 0;
+ end
+
+ endtask : tkeep_to_tuser
+
+ function automatic logic has_error();
+ logic error;
+
+ error = 0;
+ foreach (this.user[i]) begin
+ //catch if error was set
+ error = error || this.user[i][UWIDTH-1];
+ end
+ return error;
+ endfunction : has_error
+
+ function automatic int byte_length();
+ int bytes;
+ int last_bytes;
+ bytes = (this.data.size()-1)*DATA_WIDTH/8;
+ last_bytes = this.user[$][UWIDTH-2:0];
+ if (last_bytes == 0)
+ bytes+=DATA_WIDTH/8;
+ else
+ bytes+=last_bytes;
+
+ return bytes;
+
+ endfunction : byte_length
+
+ function automatic void clear_error();
+
+ foreach (this.user[i]) begin
+ this.user[i][UWIDTH-1] = 0;
+ end
+
+ endfunction : clear_error
+
+ function automatic void clear_keep();
+
+ foreach (this.keep[i]) begin
+ this.keep[i] = 0;
+ end
+
+ endfunction : clear_keep
+
+ function automatic void clear_user();
+
+ foreach (this.user[i]) begin
+ this.user[i] = 0;
+ end
+
+ endfunction : clear_user
+
+ task automatic set_error();
+ foreach (this.user[i]) begin
+ this.user[i][UWIDTH-1] = 1;
+ end
+ endtask : set_error
+
+ ///// compare_w_error
+ // Check that this packet has expected error bit in tuser
+ // Keep is not compared
+ // If COMPARE_ERROR_PACKETS is 0
+ // Don't check packet contents
+ // If COMPARE_ERROR_PACKETS is 1
+ // Check that this packet matches the expected packet
+ function automatic logic compare_w_error(
+ XportPacket_t expected,
+ int COMPARE_ERROR_PACKETS=1
+ );
+
+ automatic XportPacket_t actual_copy = this.copy();
+ automatic XportPacket_t expected_copy = expected.copy();
+
+ logic exp_error=0;
+ logic act_error=0;
+ logic error_condition;
+
+ exp_error = expected.has_error();
+ act_error = this.has_error();
+
+ actual_copy.clear_error();
+ expected_copy.clear_error();
+ actual_copy.clear_keep();
+ expected_copy.clear_keep();
+
+ error_condition = (!expected_copy.equal(actual_copy) &&
+ (!exp_error || COMPARE_ERROR_PACKETS)) ||
+ act_error != exp_error;
+ if (error_condition) begin
+ $display("Expected");
+ expected.print();
+ $display("Actual");
+ this.print();
+ if (!expected_copy.equal(actual_copy))
+ $display("ERROR :: packet mismatch");
+ if (act_error != exp_error)
+ $display("ERROR :: error mismatch");
+ end
+
+ return error_condition;
+
+ endfunction : compare_w_error
+
+ ///// compare_w_sof
+ // Check that this packet has expected sof bit in tuser
+ // Keep is not compared
+ // Check that this packet matches the expected packet
+ function automatic logic compare_w_sof(XportPacket_t expected);
+
+ automatic XportPacket_t actual_copy = this.copy();
+ automatic XportPacket_t expected_copy = expected.copy();
+
+ logic sof_error=0;
+ foreach (this.user[i]) begin
+ if (i==0) begin
+ // set if top bit of user isn't set on the first word.
+ sof_error = !this.user[i][UWIDTH-1];
+ end else begin
+ // set if top bit of user is set on any other word.
+ sof_error = this.user[i][UWIDTH-1] || sof_error;
+ end
+ end
+
+ // error bit doubles for SOF
+ actual_copy.clear_error();
+ expected_copy.clear_error();
+ actual_copy.clear_keep();
+ expected_copy.clear_keep();
+
+ // set SOF in expected
+ expected_copy.user[0][UWIDTH-1] = 0;
+
+ if (!expected_copy.equal(actual_copy) ||
+ sof_error) begin
+ $display("Expected");
+ expected_copy.print();
+ $display("Actual");
+ this.print();
+ if (!expected_copy.equal(actual_copy))
+ $display("ERROR :: packet mismatch");
+ if (sof_error)
+ $display("ERROR :: sof mismatch");
+ end
+
+ return !expected_copy.equal(actual_copy) ||
+ sof_error;
+
+ endfunction : compare_w_sof
+
+ ///// compare_w_pad
+ // Check that this packet has expected sof bit in tuser
+ // Keep is not compared
+ // Check that this packet matches the expected packet
+ // if DUMB_ORIGINAL_WAY
+ // User is not compared
+ // else
+ // Check that this packets tuser matches the expected packet
+ function automatic logic compare_w_pad(
+ XportPacket_t expected,
+ logic DUMB_ORIGINAL_WAY=0
+ );
+
+ automatic XportPacket_t actual_copy = this.copy();
+ automatic XportPacket_t expected_copy = expected.copy();
+
+ // not using MSB as error here.
+ actual_copy.clear_error();
+ expected_copy.clear_error();
+ actual_copy.clear_keep();
+ expected_copy.clear_keep();
+ // Add pad bytes to user
+ if (DUMB_ORIGINAL_WAY) begin
+ // I can't figure out how to calculate the expected on the
+ // original so I'm just copying the actual
+ foreach (expected_copy.user[i]) begin
+ expected_copy.user[i] = actual_copy.user[i];
+ end
+ end
+
+ if (!expected_copy.equal(actual_copy)) begin
+ $display("Expected");
+ expected_copy.print();
+ $display("Actual");
+ this.print();
+ if (!expected_copy.equal(actual_copy))
+ $display("ERROR :: packet mismatch");
+ end
+
+ return !expected_copy.equal(actual_copy);
+
+ endfunction : compare_w_pad
+
+ ///// compare_no_user
+ // Check that this packet has expected sof bit in tuser
+ // Keep is not compared
+ // Check that this packet matches the expected packet
+ // User is not compared
+ function automatic logic compare_no_user(XportPacket_t expected);
+
+ automatic XportPacket_t actual_copy = this.copy();
+ automatic XportPacket_t expected_copy = expected.copy();
+
+ // not using MSB as error here.
+ actual_copy.clear_error();
+ expected_copy.clear_error();
+ actual_copy.clear_keep();
+ expected_copy.clear_keep();
+
+ // Add pad bytes to user
+ foreach (expected_copy.user[i]) begin
+ expected_copy.user[i] = 0;
+ actual_copy.user[i] = 0;
+ end
+
+ if (!expected_copy.equal(actual_copy)) begin
+ $display("Expected");
+ expected.print();
+ $display("Actual");
+ this.print();
+ if (!expected_copy.equal(actual_copy))
+ $display("ERROR :: packet mismatch");
+ end
+
+ return !expected_copy.equal(actual_copy);
+
+ endfunction : compare_no_user
+
+ endclass : XportStreamPacket;
+
+endpackage : PkgEthernet