OpenCores
URL https://opencores.org/ocsvn/1000base-x/1000base-x/trunk

Subversion Repositories 1000base-x

[/] [1000base-x/] [trunk/] [testbench/] [rtl/] [verilog/] [ethernet_frame.v] - Rev 6

Go to most recent revision | Compare with Previous | Blame | View Log

//////////////////////////////////////////////////////////////////////
////                                                              ////
////  File name "ethernet_frame.v"                                ////
////                                                              ////
////  This file is part of the :                                  ////
////                                                              ////
//// "1000BASE-X IEEE 802.3-2008 Clause 36 - PCS project"         ////
////                                                              ////
////  http://opencores.org/project,1000base-x                     ////
////                                                              ////
////  Author(s):                                                  ////
////      - D.W.Pegler Cambridge Broadband Networks Ltd           ////
////                                                              ////
////      { peglerd@gmail.com, dwp@cambridgebroadand.com }        ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2009 AUTHORS. All rights reserved.             ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source is distributed in the hope that it will be       ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
//// PURPOSE.  See the GNU Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
 
package ethernet_frame;
 
   import tb_utils::hexpretty;
   import tb_utils::hexformat;
 
   typedef int crc_t[4];
   typedef int proto_t[2];
   typedef int payload_t[];
   typedef int ethernet_address_t[6];
 
   localparam ethernet_address_t ETH_A_TB        = '{'haa, 'hbb, 'hcc, 'hdd, 'hee, 'hff};
   localparam ethernet_address_t ETH_A_BCAST     = '{'hff, 'hff, 'hff, 'hff, 'hff, 'hff};
   localparam ethernet_address_t ETH_A_NULL      = '{'h00, 'h00, 'h00, 'h00, 'h00, 'h00};
 
   localparam ethernet_address_t ether_broadcast = ETH_A_BCAST;
   localparam ethernet_address_t ether_null      = ETH_A_NULL;
   localparam ethernet_address_t def_dst_addr    = ETH_A_TB;
   localparam ethernet_address_t def_src_addr    = ETH_A_TB;
 
   localparam proto_t ETH_P_IP                   = '{'h08, 'h00};
 
   localparam proto_t def_proto                  = ETH_P_IP;
 
   localparam int ethernet_preamble      = 'h5;
   localparam int ethernet_preamble_len  = 15;
   localparam int ethernet_sfd           = 'hd;
   localparam int ethernet_min_payload   = 46;
   localparam int ethernet_max_payload   = 2100;
   localparam int ethernet_crc_poly      = 32'h04c11db7;
   localparam int ethernet_overhead      = (6+6+2+4); // Excludes preamble, SFD
 
   // Parameters for 100BaseTx Ethernet:
   localparam int ethernet_slot_time        = 512;  // bit times
   localparam int ethernet_inter_frame_gap  = 96;   // bits
   localparam int ethernet_attempt_limit    = 16;
   localparam int ethernet_back_off_limit   = 10;
   localparam int ethernet_jam_size         = 32;   // bits
   localparam int ethernet_min_frame_size   = ethernet_min_payload + ethernet_overhead; // = 64;
   localparam int ethernet_clk_rate         = 25e6;
 
   typedef enum   { ETH10, ETH100, ETH1000 } EthernetSpeed;
 
   int 		  nothing[] = new[0];
 
   //////////////////////////////////////////////////////////////////////////////
   //
   //////////////////////////////////////////////////////////////////////////////
 
