1// 2// Copyright 2020 Ettus Research, A National Instruments Brand 3// 4// SPDX-License-Identifier: LGPL-3.0-or-later 5// 6// Module: PkgEthernet 7// 8// Description: This package defines the data types used to represent ETHER, 9// IPV4, and UDP. It's based on a queue of bytes representation named 10// raw_pkt_t. 11// 12 13package PkgEthernet; 14 15 import PkgAxiStreamBfm::*; 16 export PkgAxiStreamBfm::*; 17 18 //************************************************************// 19 //////////////////// ETHER PACKETS ///////////////////////////// 20 //************************************************************// 21 22 // Ether type - subset of possibilities. Add more as needed. 23 typedef enum logic [15:0] { 24 // Byte order 1 0 25 IPV4=16'h0800, IPV6=16'h86_DD, VLAN_TAGGED=16'h8100, 26 DOUBLE_VLAN_TAGGED=16'h9100, ROCE=16'h8915 27 } ether_type_t; 28 29 // Some MAC addresses 30 // Byte order 5 4 3 2 1 0 31 localparam logic [47:0] DEF_DEST_MAC_ADDR = 48'h5E_35_EB_71_46_F7; 32 localparam logic [47:0] DEF_SRC_MAC_ADDR = 48'h98_03_9B_8E_09_B9; 33 localparam logic [47:0] DEF_BRIDGE_MAC_ADDR = 48'hBB_BB_BB_BB_BB_BB; 34 35 // Ether Header 36 typedef struct { 37 logic [47:0] dest_mac = DEF_DEST_MAC_ADDR; 38 logic [47:0] src_mac = DEF_SRC_MAC_ADDR; 39 ether_type_t ether_type = IPV4; 40 } eth_hdr_t; 41 42 // Ethernet Packet, Header + Payload 43 typedef struct { 44 eth_hdr_t hdr; 45 raw_pkt_t payload; 46 logic [31:0] fcs; 47 int ipg = 12; // interpacket gap 48 } eth_pkt_t; 49 50 // Break an eth_pkt into a queue of bytes 51 function automatic raw_pkt_t flatten_eth_pkt(input eth_pkt_t pkt); 52 raw_pkt_t pay; 53 54 pay.push_back(pkt.hdr.dest_mac[47:40]); 55 pay.push_back(pkt.hdr.dest_mac[39:32]); 56 pay.push_back(pkt.hdr.dest_mac[31:24]); 57 pay.push_back(pkt.hdr.dest_mac[23:16]); 58 pay.push_back(pkt.hdr.dest_mac[15:8]); 59 pay.push_back(pkt.hdr.dest_mac[7:0]); 60 pay.push_back(pkt.hdr.src_mac[47:40]); 61 pay.push_back(pkt.hdr.src_mac[39:32]); 62 pay.push_back(pkt.hdr.src_mac[31:24]); 63 pay.push_back(pkt.hdr.src_mac[23:16]); 64 pay.push_back(pkt.hdr.src_mac[15:8]); 65 pay.push_back(pkt.hdr.src_mac[7:0]); 66 pay.push_back(pkt.hdr.ether_type[15:8]); 67 pay.push_back(pkt.hdr.ether_type[7:0]); 68 pay = {pay,pkt.payload}; 69 70 return pay; 71 72 endfunction 73 74 // Break a queue of bytes into a eth_pkt 75 function automatic eth_pkt_t unflatten_eth_pkt(input raw_pkt_t pay); 76 eth_pkt_t pkt; 77 78 pkt.hdr.dest_mac[47:40] = pay.pop_front(); 79 pkt.hdr.dest_mac[39:32] = pay.pop_front(); 80 pkt.hdr.dest_mac[31:24] = pay.pop_front(); 81 pkt.hdr.dest_mac[23:16] = pay.pop_front(); 82 pkt.hdr.dest_mac[15:8] = pay.pop_front(); 83 pkt.hdr.dest_mac[7:0] = pay.pop_front(); 84 pkt.hdr.src_mac[47:40] = pay.pop_front(); 85 pkt.hdr.src_mac[39:32] = pay.pop_front(); 86 pkt.hdr.src_mac[31:24] = pay.pop_front(); 87 pkt.hdr.src_mac[23:16] = pay.pop_front(); 88 pkt.hdr.src_mac[15:8] = pay.pop_front(); 89 pkt.hdr.src_mac[7:0] = pay.pop_front(); 90 pkt.hdr.ether_type[15:8] = pay.pop_front(); 91 pkt.hdr.ether_type[7:0] = pay.pop_front(); 92 pkt.payload = pay; 93 94 return pkt; 95 96 endfunction 97 98 function automatic logic eth_pkt_compare(input eth_pkt_t a, input eth_pkt_t b); 99 100 return ((a.hdr.dest_mac == b.hdr.dest_mac) && 101 (a.hdr.src_mac == b.hdr.src_mac) && 102 (a.hdr.ether_type == b.hdr.ether_type) && 103 raw_pkt_compare(a.payload,b.payload)); 104 105 endfunction 106 107 //************************************************************// 108 //////////////////// IPV4 PACKETS ////////////////////////////// 109 //************************************************************// 110 111 // IP Protocol - subset of possibilities. add more as needed 112 typedef enum logic [7:0] { 113 UDP=8'd17, TCP=8'd6, ICMP=8'd1, IGMP=8'd2, ENCAP=8'd41 114 } ip_protocol_t; 115 116 // follow normal convention of an IP address 117 function automatic logic [31:0] ip(logic [7:0] a,b,c,d); 118 return {a,b,c,d}; 119 endfunction 120 121 122 localparam logic [31:0] DEF_DEST_IP_ADDR = ip(192,168,10,2); 123 localparam logic [31:0] DEF_SRC_IP_ADDR = ip(192,168,10,1); 124 localparam logic [31:0] DEF_BRIDGE_IP_ADDR = 32'h33_33_33_33; 125 126 // IPv4 Header 127 typedef struct { 128 logic [3:0] header_length = 4'd5; 129 logic [3:0] version = 4'd4; 130 logic [5:0] dscp = 6'b0000_00; 131 logic [1:0] ecn = 2'b00; 132 logic [15:0] length = 16'hXXXX; //flag for (fill it in please) 133 logic [15:0] identification = 16'h462E; 134 logic rsv_zero = 1'b0; 135 logic dont_frag = 1'b1; 136 logic more_frag = 1'b0; 137 logic [12:0] frag_offset = 16'd0; 138 logic [7:0] time_to_live = 16'd64; 139 ip_protocol_t protocol = UDP; 140 logic [15:0] checksum = 16'hXXXX; //flag for (fill it in please) 141 logic [31:0] src_ip = DEF_SRC_IP_ADDR; 142 logic [31:0] dest_ip = DEF_DEST_IP_ADDR; 143 } ipv4_hdr_t; 144 145 // IP Packet, Header + Payload 146 typedef struct { 147 ipv4_hdr_t hdr; 148 raw_pkt_t payload; 149 } ipv4_pkt_t; 150 151 // The checksum for an IP header is the sum of all the 16 bit words that 152 // make up the header with the checksum set to zero. Add back the carry over 153 // from bits [31:16] then invert. 154 // See https://en.wikipedia.org/wiki/IPv4_header_checksum 155 function automatic logic [15:0] calc_ipv4_checksum(input raw_pkt_t pkt); 156 157 // This is a bit oversized, but it's not costing anything. 158 // 10 max sized words can at most add logbase2 of 10 bits. 159 logic [31:0] checksum; 160 161 checksum = 0; 162 // Iterate over 16 bit chunks reading from a byte addressed memory. 163 // There are 20 bytes in an ipv4 header. 164 for (int i = 0 ; i < 20 ; i+=2 ) begin 165 // BIG endian network ordering... so weird 166 checksum += {pkt[i],pkt[i+1]}; 167 end 168 checksum += checksum[31:16]; 169 checksum = ~checksum; 170 171 return checksum[15:0]; 172 173 endfunction 174 175 // Break an eth_pkt into a queue of bytes 176 function automatic raw_pkt_t flatten_ipv4_pkt(input ipv4_pkt_t pkt); 177 raw_pkt_t pay; 178 179 logic [15:0] length; 180 logic [15:0] checksum; 181 logic [2:0] flags; 182 183 // If header or length is not set to default value then use the value in 184 // the packet. 185 if ($isunknown(pkt.hdr.length)) 186 length = pkt.payload.size()+20; // 20 because length includes IP header length. 187 else 188 length = pkt.hdr.length; 189 190 flags = {pkt.hdr.more_frag,pkt.hdr.dont_frag,pkt.hdr.rsv_zero}; 191 // Start off with checksum as 0 192 checksum = 0; 193 194 // 20 byte IP header 195 pay.push_back({pkt.hdr.version,pkt.hdr.header_length}); // byte 0 196 pay.push_back({pkt.hdr.dscp,pkt.hdr.ecn}); // byte 1 197 pay.push_back(length[15:8]); // byte 2 198 pay.push_back(length[7:0]); // byte 3 199 pay.push_back(pkt.hdr.identification[15:8]); // byte 4 200 pay.push_back(pkt.hdr.identification[7:0]); // byte 5 201 pay.push_back({flags,pkt.hdr.frag_offset[12:8]}); // byte 6 202 pay.push_back(pkt.hdr.frag_offset[7:0]); // byte 7 203 pay.push_back(pkt.hdr.time_to_live); // byte 8 204 pay.push_back(pkt.hdr.protocol); // byte 9 205 pay.push_back(checksum[15:8]); // byte 10 206 pay.push_back(checksum[7:0]); // byte 11 207 pay.push_back(pkt.hdr.src_ip[31:24]); // byte 12 208 pay.push_back(pkt.hdr.src_ip[23:16]); // byte 13 209 pay.push_back(pkt.hdr.src_ip[15:8]); // byte 14 210 pay.push_back(pkt.hdr.src_ip[7:0]); // byte 15 211 pay.push_back(pkt.hdr.dest_ip[31:24]); // byte 16 212 pay.push_back(pkt.hdr.dest_ip[23:16]); // byte 17 213 pay.push_back(pkt.hdr.dest_ip[15:8]); // byte 18 214 pay.push_back(pkt.hdr.dest_ip[7:0]); // byte 19 215 pay = {pay,pkt.payload}; 216 217 if ($isunknown(pkt.hdr.checksum)) 218 checksum = calc_ipv4_checksum(pay); 219 else 220 checksum = pkt.hdr.checksum; 221 // replace the checksum (bytes 11:10 222 pay[10] = checksum[15:8]; 223 pay[11] = checksum[7:0]; 224 225 return pay; 226 endfunction 227 228 // Break a queue of bytes into a ip_pkt 229 function automatic ipv4_pkt_t unflatten_ipv4_pkt(input raw_pkt_t pay); 230 ipv4_pkt_t pkt; 231 232 // 20 byte IP header 233 {pkt.hdr.version, 234 pkt.hdr.header_length} = pay.pop_front(); // byte 0 235 {pkt.hdr.dscp,pkt.hdr.ecn} = pay.pop_front(); // byte 1 236 pkt.hdr.length[15:8] = pay.pop_front(); // byte 2 237 pkt.hdr.length[7:0] = pay.pop_front(); // byte 3 238 pkt.hdr.identification[15:8] = pay.pop_front(); // byte 4 239 pkt.hdr.identification[7:0] = pay.pop_front(); // byte 5 240 {pkt.hdr.more_frag, 241 pkt.hdr.dont_frag, 242 pkt.hdr.rsv_zero, 243 pkt.hdr.frag_offset[12:8]} = pay.pop_front(); // byte 6 244 pkt.hdr.frag_offset[7:0] = pay.pop_front(); // byte 7 245 pkt.hdr.time_to_live = pay.pop_front(); // byte 8 246 pkt.hdr.protocol = ip_protocol_t'(pay.pop_front()); // byte 9 247 pkt.hdr.checksum[15:8] = pay.pop_front(); // byte 10 248 pkt.hdr.checksum[7:0] = pay.pop_front(); // byte 11 249 pkt.hdr.src_ip[31:24] = pay.pop_front(); // byte 12 250 pkt.hdr.src_ip[23:16] = pay.pop_front(); // byte 13 251 pkt.hdr.src_ip[15:8] = pay.pop_front(); // byte 14 252 pkt.hdr.src_ip[7:0] = pay.pop_front(); // byte 15 253 pkt.hdr.dest_ip[31:24] = pay.pop_front(); // byte 16 254 pkt.hdr.dest_ip[23:16] = pay.pop_front(); // byte 17 255 pkt.hdr.dest_ip[15:8] = pay.pop_front(); // byte 18 256 pkt.hdr.dest_ip[7:0] = pay.pop_front(); // byte 19 257 pkt.payload = pay; 258 259 return pkt; 260 261 endfunction 262 263 function automatic logic ipv4_pkt_compare(input ipv4_pkt_t a, input ipv4_pkt_t b); 264 265 return ((a.hdr.header_length == b.hdr.header_length) && 266 (a.hdr.version == b.hdr.version) && 267 (a.hdr.dscp == b.hdr.dscp) && 268 (a.hdr.ecn == b.hdr.ecn) && 269 (a.hdr.length == b.hdr.length) && 270 (a.hdr.identification == b.hdr.identification) && 271 (a.hdr.rsv_zero == b.hdr.rsv_zero) && 272 (a.hdr.dont_frag == b.hdr.dont_frag) && 273 (a.hdr.more_frag == b.hdr.more_frag) && 274 (a.hdr.frag_offset == b.hdr.frag_offset) && 275 (a.hdr.time_to_live == b.hdr.time_to_live) && 276 (a.hdr.protocol == b.hdr.protocol) && 277 (a.hdr.checksum == b.hdr.checksum) && 278 (a.hdr.src_ip == b.hdr.src_ip) && 279 (a.hdr.dest_ip == b.hdr.dest_ip) && 280 raw_pkt_compare(a.payload,b.payload)); 281 282 endfunction 283 284 //************************************************************// 285 //////////////////// UDP PACKETS /////////////////////////////// 286 //************************************************************// 287 288 localparam logic [15:0] DEF_SRC_UDP_PORT = 16'd49748; 289 localparam logic [15:0] DEF_DEST_UDP_PORT = 16'd49153; 290 localparam logic [15:0] DEF_BRIDGE_UDP_PORT = 16'h66_55; 291 292 // UDP Header 293 typedef struct { 294 logic [15:0] src_port = DEF_SRC_UDP_PORT; 295 logic [15:0] dest_port = DEF_DEST_UDP_PORT; 296 logic [15:0] length = 16'hXXXX; //flag for (fill it in please) 297 logic [15:0] checksum = 16'hXXXX; //flag for (fill it in please) 298 } udp_hdr_t; 299 300 // UDP Packet, Header + Payload 301 typedef struct { 302 udp_hdr_t hdr; 303 raw_pkt_t payload; 304 } udp_pkt_t; 305 306 function automatic logic [15:0] calc_udp_checksum( 307 input logic [31:0] src_ip, 308 input logic [31:0] dest_ip, 309 input raw_pkt_t pkt); 310 311 logic [31:0] checksum; 312 raw_pkt_t virtual_header; 313 314 // UDP checksum is calculated over a virtual header that is added to 315 // the front of the packet. 316 virtual_header.push_back(src_ip[31:24]); // byte 0 317 virtual_header.push_back(src_ip[23:16]); // byte 1 318 virtual_header.push_back(src_ip[15:8]); // byte 2 319 virtual_header.push_back(src_ip[7:0]); // byte 3 320 virtual_header.push_back(dest_ip[31:24]); // byte 4 321 virtual_header.push_back(dest_ip[23:16]); // byte 5 322 virtual_header.push_back(dest_ip[15:8]); // byte 6 323 virtual_header.push_back(dest_ip[7:0]); // byte 7 324 virtual_header.push_back(0); // byte 8 325 virtual_header.push_back(UDP); // byte 9 UDP (Protocol enum) x11 326 virtual_header.push_back(0); // byte 10 327 virtual_header.push_back(pkt[6]); // byte 11 Length 328 virtual_header.push_back(pkt[7]); // byte 12 Length 329 330 pkt = {virtual_header,pkt}; // add virtual header in front 331 332 checksum = 0; 333 // Iterate over 16 bit chunks reading from an array of bytes 334 // need to traverse the virtual header / udp header / udp data 335 for (int i = 0 ; i < pkt.size ; i+=2 ) begin 336 // BIG endian network ordering... so weird 337 checksum += {pkt[i],pkt[i+1]}; 338 end 339 checksum += checksum[31:16]; 340 checksum = ~checksum; 341 342 return checksum[15:0]; 343 344 endfunction 345 346 // Break a udp_pkt into a queue of bytes 347 function automatic raw_pkt_t flatten_udp_pkt( 348 input logic [31:0] src_ip, 349 input logic [31:0] dest_ip, 350 input udp_pkt_t pkt); 351 raw_pkt_t pay; 352 353 logic [15:0] length; 354 logic [15:0] checksum; 355 356 // If header or length is not set to default value then use the value in 357 // the packet. 358 if ($isunknown(pkt.hdr.length)) 359 length = pkt.payload.size()+8; // 8 because length includes UDP header length. 360 else 361 length = pkt.hdr.length; 362 363 //temporary checksum 364 checksum = 0; 365 366 pay.push_back(pkt.hdr.src_port[15:8]); // byte 0 367 pay.push_back(pkt.hdr.src_port[7:0]); // byte 1 368 pay.push_back(pkt.hdr.dest_port[15:8]); // byte 2 369 pay.push_back(pkt.hdr.dest_port[7:0]); // byte 3 370 pay.push_back(length[15:8]); // byte 4 371 pay.push_back(length[7:0]); // byte 5 372 pay.push_back(checksum[15:8]); // byte 6 373 pay.push_back(checksum[7:0]); // byte 7 374 pay = {pay,pkt.payload}; 375 376 if ($isunknown(pkt.hdr.checksum)) 377 checksum = calc_udp_checksum(src_ip,dest_ip,pay); 378 else 379 checksum = pkt.hdr.checksum; 380 381 pay[6] = checksum[15:8]; 382 pay[7] = checksum[7:0]; 383 384 return pay; 385 386 endfunction 387 388 // Break a queue of bytes into a udp_pkt 389 function automatic udp_pkt_t unflatten_udp_pkt(input raw_pkt_t pay); 390 udp_pkt_t pkt; 391 392 pkt.hdr.src_port[15:8] = pay.pop_front(); 393 pkt.hdr.src_port[7:0] = pay.pop_front(); 394 pkt.hdr.dest_port[15:8] = pay.pop_front(); 395 pkt.hdr.dest_port[7:0] = pay.pop_front(); 396 pkt.hdr.length[15:8] = pay.pop_front(); 397 pkt.hdr.length[7:0] = pay.pop_front(); 398 pkt.hdr.checksum[15:8] = pay.pop_front(); 399 pkt.hdr.checksum[7:0] = pay.pop_front(); 400 pkt.payload = pay; 401 402 return pkt; 403 404 endfunction 405 406 function automatic logic udp_pkt_compare(input udp_pkt_t a, input udp_pkt_t b); 407 408 return ((a.hdr.src_port == b.hdr.src_port) && 409 (a.hdr.dest_port == b.hdr.dest_port) && 410 (a.hdr.length == b.hdr.length) && 411 raw_pkt_compare(a.payload,b.payload)); 412 413 endfunction 414 415 typedef enum int { 416 NO_PREAMBLE=0, NORMAL_PREAMBLE=1, ZERO_PREAMBLE=2 417 } preamble_t; 418 419 // Build up a raw UDP packet. 420 // Args: 421 // - pkt: Packet data (queue) 422 // - stream: Stream to use (Optional) 423 function automatic raw_pkt_t build_udp_pkt ( 424 input eth_hdr_t eth_hdr, 425 input ipv4_hdr_t ipv4_hdr, 426 input udp_hdr_t udp_hdr, 427 input raw_pkt_t pay, 428 input int preamble = NO_PREAMBLE); 429 430 automatic udp_pkt_t udp_pkt; 431 automatic ipv4_pkt_t ipv4_pkt; 432 automatic eth_pkt_t eth_pkt; 433 automatic raw_pkt_t raw_pkt; 434 435 udp_pkt.hdr = udp_hdr; 436 udp_pkt.payload = pay; 437 ipv4_pkt.hdr = ipv4_hdr; 438 ipv4_pkt.payload = flatten_udp_pkt(ipv4_hdr.src_ip,ipv4_hdr.dest_ip,udp_pkt); 439 eth_pkt.hdr = eth_hdr; 440 eth_pkt.payload = flatten_ipv4_pkt(ipv4_pkt); 441 raw_pkt = flatten_eth_pkt(eth_pkt); 442 if (preamble==NORMAL_PREAMBLE) begin 443 raw_pkt.push_front(8'hAB); 444 raw_pkt.push_front(8'hAA); 445 raw_pkt.push_front(8'hAA); 446 raw_pkt.push_front(8'hAA); 447 raw_pkt.push_front(8'hAA); 448 raw_pkt.push_front(8'hAA); 449 end else if (preamble==ZERO_PREAMBLE) begin 450 raw_pkt.push_front(8'h00); 451 raw_pkt.push_front(8'h00); 452 raw_pkt.push_front(8'h00); 453 raw_pkt.push_front(8'h00); 454 raw_pkt.push_front(8'h00); 455 raw_pkt.push_front(8'h00); 456 end 457 return raw_pkt; 458 459 endfunction 460 461 // Wait for a packet to finish on the bus 462 // and decode it 463 task automatic decode_udp_pkt ( 464 input raw_pkt_t raw_pkt, 465 output eth_hdr_t eth_hdr, 466 output ipv4_hdr_t ipv4_hdr, 467 output udp_hdr_t udp_hdr, 468 output raw_pkt_t payload); 469 470 eth_pkt_t eth_pkt; 471 ipv4_pkt_t ipv4_pkt; 472 udp_pkt_t udp_pkt; 473 474 eth_pkt = unflatten_eth_pkt(raw_pkt); 475 ipv4_pkt = unflatten_ipv4_pkt(eth_pkt.payload); 476 udp_pkt = unflatten_udp_pkt(ipv4_pkt.payload); 477 478 eth_hdr = eth_pkt.hdr; 479 ipv4_hdr = ipv4_pkt.hdr; 480 udp_hdr = udp_pkt.hdr; 481 payload = udp_pkt.payload; 482 483 endtask 484 485 //--------------------------------------------------------------------------- 486 // XPORT Stream Packet Class 487 //--------------------------------------------------------------------------- 488 // Extensions to the AxiStreamPacket used in the XPORT code 489 class XportStreamPacket #( 490 int DATA_WIDTH = 64 491 ) extends AxiStreamPacket #(DATA_WIDTH, $clog2((DATA_WIDTH/8)+1)); 492 493 typedef XportStreamPacket #(DATA_WIDTH) XportPacket_t; 494 localparam UWIDTH = $clog2((DATA_WIDTH/8)+1); 495 // Class constructor. 496 function new (); 497 super.new(); 498 endfunction : new 499 500 // Return a handle to a copy of this transaction 501 function XportPacket_t copy(); 502 XportPacket_t temp; 503 temp = new(); 504 temp.data = this.data; 505 temp.user = this.user; 506 temp.keep = this.keep; 507 return temp; 508 endfunction 509 510 // bring in data from an AxisPacket 511 function void import_axis(AxisPacket_t axi_pkt); 512 this.data = axi_pkt.data; 513 this.user = axi_pkt.user; 514 this.keep = axi_pkt.keep; 515 endfunction : import_axis 516 517 518 // figure out the value of tkeep based on tuser(trailing words) 519 function keep_t calc_last_tkeep(user_t tuser); 520 keep_t last_tkeep; 521 // check if there is an X 522 if (tuser[$clog2(DATA_WIDTH/8)-1:0] === 0) begin 523 last_tkeep = '1; 524 end else if ($isunknown(tuser[$clog2(DATA_WIDTH/8)-1:0])) begin 525 last_tkeep = '1; 526 end else begin 527 last_tkeep = 0; 528 foreach (calc_last_tkeep[i]) begin 529 // set the bit if it's less than value of tuser 530 last_tkeep[i] = i < tuser[$clog2(DATA_WIDTH/8)-1:0]; 531 end 532 end 533 return last_tkeep; 534 endfunction : calc_last_tkeep; 535 536 // figure out the value of tuser(traling words) based on tkeep 537 function user_t calc_last_tuser(keep_t tkeep); 538 user_t last_tuser; 539 // check if there is an X 540 if ($isunknown(tkeep)) begin 541 last_tuser = '0; 542 end else begin 543 last_tuser = 0; 544 foreach (tkeep[i]) begin 545 if (tkeep[i]==1'b1) begin 546 last_tuser = last_tuser+1; 547 end 548 end 549 end 550 // full word is 0 551 if (last_tuser == DATA_WIDTH/8) begin 552 last_tuser = 0; 553 end 554 return last_tuser; 555 endfunction : calc_last_tuser; 556 557 // clear bytes that aren't marked as valid by keep 558 function void clear_unused_bytes(); 559 keep_t last_tkeep; 560 last_tkeep = this.keep[$]; 561 // check that the last user is the same as the last keep 562 assert (this.keep[$] == calc_last_tkeep(this.user[$])) else 563 $error("clear_unused_bytes: final tkeep and tuser don't match"); 564 565 // set data bytes where the value isn't used to zero 566 foreach (last_tkeep[i]) begin 567 if (last_tkeep[i] == 0) this.data[$][i*8 +: 8] = 0; 568 end 569 endfunction : clear_unused_bytes; 570 571 // take the tuser signal's and use them to set 572 // tkeep signals 573 task automatic tuser_to_tkeep(logic PRESERVE_TUSER=1); 574 575 // set all the tuser values to zero 576 // set all the tuser values to zero 577 foreach (this.user[i]) begin 578 this.keep[i] = '1; 579 if(!PRESERVE_TUSER) 580 this.user[i] = 0; 581 end 582 583 // figure out the value of tkeep for the last word 584 this.keep[$] = calc_last_tkeep(this.user[$]); 585 586 // set data bytes where the value isn't used to zero 587 clear_unused_bytes; 588 589 endtask : tuser_to_tkeep 590 591 // take the tkeep signal's and use them to set 592 // width in the user signals 593 task automatic tkeep_to_tuser(int ERROR_PROB=0); 594 595 // set all the tuser values to zero 596 foreach (this.user[i]) begin 597 this.user[i] = 0; 598 this.user[i][UWIDTH-1] = $urandom_range(99) < ERROR_PROB; 599 end 600 601 // figure out the value of user for the last word 602 this.user[$] = calc_last_tuser(this.keep[$]); 603 this.user[$][UWIDTH-1] = $urandom_range(99) < ERROR_PROB; 604 605 // set data bytes where the value isn't used to zero 606 clear_unused_bytes; 607 608 endtask : tkeep_to_tuser 609 610 function automatic logic has_error(); 611 logic error; 612 613 error = 0; 614 foreach (this.user[i]) begin 615 //catch if error was set 616 error = error || this.user[i][UWIDTH-1]; 617 end 618 return error; 619 endfunction : has_error 620 621 function automatic int byte_length(); 622 int bytes; 623 int last_bytes; 624 bytes = (this.data.size()-1)*DATA_WIDTH/8; 625 last_bytes = this.user[$][UWIDTH-2:0]; 626 if (last_bytes == 0) 627 bytes+=DATA_WIDTH/8; 628 else 629 bytes+=last_bytes; 630 631 return bytes; 632 633 endfunction : byte_length 634 635 function automatic void clear_error(); 636 637 foreach (this.user[i]) begin 638 this.user[i][UWIDTH-1] = 0; 639 end 640 641 endfunction : clear_error 642 643 function automatic void clear_keep(); 644 645 foreach (this.keep[i]) begin 646 this.keep[i] = 0; 647 end 648 649 endfunction : clear_keep 650 651 function automatic void clear_user(); 652 653 foreach (this.user[i]) begin 654 this.user[i] = 0; 655 end 656 657 endfunction : clear_user 658 659 task automatic set_error(); 660 foreach (this.user[i]) begin 661 this.user[i][UWIDTH-1] = 1; 662 end 663 endtask : set_error 664 665 ///// compare_w_error 666 // Check that this packet has expected error bit in tuser 667 // Keep is not compared 668 // If COMPARE_ERROR_PACKETS is 0 669 // Don't check packet contents 670 // If COMPARE_ERROR_PACKETS is 1 671 // Check that this packet matches the expected packet 672 function automatic logic compare_w_error( 673 XportPacket_t expected, 674 int COMPARE_ERROR_PACKETS=1 675 ); 676 677 automatic XportPacket_t actual_copy = this.copy(); 678 automatic XportPacket_t expected_copy = expected.copy(); 679 680 logic exp_error=0; 681 logic act_error=0; 682 logic error_condition; 683 684 exp_error = expected.has_error(); 685 act_error = this.has_error(); 686 687 actual_copy.clear_error(); 688 expected_copy.clear_error(); 689 actual_copy.clear_unused_bytes(); 690 expected_copy.clear_unused_bytes(); 691 692 error_condition = (!expected_copy.equal(actual_copy) && 693 (!exp_error || COMPARE_ERROR_PACKETS)) || 694 act_error != exp_error; 695 if (error_condition) begin 696 $display("Expected"); 697 expected.print(); 698 $display("Actual"); 699 this.print(); 700 if (!expected_copy.equal(actual_copy)) 701 $display("ERROR :: packet mismatch"); 702 if (act_error != exp_error) 703 $display("ERROR :: error mismatch"); 704 end 705 706 return error_condition; 707 708 endfunction : compare_w_error 709 710 ///// compare_w_sof 711 // Check that this packet has expected sof bit in tuser 712 // Keep is not compared 713 // Check that this packet matches the expected packet 714 function automatic logic compare_w_sof(XportPacket_t expected); 715 716 automatic XportPacket_t actual_copy = this.copy(); 717 automatic XportPacket_t expected_copy = expected.copy(); 718 719 logic sof_error=0; 720 foreach (this.user[i]) begin 721 if (i==0) begin 722 // set if top bit of user isn't set on the first word. 723 sof_error = !this.user[i][UWIDTH-1]; 724 end else begin 725 // set if top bit of user is set on any other word. 726 sof_error = this.user[i][UWIDTH-1] || sof_error; 727 end 728 end 729 730 // error bit doubles for SOF 731 actual_copy.clear_error(); 732 expected_copy.clear_error(); 733 actual_copy.clear_unused_bytes(); 734 expected_copy.clear_unused_bytes(); 735 736 // set SOF in expected 737 expected_copy.user[0][UWIDTH-1] = 0; 738 739 if (!expected_copy.equal(actual_copy) || 740 sof_error) begin 741 $display("Expected"); 742 expected_copy.print(); 743 $display("Actual"); 744 this.print(); 745 if (!expected_copy.equal(actual_copy)) 746 $display("ERROR :: packet mismatch"); 747 if (sof_error) 748 $display("ERROR :: sof mismatch"); 749 end 750 751 return !expected_copy.equal(actual_copy) || 752 sof_error; 753 754 endfunction : compare_w_sof 755 756 ///// compare_w_pad 757 // Check that this packet has expected sof bit in tuser 758 // Keep is not compared 759 // Check that this packet matches the expected packet 760 // if DUMB_ORIGINAL_WAY 761 // User is not compared 762 // else 763 // Check that this packets tuser matches the expected packet 764 function automatic logic compare_w_pad( 765 XportPacket_t expected, 766 logic DUMB_ORIGINAL_WAY=0 767 ); 768 769 automatic XportPacket_t actual_copy = this.copy(); 770 automatic XportPacket_t expected_copy = expected.copy(); 771 772 // not using MSB as error here. 773 actual_copy.clear_error(); 774 expected_copy.clear_error(); 775 actual_copy.clear_unused_bytes(); 776 expected_copy.clear_unused_bytes(); 777 778 // Add pad bytes to user 779 if (DUMB_ORIGINAL_WAY) begin 780 actual_copy.clear_keep(); 781 expected_copy.clear_keep(); 782 // I can't figure out a goodway to calculate the 783 // expected tuser for non last word values. 784 // So I'm just copying the actual 785 foreach (expected_copy.user[i]) begin 786 if (i != expected_copy.user.size()-1) begin 787 expected_copy.user[i] = actual_copy.user[i]; 788 end 789 end 790 end 791 792 if (!expected_copy.equal(actual_copy)) begin 793 $display("Expected"); 794 expected_copy.print(); 795 $display("Actual"); 796 this.print(); 797 if (!expected_copy.equal(actual_copy)) 798 $display("ERROR :: packet mismatch"); 799 end 800 801 return !expected_copy.equal(actual_copy); 802 803 endfunction : compare_w_pad 804 805 ///// compare_no_user 806 // Check that this packet has expected sof bit in tuser 807 // Keep is not compared 808 // Check that this packet matches the expected packet 809 // User is not compared 810 function automatic logic compare_no_user(XportPacket_t expected, int PRINT_LVL=1); 811 812 automatic XportPacket_t actual_copy = this.copy(); 813 automatic XportPacket_t expected_copy = expected.copy(); 814 815 // not using MSB as error here. 816 actual_copy.clear_error(); 817 expected_copy.clear_error(); 818 actual_copy.clear_unused_bytes(); 819 expected_copy.clear_unused_bytes(); 820 821 // Add pad bytes to user 822 foreach (expected_copy.user[i]) begin 823 expected_copy.user[i] = 0; 824 actual_copy.user[i] = 0; 825 end 826 827 if (PRINT_LVL==1) begin 828 if (!expected_copy.equal(actual_copy)) begin 829 $display("Expected"); 830 expected.print(); 831 $display("Actual"); 832 this.print(); 833 if (!expected_copy.equal(actual_copy)) 834 $display("ERROR :: packet mismatch"); 835 end 836 end 837 return !expected_copy.equal(actual_copy); 838 839 endfunction : compare_no_user 840 841 endclass : XportStreamPacket; 842 843endpackage : PkgEthernet 844