class CRC32;
 
   static function reg [7:0] byte_swap(reg [7:0] x);
      return {x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]};
   endfunction
 
   static function reg [31:0] word_swap(reg [31:0] x);
      return {byte_swap(x[7:0]), byte_swap(x[15:8]), byte_swap(x[23:16]), byte_swap(x[31:24])};
   endfunction
 
   static function reg[31:0] pack_swap(reg [31:0] x);
      return  { x[7:0], x[15:8], x[23:16], x[31:24]};
   endfunction // pack_swap
 
   static int 	  crc32_table[256];
   static int 	  crc32_table_ready = 0;
   int 		  accum = 32'hffffffff;
 
   static function automatic void populate_crc_table();
      $display("Populating crc32 table...");
      for(int i=0; i<256; i++)
        begin
           int c = i<<24;
           for(int j=0; j<8; j++)
             begin
		if(c & 32'h80000000)
                  c = (c << 1) ^ ethernet_crc_poly;
		else
                  c = (c << 1);
             end
           crc32_table[byte_swap(i)] = word_swap(c);
        end
      crc32_table_ready = 1;
   endfunction
 
   function void reset();
      accum = 32'hffffffff;
      if(!crc32_table_ready) populate_crc_table();
   endfunction
 
   function new();
      reset();
   endfunction
 
   function void push(int x);
      accum = (accum[31:8] ^ crc32_table[accum[7:0] ^ x[7:0]]) & 32'hffffffff; 
   endfunction
 
   function int eval();
      return ~accum;
   endfunction
 
   static function int block(int buffer[], int start, int finish);
      CRC32 x = new();
      x.reset();
      for(int i=start; i<finish; i++) x.push(buffer[i]);
      return x.eval();
   endfunction
 
endclass // CRC32
 
   //////////////////////////////////////////////////////////////////////////////
   //
   //////////////////////////////////////////////////////////////////////////////
 
   function automatic string fmt_addr(ethernet_address_t addr);
 
      $sformat(fmt_addr, "%02X.%02X.%02X.%02X.%02X.%02X",
	       addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
 
   endfunction 
 
   function void random_payload(int size, output int rv[], input int randomize, int seed=-1);
 
      int tmp;
 
      if (seed >= 0) tmp = $urandom(seed);
 
      rv = new[size];
 
      for(int i=0; i<size; i++)
	rv[i] = (randomize) ? ($urandom() & 'hff) : ((1+i) & 'hff);
 
   endfunction
 
   //----------------------------------------------------------------------------
 
  class EthernetFrame extends packet::Packet;
    int raw[];
    int badcrc;
    time delay = 0;  
    int epd_sequence = 0;
 
    function new(
      int da[]      = def_dst_addr,
      int sa[]      = def_src_addr,
      int proto[]   = def_proto,
      int payload[] = nothing,
      int seed      = -1,
      int randomize = 1,
      int length    = 100,
      int badcrc    = 0,
      int initraw[] = nothing
    );
       set_badcrc(badcrc, 0);
 
      if(initraw.size()!=0)
        raw = new[initraw.size()](initraw);
      else
        begin
          if(payload.size()==0) random_payload(length, payload, randomize, seed);
          set_payload(payload);
          set_da(da, 0);
          set_sa(sa, 0);
          set_proto(proto, 1);  
        end
    endfunction
 
    function int len();
      return raw.size();
    endfunction
 
    function int payload_len();
      return raw.size() - ethernet_overhead;
    endfunction
 
    function string repr_verbose(int n_start=4, int n_end=4);
      string s;
      $sformat(s, "<Frame,da=%s,sa=%s,len=%s,pay=%s,crc=%s>",
        fmt_addr(get_da()),
        fmt_addr(get_sa()),
        hexpretty(get_proto()),
        hexpretty(get_payload(), n_start, n_end),
        hexpretty(get_crc())
      );
      return s;
   endfunction // repr
 
 
   function string dump();
      string s;
      $sformat(s, "<len=%0d,da=%s,sa=%s,type=%s,pay=%s,crc=%s>",
        len(),
        fmt_addr(get_da()),
        fmt_addr(get_sa()),
        hexpretty(get_proto()),
        hexformat(get_payload(), "0x%02x", ","),
        hexpretty(get_crc())
      );
      return s;
    endfunction
 
 
    function void resize(int n);
      raw = new[n](raw);
    endfunction
 
 
     function void cut(int pos, int n);
	for(int i=pos; i<(raw.size-n); i++)
	  raw[i] = raw[i+n];
 
	resize(raw.size - n);	
     endfunction; // extract  
 
    function void set_da(ethernet_address_t da, int update=1);
      raw[0:5] = da;
      if(update)
        update_crc();
    endfunction
 
    function ethernet_address_t get_da();
      return raw[0:5];
    endfunction
 
    function void set_sa(ethernet_address_t sa, int update=1);
      raw[6:11] = sa;
      if(update)
        update_crc();
    endfunction
 
    function ethernet_address_t get_sa();
      return raw[6:11];
    endfunction
 
    function void set_proto(proto_t x, int update=1);
      raw[12:13] = x;
      if(update)
        update_crc();
    endfunction
 
    function proto_t get_proto();
      return raw[12:13];
    endfunction
 
    function void set_badcrc(int b, int update=1);
      badcrc = b;
      if(update)
        update_crc();
    endfunction
 
     function void set_payload(int p[]);
       int   n = p.size();
       resize(n+ethernet_overhead);
       for(int i=0; i<n; i++)
         raw[14+i] = p[i];
    endfunction
 
    function void pad_up();
      int n = raw.size();
      if(n < ethernet_min_frame_size)
        begin
           $display("Inserting %0d bytes of padding.", ethernet_min_frame_size-n);
           resize(ethernet_min_frame_size);
           for(int i=n-4; i<ethernet_min_frame_size-4; i++)
             raw[i] = 0;
           update_crc();
        end
    endfunction
 
     function void align();
	int n = raw.size();
	if(n[0])
          begin
             $display("Increasing size of frame from %0d bytes to %0d bytes.", n, n+1);
             resize(n+1);
             raw[n-4] = 0;
             update_crc();
          end
     endfunction
 
    // Seems we can't avoid the copy in here...
    function payload_t get_payload();
      int n = raw.size()-ethernet_overhead;
      get_payload = new[n];
      for(int i=0; i<n; i++)
        get_payload[i] = raw[14+i];
    endfunction
 
    function crc_t calc_crc();
      int crc = CRC32::block(raw, 0, raw.size()-4);
      calc_crc[0] = crc[7:0];
      calc_crc[1] = crc[15:8];
      calc_crc[2] = crc[23:16];
      calc_crc[3] = crc[31:24];
    endfunction
 
    function crc_t get_crc();
      return raw[raw.size()-4+:4];
    endfunction
 
    function int check_crc();
      int expected_crc[4] = calc_crc();
      int extracted_crc[4] = get_crc();
      return expected_crc==extracted_crc;
    endfunction
 
    // Update length and CRC fields.
    function void update_crc();
      if(raw.size()>=4)
        begin
          int fcs[4];
          int n;
          fcs = calc_crc();
	   n = raw.size();
          for(int i=0; i<4; i++)
            raw[n-4+i] = fcs[i] ^ (badcrc ? 'ha5 : 0);
        end
    endfunction
 
  endclass
 
  // Specialize a mailbox for passing Ethernet frames.
  typedef mailbox #(EthernetFrame) FrameMailBox;
 
endpackage
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.